1 /* 2 * Copyright 2019 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.system; 18 19 import android.accounts.Account; 20 import android.accounts.AccountManager; 21 import android.accounts.AuthenticatorDescription; 22 import android.car.drivingstate.CarUxRestrictions; 23 import android.content.Context; 24 import android.content.pm.PackageManager; 25 import android.content.pm.UserInfo; 26 import android.content.res.Resources; 27 import android.graphics.drawable.Drawable; 28 import android.os.UserHandle; 29 import android.os.UserManager; 30 import android.util.ArrayMap; 31 32 import androidx.annotation.Nullable; 33 import androidx.preference.Preference; 34 import androidx.preference.PreferenceGroup; 35 36 import com.android.car.settings.R; 37 import com.android.car.settings.common.FragmentController; 38 import com.android.car.settings.common.Logger; 39 import com.android.car.settings.common.PreferenceController; 40 import com.android.car.ui.preference.CarUiPreference; 41 42 import java.util.HashSet; 43 import java.util.List; 44 import java.util.Map; 45 import java.util.Set; 46 47 /** 48 * Displays the currently signed in accounts on the vehicle to inform the user that they will be 49 * removed during a factory reset. 50 */ 51 public class MasterClearAccountsPreferenceController extends PreferenceController<PreferenceGroup> { 52 53 private static final Logger LOG = new Logger(MasterClearAccountsPreferenceController.class); 54 55 private final Map<Account, Preference> mAccountPreferenceMap = new ArrayMap<>(); 56 MasterClearAccountsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)57 public MasterClearAccountsPreferenceController(Context context, String preferenceKey, 58 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 59 super(context, preferenceKey, fragmentController, uxRestrictions); 60 } 61 62 @Override getPreferenceType()63 protected Class<PreferenceGroup> getPreferenceType() { 64 return PreferenceGroup.class; 65 } 66 67 @Override onCreateInternal()68 protected void onCreateInternal() { 69 getPreference().addPreference( 70 createPreference(getContext().getString(R.string.master_clear_accounts), /* icon= */ 71 null)); 72 } 73 74 @Override updateState(PreferenceGroup preferenceGroup)75 protected void updateState(PreferenceGroup preferenceGroup) { 76 // Refresh the accounts in the off chance an account was added or removed while stopped. 77 Set<Account> accountsToRemove = new HashSet<>(mAccountPreferenceMap.keySet()); 78 List<UserInfo> profiles = UserManager.get(getContext()).getProfiles(UserHandle.myUserId()); 79 for (UserInfo profile : profiles) { 80 UserHandle userHandle = new UserHandle(profile.id); 81 AuthenticatorDescription[] descriptions = AccountManager.get( 82 getContext()).getAuthenticatorTypesAsUser(profile.id); 83 Account[] accounts = AccountManager.get(getContext()).getAccountsAsUser(profile.id); 84 for (Account account : accounts) { 85 AuthenticatorDescription description = null; 86 for (AuthenticatorDescription desc : descriptions) { 87 if (account.type.equals(desc.type)) { 88 description = desc; 89 break; 90 } 91 } 92 if (description == null) { 93 LOG.w("No descriptor for account name=" + account.name + " type=" 94 + account.type); 95 continue; 96 } 97 98 accountsToRemove.remove(account); 99 if (!mAccountPreferenceMap.containsKey(account)) { 100 Preference accountPref = createPreference(account.name, 101 getAccountIcon(description, userHandle)); 102 mAccountPreferenceMap.put(account, accountPref); 103 preferenceGroup.addPreference(accountPref); 104 } 105 } 106 } 107 108 for (Account accountToRemove : accountsToRemove) { 109 preferenceGroup.removePreference(mAccountPreferenceMap.get(accountToRemove)); 110 } 111 112 // If the only preference is the title, hide the group. 113 preferenceGroup.setVisible(preferenceGroup.getPreferenceCount() > 1); 114 } 115 getAccountIcon(AuthenticatorDescription description, UserHandle userHandle)116 private Drawable getAccountIcon(AuthenticatorDescription description, UserHandle userHandle) { 117 Drawable icon = null; 118 try { 119 if (description.iconId != 0) { 120 Context authContext = getContext().createPackageContextAsUser( 121 description.packageName, /* flags= */ 0, userHandle); 122 icon = getContext().getPackageManager().getUserBadgedIcon( 123 authContext.getDrawable(description.iconId), userHandle); 124 } 125 } catch (PackageManager.NameNotFoundException e) { 126 LOG.w("Bad package name for account type " + description.type, e); 127 } catch (Resources.NotFoundException e) { 128 LOG.w("Invalid icon id for account type " + description.type, e); 129 } 130 if (icon == null) { 131 icon = getContext().getPackageManager().getDefaultActivityIcon(); 132 } 133 return icon; 134 } 135 createPreference(String title, @Nullable Drawable icon)136 private Preference createPreference(String title, @Nullable Drawable icon) { 137 CarUiPreference preference = new CarUiPreference(getContext()); 138 preference.setTitle(title); 139 preference.setIcon(icon); 140 preference.setSelectable(false); 141 preference.setSingleLineTitle(false); 142 return preference; 143 } 144 } 145