1 /* 2 * Copyright (C) 2020 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.systemui.car.systembar; 18 19 import android.annotation.Nullable; 20 import android.app.role.OnRoleHoldersChangedListener; 21 import android.app.role.RoleManager; 22 import android.content.Context; 23 import android.content.pm.ApplicationInfo; 24 import android.content.pm.PackageManager; 25 import android.graphics.drawable.Drawable; 26 import android.os.UserHandle; 27 import android.util.Log; 28 import android.view.View; 29 import android.view.ViewGroup; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.systemui.car.CarDeviceProvisionedController; 33 import com.android.systemui.dagger.SysUISingleton; 34 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 39 import javax.inject.Inject; 40 41 /** 42 * Some CarSystemBarButtons can be associated to a {@link RoleManager} role. When they are, it is 43 * possible to have them display the icon of the default application (role holder) for the given 44 * role. 45 * 46 * This class monitors the current role holders for each role type and updates the button icon for 47 * this buttons with have this feature enabled. 48 */ 49 @SysUISingleton 50 public class ButtonRoleHolderController { 51 private static final String TAG = "ButtonRoleHolderController"; 52 53 private final Context mContext; 54 private final PackageManager mPackageManager; 55 private final RoleManager mRoleManager; 56 private final CarDeviceProvisionedController mDeviceController; 57 private final Map<String, CarSystemBarButton> mButtonMap = new HashMap<>(); 58 private final OnRoleHoldersChangedListener mListener = this::onRoleChanged; 59 private boolean mRegistered; 60 61 @Inject ButtonRoleHolderController(Context context, PackageManager packageManager, RoleManager roleManager, CarDeviceProvisionedController deviceController)62 public ButtonRoleHolderController(Context context, PackageManager packageManager, 63 RoleManager roleManager, CarDeviceProvisionedController deviceController) { 64 mContext = context; 65 mPackageManager = packageManager; 66 mRoleManager = roleManager; 67 mDeviceController = deviceController; 68 } 69 70 /** 71 * Iterate through a view looking for CarSystemBarButton and add it to this controller if it 72 * opted to be associated with a {@link RoleManager} role type. 73 * 74 * @param v the View that may contain CarFacetButtons 75 */ addAllButtonsWithRoleName(View v)76 void addAllButtonsWithRoleName(View v) { 77 if (v instanceof CarSystemBarButton) { 78 CarSystemBarButton button = (CarSystemBarButton) v; 79 String roleName = button.getRoleName(); 80 if (roleName != null && button.isDefaultAppIconForRoleEnabled()) { 81 addButtonWithRoleName(button, roleName); 82 } 83 } else if (v instanceof ViewGroup) { 84 ViewGroup viewGroup = (ViewGroup) v; 85 for (int i = 0; i < viewGroup.getChildCount(); i++) { 86 addAllButtonsWithRoleName(viewGroup.getChildAt(i)); 87 } 88 } 89 } 90 addButtonWithRoleName(CarSystemBarButton button, String roleName)91 private void addButtonWithRoleName(CarSystemBarButton button, String roleName) { 92 mButtonMap.put(roleName, button); 93 updateIcon(roleName); 94 if (!mRegistered) { 95 mRoleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(), 96 mListener, UserHandle.ALL); 97 mRegistered = true; 98 } 99 } 100 removeAll()101 void removeAll() { 102 mButtonMap.clear(); 103 if (mRegistered) { 104 mRoleManager.removeOnRoleHoldersChangedListenerAsUser(mListener, UserHandle.ALL); 105 mRegistered = false; 106 } 107 } 108 109 @VisibleForTesting onRoleChanged(String roleName, UserHandle user)110 void onRoleChanged(String roleName, UserHandle user) { 111 if (RoleManager.ROLE_ASSISTANT.equals(roleName) 112 && user.getIdentifier() == mDeviceController.getCurrentUser()) { 113 updateIcon(roleName); 114 } 115 } 116 updateIcon(String roleName)117 private void updateIcon(String roleName) { 118 CarSystemBarButton button = mButtonMap.get(roleName); 119 if (button == null) { 120 return; 121 } 122 List<String> holders = mRoleManager.getRoleHoldersAsUser(button.getRoleName(), 123 UserHandle.of(mDeviceController.getCurrentUser())); 124 if (holders == null || holders.isEmpty()) { 125 button.setAppIcon(null); 126 } else { 127 button.setAppIcon(loadIcon(holders.get(0))); 128 } 129 } 130 131 @Nullable loadIcon(String packageName)132 private Drawable loadIcon(String packageName) { 133 try { 134 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 135 PackageManager.MATCH_ANY_USER); 136 return appInfo.loadIcon(mPackageManager); 137 } catch (PackageManager.NameNotFoundException e) { 138 Log.e(ButtonRoleHolderController.TAG, "Package not found: " + packageName, e); 139 return null; 140 } 141 } 142 } 143