1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.profiles;
18 
19 import android.car.drivingstate.CarUxRestrictions;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.UserInfo;
25 
26 import androidx.annotation.CallSuper;
27 import androidx.annotation.VisibleForTesting;
28 import androidx.preference.Preference;
29 import androidx.preference.PreferenceGroup;
30 
31 import com.android.car.settings.common.FragmentController;
32 import com.android.car.settings.common.PreferenceController;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Objects;
37 
38 /** Shared business logic between {@link ProfilesListFragment} and
39  * {@link ChooseNewAdminFragment}.
40  */
41 public abstract class ProfilesBasePreferenceController extends
42         PreferenceController<PreferenceGroup> {
43 
44     private ProfilesPreferenceProvider mPreferenceProvider;
45     private List<Preference> mProfilesToDisplay = new ArrayList<>();
46 
47     @VisibleForTesting
48     final BroadcastReceiver mProfileUpdateReceiver = new BroadcastReceiver() {
49         @Override
50         public void onReceive(Context context, Intent intent) {
51             /** Update screen when profiles list is updated. */
52             refreshUi();
53         }
54     };
55 
ProfilesBasePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)56     public ProfilesBasePreferenceController(Context context, String preferenceKey,
57             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
58         super(context, preferenceKey, fragmentController, uxRestrictions);
59         ProfilesPreferenceProvider.ProfileClickListener profileClickListener = this::profileClicked;
60         mPreferenceProvider = new ProfilesPreferenceProvider(context, profileClickListener);
61     }
62 
63     @Override
getPreferenceType()64     protected Class<PreferenceGroup> getPreferenceType() {
65         return PreferenceGroup.class;
66     }
67 
68     /**
69      * Ensure that helper is set by the time onCreate is called. Register a listener to refresh
70      * screen on updates.
71      */
72     @Override
73     @CallSuper
onCreateInternal()74     protected void onCreateInternal() {
75         registerForProfileEvents();
76     }
77 
78     /** Unregister listener to refresh screen on updates. */
79     @Override
80     @CallSuper
onDestroyInternal()81     protected void onDestroyInternal() {
82         unregisterForProfileEvents();
83     }
84 
85     @Override
updateState(PreferenceGroup preferenceGroup)86     protected void updateState(PreferenceGroup preferenceGroup) {
87         List<Preference> newProfiles = mPreferenceProvider.createProfileList();
88         if (profileListsAreDifferent(mProfilesToDisplay, newProfiles)) {
89             mProfilesToDisplay = newProfiles;
90             preferenceGroup.removeAll();
91 
92             for (Preference preference : mProfilesToDisplay) {
93                 preferenceGroup.addPreference(preference);
94             }
95         }
96     }
97 
98     /** Handles the profile click on a preference for a certain profile. */
profileClicked(UserInfo userInfo)99     protected abstract void profileClicked(UserInfo userInfo);
100 
101 
102     /** Gets the preference provider to set additional arguments if necessary. */
getPreferenceProvider()103     protected ProfilesPreferenceProvider getPreferenceProvider() {
104         return mPreferenceProvider;
105     }
106 
getProfilesToDisplay()107     protected List<Preference> getProfilesToDisplay() {
108         return mProfilesToDisplay;
109     }
110 
profileListsAreDifferent(List<Preference> currentList, List<Preference> newList)111     private boolean profileListsAreDifferent(List<Preference> currentList,
112             List<Preference> newList) {
113         if (currentList.size() != newList.size()) {
114             return true;
115         }
116 
117         for (int i = 0; i < currentList.size(); i++) {
118             // Cannot use "compareTo" on preference, since it uses the order attribute to compare.
119             if (preferencesAreDifferent(currentList.get(i), newList.get(i))) {
120                 return true;
121             }
122         }
123 
124         return false;
125     }
126 
preferencesAreDifferent(Preference lhs, Preference rhs)127     private boolean preferencesAreDifferent(Preference lhs, Preference rhs) {
128         return !Objects.equals(lhs.getTitle(), rhs.getTitle())
129                 || !Objects.equals(lhs.getSummary(), rhs.getSummary());
130     }
131 
registerForProfileEvents()132     private void registerForProfileEvents() {
133         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED);
134         getContext().registerReceiver(mProfileUpdateReceiver, filter);
135     }
136 
unregisterForProfileEvents()137     private void unregisterForProfileEvents() {
138         getContext().unregisterReceiver(mProfileUpdateReceiver);
139     }
140 }
141