1 /*
2  * Copyright (C) 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.settings.bugreporthandler;
18 
19 import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_PROFILE_APP_SUBTEXT;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_APP_SUBTEXT;
21 import static android.provider.Settings.ACTION_BUGREPORT_HANDLER_SETTINGS;
22 
23 import android.app.Activity;
24 import android.app.admin.DevicePolicyManager;
25 import android.app.settings.SettingsEnums;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.PackageItemInfo;
30 import android.content.pm.PackageManager;
31 import android.content.pm.UserInfo;
32 import android.util.Log;
33 import android.util.Pair;
34 import android.view.View;
35 
36 import androidx.annotation.VisibleForTesting;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.settings.R;
40 import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
41 import com.android.settings.development.DeveloperOptionAwareMixin;
42 import com.android.settingslib.applications.DefaultAppInfo;
43 import com.android.settingslib.development.DevelopmentSettingsEnabler;
44 import com.android.settingslib.widget.CandidateInfo;
45 import com.android.settingslib.widget.FooterPreference;
46 import com.android.settingslib.widget.SelectorWithWidgetPreference;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 /**
52  * Picker for BugReportHandler.
53  */
54 public class BugReportHandlerPicker extends DefaultAppPickerFragment implements
55         DeveloperOptionAwareMixin {
56     private static final String TAG = "BugReportHandlerPicker";
57 
58     private BugReportHandlerUtil mBugReportHandlerUtil;
59     private FooterPreference mFooter;
60 
getHandlerApp(String key)61     private static String getHandlerApp(String key) {
62         int index = key.lastIndexOf('#');
63         String handlerApp = key.substring(0, index);
64         return handlerApp;
65     }
66 
getHandlerUser(String key)67     private static int getHandlerUser(String key) {
68         int index = key.lastIndexOf('#');
69         int handlerUser = 0;
70         try {
71             handlerUser = Integer.parseInt(key.substring(index + 1));
72         } catch (NumberFormatException nfe) {
73             Log.e(TAG, "Failed to get handlerUser");
74         }
75         return handlerUser;
76     }
77 
78     @VisibleForTesting
getKey(String handlerApp, int handlerUser)79     static String getKey(String handlerApp, int handlerUser) {
80         return handlerApp + "#" + handlerUser;
81     }
82 
83     @Override
onAttach(Context context)84     public void onAttach(Context context) {
85         super.onAttach(context);
86         if (!DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context)) {
87             getActivity().finish();
88         }
89     }
90 
91     @Override
getPreferenceScreenResId()92     protected int getPreferenceScreenResId() {
93         return R.xml.bug_report_handler_settings;
94     }
95 
96     @Override
addStaticPreferences(PreferenceScreen screen)97     protected void addStaticPreferences(PreferenceScreen screen) {
98         if (mFooter == null) {
99             mFooter = new FooterPreference(screen.getContext());
100             mFooter.setIcon(R.drawable.ic_info_outline_24dp);
101             mFooter.setSingleLineTitle(false);
102             mFooter.setTitle(R.string.bug_report_handler_picker_footer_text);
103             mFooter.setSelectable(false);
104         }
105         screen.addPreference(mFooter);
106     }
107 
108     @Override
getCandidates()109     protected List<DefaultAppInfo> getCandidates() {
110         final Context context = getContext();
111         final List<Pair<ApplicationInfo, Integer>> validBugReportHandlerInfos =
112                 getBugReportHandlerUtil().getValidBugReportHandlerInfos(context);
113         final List<DefaultAppInfo> candidates = new ArrayList<>();
114         for (Pair<ApplicationInfo, Integer> info : validBugReportHandlerInfos) {
115             candidates.add(createDefaultAppInfo(context, mPm, info.second, info.first));
116         }
117         return candidates;
118     }
119 
getBugReportHandlerUtil()120     private BugReportHandlerUtil getBugReportHandlerUtil() {
121         if (mBugReportHandlerUtil == null) {
122             setBugReportHandlerUtil(createDefaultBugReportHandlerUtil());
123         }
124         return mBugReportHandlerUtil;
125     }
126 
127     @VisibleForTesting
setBugReportHandlerUtil(BugReportHandlerUtil bugReportHandlerUtil)128     void setBugReportHandlerUtil(BugReportHandlerUtil bugReportHandlerUtil) {
129         mBugReportHandlerUtil = bugReportHandlerUtil;
130     }
131 
132     @VisibleForTesting
createDefaultBugReportHandlerUtil()133     BugReportHandlerUtil createDefaultBugReportHandlerUtil() {
134         return new BugReportHandlerUtil();
135     }
136 
137     @Override
getDefaultKey()138     protected String getDefaultKey() {
139         final Pair<String, Integer> pair =
140                 getBugReportHandlerUtil().getCurrentBugReportHandlerAppAndUser(getContext());
141         return getKey(pair.first, pair.second);
142     }
143 
144     @Override
setDefaultKey(String key)145     protected boolean setDefaultKey(String key) {
146         return getBugReportHandlerUtil().setCurrentBugReportHandlerAppAndUser(getContext(),
147                 getHandlerApp(key),
148                 getHandlerUser(key));
149     }
150 
151     @Override
onSelectionPerformed(boolean success)152     protected void onSelectionPerformed(boolean success) {
153         super.onSelectionPerformed(success);
154         if (success) {
155             final Activity activity = getActivity();
156             final Intent intent = activity == null ? null : activity.getIntent();
157             if (intent != null && ACTION_BUGREPORT_HANDLER_SETTINGS.equals(intent.getAction())) {
158                 // If this was started through ACTION_BUGREPORT_HANDLER_SETTINGS then return once
159                 // we have chosen a new handler.
160                 getActivity().finish();
161             }
162         } else {
163             getBugReportHandlerUtil().showInvalidChoiceToast(getContext());
164             updateCandidates();
165         }
166     }
167 
168     @Override
getMetricsCategory()169     public int getMetricsCategory() {
170         return SettingsEnums.SETTINGS_BUGREPORT_HANDLER;
171     }
172 
173 
174     @Override
bindPreferenceExtra(SelectorWithWidgetPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey)175     public void bindPreferenceExtra(SelectorWithWidgetPreference pref,
176             String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
177         super.bindPreferenceExtra(pref, key, info, defaultKey, systemDefaultKey);
178         pref.setAppendixVisibility(View.GONE);
179     }
180 
181     @VisibleForTesting
createDefaultAppInfo(Context context, PackageManager pm, int userId, PackageItemInfo packageItemInfo)182     DefaultAppInfo createDefaultAppInfo(Context context, PackageManager pm, int userId,
183             PackageItemInfo packageItemInfo) {
184         return new BugreportHandlerAppInfo(context, pm, userId, packageItemInfo,
185                 getDescription(packageItemInfo.packageName, userId));
186     }
187 
getDescription(String handlerApp, int handlerUser)188     private String getDescription(String handlerApp, int handlerUser) {
189         final Context context = getContext();
190         if (BugReportHandlerUtil.SHELL_APP_PACKAGE.equals(handlerApp)) {
191             return context.getString(R.string.system_default_app_subtext);
192         }
193         if (mUserManager.getUserProfiles().size() < 2) {
194             return "";
195         }
196         final UserInfo userInfo = mUserManager.getUserInfo(handlerUser);
197         DevicePolicyManager devicePolicyManager =
198                 context.getSystemService(DevicePolicyManager.class);
199 
200         if (userInfo != null && userInfo.isManagedProfile()) {
201             return devicePolicyManager.getResources().getString(WORK_PROFILE_APP_SUBTEXT,
202                     () -> context.getString(R.string.work_profile_app_subtext));
203         }
204         return devicePolicyManager.getResources().getString(PERSONAL_PROFILE_APP_SUBTEXT,
205                 () -> context.getString(R.string.personal_profile_app_subtext));
206     }
207 
208     private static class BugreportHandlerAppInfo extends DefaultAppInfo {
209         private final Context mContext;
210 
BugreportHandlerAppInfo(Context context, PackageManager pm, int userId, PackageItemInfo packageItemInfo, String summary)211         BugreportHandlerAppInfo(Context context, PackageManager pm, int userId,
212                 PackageItemInfo packageItemInfo, String summary) {
213             super(context, pm, userId, packageItemInfo, summary, true /* enabled */);
214             mContext = context;
215         }
216 
217         @Override
getKey()218         public String getKey() {
219             if (packageItemInfo != null) {
220                 return BugReportHandlerPicker.getKey(packageItemInfo.packageName, userId);
221             } else {
222                 return null;
223             }
224         }
225 
226         @Override
loadLabel()227         public CharSequence loadLabel() {
228             if (mContext == null || packageItemInfo == null) {
229                 return null;
230             }
231             if (BugReportHandlerUtil.SHELL_APP_PACKAGE.equals(packageItemInfo.packageName)) {
232                 return mContext.getString(com.android.internal.R.string.android_system_label);
233             }
234             return super.loadLabel();
235         }
236     }
237 }
238