1 /* 2 * Copyright (C) 2015 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.settings.dashboard.profileselector; 18 19 import android.app.Dialog; 20 import android.app.PendingIntent; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.DialogInterface.OnCancelListener; 24 import android.content.DialogInterface.OnDismissListener; 25 import android.content.DialogInterface.OnShowListener; 26 import android.content.Intent; 27 import android.content.pm.UserInfo; 28 import android.os.Bundle; 29 import android.os.UserHandle; 30 import android.os.UserManager; 31 import android.util.Log; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 35 import androidx.annotation.NonNull; 36 import androidx.appcompat.app.AlertDialog; 37 import androidx.fragment.app.DialogFragment; 38 import androidx.fragment.app.FragmentManager; 39 40 import com.android.internal.widget.DialogTitle; 41 import com.android.internal.widget.LinearLayoutManager; 42 import com.android.internal.widget.RecyclerView; 43 import com.android.settings.R; 44 import com.android.settings.Utils; 45 import com.android.settings.overlay.FeatureFactory; 46 import com.android.settingslib.drawer.Tile; 47 48 import java.util.List; 49 50 /** 51 * A {@link DialogFragment} that can select one of the different profiles. 52 */ 53 public class ProfileSelectDialog extends DialogFragment implements UserAdapter.OnClickListener { 54 55 private static final String TAG = "ProfileSelectDialog"; 56 private static final String ARG_SELECTED_TILE = "selectedTile"; 57 private static final String ARG_SOURCE_METRIC_CATEGORY = "sourceMetricCategory"; 58 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 59 60 private int mSourceMetricCategory; 61 private Tile mSelectedTile; 62 private OnShowListener mOnShowListener; 63 private OnCancelListener mOnCancelListener; 64 private OnDismissListener mOnDismissListener; 65 66 /** 67 * Display the profile select dialog, adding the fragment to the given FragmentManager. 68 * 69 * @param manager The FragmentManager this fragment will be added to. 70 * @param tile The tile for this fragment. 71 * @param sourceMetricCategory The source metric category. 72 * @param onShowListener The listener listens to the dialog showing event. 73 * @param onDismissListener The listener listens to the dialog dismissing event. 74 * @param onCancelListener The listener listens to the dialog cancelling event. 75 */ show(FragmentManager manager, Tile tile, int sourceMetricCategory, OnShowListener onShowListener, OnDismissListener onDismissListener, OnCancelListener onCancelListener)76 public static void show(FragmentManager manager, Tile tile, int sourceMetricCategory, 77 OnShowListener onShowListener, OnDismissListener onDismissListener, 78 OnCancelListener onCancelListener) { 79 final ProfileSelectDialog dialog = new ProfileSelectDialog(); 80 final Bundle args = new Bundle(); 81 args.putParcelable(ARG_SELECTED_TILE, tile); 82 args.putInt(ARG_SOURCE_METRIC_CATEGORY, sourceMetricCategory); 83 dialog.setArguments(args); 84 dialog.mOnShowListener = onShowListener; 85 dialog.mOnDismissListener = onDismissListener; 86 dialog.mOnCancelListener = onCancelListener; 87 dialog.show(manager, "select_profile"); 88 } 89 90 @Override onCreate(Bundle savedInstanceState)91 public void onCreate(Bundle savedInstanceState) { 92 super.onCreate(savedInstanceState); 93 Bundle arguments = requireArguments(); 94 mSelectedTile = arguments.getParcelable(ARG_SELECTED_TILE, Tile.class); 95 mSourceMetricCategory = arguments.getInt(ARG_SOURCE_METRIC_CATEGORY); 96 } 97 98 @NonNull 99 @Override onCreateDialog(Bundle savedInstanceState)100 public Dialog onCreateDialog(Bundle savedInstanceState) { 101 return createDialog(getContext(), mSelectedTile.userHandle, this); 102 } 103 104 /** 105 * Creates the profile select dialog. 106 */ createDialog(Context context, List<UserHandle> userProfiles, UserAdapter.OnClickListener onClickListener)107 public static Dialog createDialog(Context context, List<UserHandle> userProfiles, 108 UserAdapter.OnClickListener onClickListener) { 109 LayoutInflater layoutInflater = context.getSystemService(LayoutInflater.class); 110 111 DialogTitle titleView = 112 (DialogTitle) layoutInflater.inflate(R.layout.user_select_title, null); 113 titleView.setText(com.android.settingslib.R.string.choose_profile); 114 115 View contentView = layoutInflater.inflate(R.layout.user_select, null); 116 117 RecyclerView listView = contentView.findViewById(R.id.list); 118 listView.setAdapter( 119 UserAdapter.createUserRecycleViewAdapter(context, userProfiles, onClickListener)); 120 listView.setLayoutManager( 121 new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); 122 123 return new AlertDialog.Builder(context) 124 .setCustomTitle(titleView) 125 .setView(contentView) 126 .create(); 127 } 128 129 @Override onClick(int position)130 public void onClick(int position) { 131 final UserHandle user = mSelectedTile.userHandle.get(position); 132 if (!mSelectedTile.hasPendingIntent()) { 133 final Intent intent = new Intent(mSelectedTile.getIntent()); 134 FeatureFactory.getFeatureFactory().getMetricsFeatureProvider() 135 .logStartedIntentWithProfile(intent, mSourceMetricCategory, 136 position == 1 /* isWorkProfile */); 137 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 138 getActivity().startActivityAsUser(intent, user); 139 } else { 140 PendingIntent pendingIntent = mSelectedTile.pendingIntentMap.get(user); 141 FeatureFactory.getFeatureFactory().getMetricsFeatureProvider() 142 .logSettingsTileClickWithProfile(mSelectedTile.getKey(getContext()), 143 mSourceMetricCategory, 144 position == 1 /* isWorkProfile */); 145 try { 146 pendingIntent.send(); 147 } catch (PendingIntent.CanceledException e) { 148 Log.w(TAG, "Failed executing pendingIntent. " + pendingIntent.getIntent(), e); 149 } 150 } 151 dismiss(); 152 } 153 154 @Override onStart()155 public void onStart() { 156 super.onStart(); 157 // The fragment shows the dialog within onStart() 158 if (mOnShowListener != null) { 159 mOnShowListener.onShow(getDialog()); 160 } 161 } 162 163 @Override onCancel(DialogInterface dialog)164 public void onCancel(DialogInterface dialog) { 165 super.onCancel(dialog); 166 if (mOnCancelListener != null) { 167 mOnCancelListener.onCancel(dialog); 168 } 169 } 170 171 @Override onDismiss(DialogInterface dialog)172 public void onDismiss(DialogInterface dialog) { 173 super.onDismiss(dialog); 174 if (mOnDismissListener != null) { 175 mOnDismissListener.onDismiss(dialog); 176 } 177 } 178 updateUserHandlesIfNeeded(Context context, Tile tile)179 public static void updateUserHandlesIfNeeded(Context context, Tile tile) { 180 final List<UserHandle> userHandles = tile.userHandle; 181 if (tile.userHandle == null || tile.userHandle.size() <= 1) { 182 return; 183 } 184 final UserManager userManager = UserManager.get(context); 185 for (int i = userHandles.size() - 1; i >= 0; i--) { 186 UserInfo userInfo = userManager.getUserInfo(userHandles.get(i).getIdentifier()); 187 if (userInfo == null 188 || userInfo.isCloneProfile() 189 || Utils.shouldHideUser(userHandles.get(i), userManager)) { 190 if (DEBUG) { 191 Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier()); 192 } 193 userHandles.remove(i); 194 } 195 } 196 } 197 198 /** 199 * Checks the userHandle and pendingIntentMap in the provided tile, and remove the invalid 200 * entries if any. 201 */ updatePendingIntentsIfNeeded(Context context, Tile tile)202 public static void updatePendingIntentsIfNeeded(Context context, Tile tile) { 203 if (tile.userHandle == null || tile.userHandle.size() <= 1 204 || tile.pendingIntentMap.size() <= 1) { 205 return; 206 } 207 for (UserHandle userHandle : List.copyOf(tile.userHandle)) { 208 if (!tile.pendingIntentMap.containsKey(userHandle)) { 209 if (DEBUG) { 210 Log.d(TAG, "Delete the user without pending intent: " 211 + userHandle.getIdentifier()); 212 } 213 tile.userHandle.remove(userHandle); 214 } 215 } 216 217 final UserManager userManager = UserManager.get(context); 218 for (UserHandle userHandle : List.copyOf(tile.pendingIntentMap.keySet())) { 219 UserInfo userInfo = userManager.getUserInfo(userHandle.getIdentifier()); 220 if (userInfo == null 221 || userInfo.isCloneProfile() 222 || Utils.shouldHideUser(userHandle, userManager)) { 223 if (DEBUG) { 224 Log.d(TAG, "Delete the user: " + userHandle.getIdentifier()); 225 } 226 tile.userHandle.remove(userHandle); 227 tile.pendingIntentMap.remove(userHandle); 228 } 229 } 230 } 231 } 232