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.permissioncontroller.role.ui; 18 19 import static com.android.permissioncontroller.Constants.EXTRA_IS_ECM_IN_APP; 20 21 import android.app.role.RoleManager; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.pm.ApplicationInfo; 25 import android.os.Bundle; 26 import android.os.Process; 27 import android.provider.Settings; 28 import android.provider.Telephony; 29 import android.telecom.TelecomManager; 30 import android.text.TextUtils; 31 import android.util.Log; 32 import android.view.WindowManager; 33 34 import androidx.annotation.NonNull; 35 import androidx.annotation.Nullable; 36 import androidx.fragment.app.FragmentActivity; 37 38 import com.android.permissioncontroller.DeviceUtils; 39 import com.android.permissioncontroller.PermissionControllerStatsLog; 40 import com.android.permissioncontroller.permission.utils.CollectionUtils; 41 import com.android.permissioncontroller.role.model.UserDeniedManager; 42 import com.android.permissioncontroller.role.ui.wear.WearRequestRoleFragment; 43 import com.android.permissioncontroller.role.utils.PackageUtils; 44 import com.android.role.controller.model.Role; 45 import com.android.role.controller.model.Roles; 46 47 import java.util.List; 48 import java.util.Objects; 49 50 /** 51 * {@code Activity} for a role request. 52 */ 53 public class RequestRoleActivity extends FragmentActivity { 54 55 private static final String LOG_TAG = RequestRoleActivity.class.getSimpleName(); 56 57 private String mRoleName; 58 private String mPackageName; 59 60 @Override onCreate(@ullable Bundle savedInstanceState)61 protected void onCreate(@Nullable Bundle savedInstanceState) { 62 super.onCreate(savedInstanceState); 63 64 getWindow().addSystemFlags( 65 WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 66 67 mRoleName = getIntent().getStringExtra(Intent.EXTRA_ROLE_NAME); 68 mPackageName = getCallingPackage(); 69 70 if (!handleChangeDefaultDialerDialogCompatibility()) { 71 reportRequestResult( 72 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 73 finish(); 74 return; 75 } 76 77 if (!handleSmsDefaultDialogCompatibility()) { 78 reportRequestResult( 79 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 80 finish(); 81 return; 82 } 83 84 if (TextUtils.isEmpty(mRoleName)) { 85 Log.w(LOG_TAG, "Role name cannot be null or empty: " + mRoleName); 86 reportRequestResult( 87 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 88 finish(); 89 return; 90 } 91 if (TextUtils.isEmpty(mPackageName)) { 92 Log.w(LOG_TAG, "Package name cannot be null or empty: " + mPackageName); 93 reportRequestResult( 94 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 95 finish(); 96 return; 97 } 98 99 // Perform checks here so that we have a chance to finish without being visible to user. 100 Role role = Roles.get(this).get(mRoleName); 101 if (role == null) { 102 Log.w(LOG_TAG, "Unknown role: " + mRoleName); 103 reportRequestResult( 104 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 105 finish(); 106 return; 107 } 108 109 if (!role.isAvailableAsUser(Process.myUserHandle(), this)) { 110 Log.e(LOG_TAG, "Role is unavailable: " + mRoleName); 111 reportRequestResult( 112 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 113 finish(); 114 return; 115 } 116 117 if (!role.isVisibleAsUser(Process.myUserHandle(), this)) { 118 Log.e(LOG_TAG, "Role is invisible: " + mRoleName); 119 reportRequestResult( 120 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 121 finish(); 122 return; 123 } 124 125 if (!role.isRequestable()) { 126 Log.e(LOG_TAG, "Role is not requestable: " + mRoleName); 127 reportRequestResult( 128 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 129 finish(); 130 return; 131 } 132 133 if (!role.isExclusive()) { 134 Log.e(LOG_TAG, "Role is not exclusive: " + mRoleName); 135 reportRequestResult( 136 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 137 finish(); 138 return; 139 } 140 141 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(mPackageName, this); 142 if (applicationInfo == null) { 143 Log.w(LOG_TAG, "Unknown application: " + mPackageName); 144 reportRequestResult( 145 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED); 146 finish(); 147 return; 148 } 149 150 RoleManager roleManager = getSystemService(RoleManager.class); 151 List<String> currentPackageNames = roleManager.getRoleHolders(mRoleName); 152 if (currentPackageNames.contains(mPackageName)) { 153 Log.i(LOG_TAG, "Application is already a role holder, role: " + mRoleName 154 + ", package: " + mPackageName); 155 reportRequestResult(PermissionControllerStatsLog 156 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_ALREADY_GRANTED); 157 setResult(RESULT_OK); 158 finish(); 159 return; 160 } 161 162 Intent restrictionIntent = role.getApplicationRestrictionIntentAsUser(applicationInfo, 163 Process.myUserHandle(), this); 164 if (restrictionIntent != null) { 165 if (Objects.equals(restrictionIntent.getAction(), 166 Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)) { 167 Log.w(LOG_TAG, "Cannot request role due to user restriction" 168 + ", role: " + mRoleName + ", package: " + mPackageName); 169 reportRequestResult(PermissionControllerStatsLog 170 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_RESTRICTION); 171 } else { 172 Log.w(LOG_TAG, "Cannot request role due to enhanced confirmation restriction" 173 + ", role: " + mRoleName + ", package: " + mPackageName); 174 reportRequestResult(PermissionControllerStatsLog 175 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_ENHANCED_CONFIRMATION_RESTRICTION); 176 restrictionIntent.putExtra(EXTRA_IS_ECM_IN_APP, true); 177 } 178 startActivity(restrictionIntent); 179 finish(); 180 return; 181 } 182 183 if (!role.isPackageQualifiedAsUser(mPackageName, Process.myUserHandle(), this)) { 184 Log.w(LOG_TAG, "Application doesn't qualify for role, role: " + mRoleName 185 + ", package: " + mPackageName); 186 reportRequestResult(PermissionControllerStatsLog 187 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_NOT_QUALIFIED); 188 finish(); 189 return; 190 } 191 192 if (UserDeniedManager.getInstance(this).isDeniedAlways(mRoleName, mPackageName)) { 193 Log.w(LOG_TAG, "Application is denied always for role, role: " + mRoleName 194 + ", package: " + mPackageName); 195 reportRequestResult(PermissionControllerStatsLog 196 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_ALWAYS_DENIED); 197 finish(); 198 return; 199 } 200 201 if (savedInstanceState == null) { 202 if (DeviceUtils.isWear(this)) { 203 WearRequestRoleFragment fragment = WearRequestRoleFragment.newInstance( 204 mRoleName, mPackageName); 205 getSupportFragmentManager().beginTransaction() 206 .add(android.R.id.content, fragment) 207 .commit(); 208 } else { 209 RequestRoleFragment fragment = RequestRoleFragment.newInstance(mRoleName, 210 mPackageName); 211 getSupportFragmentManager().beginTransaction() 212 .add(fragment, null) 213 .commit(); 214 } 215 } 216 } 217 218 /** 219 * Handle compatibility with the old 220 * {@link com.android.server.telecom.components.ChangeDefaultDialerDialog}. 221 * 222 * @return whether we should continue requesting the role. The activity should be finished if 223 * {@code false} is returned. 224 */ handleChangeDefaultDialerDialogCompatibility()225 private boolean handleChangeDefaultDialerDialogCompatibility() { 226 Intent intent = getIntent(); 227 if (!Objects.equals(intent.getAction(), TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)) { 228 return true; 229 } 230 231 Log.w(LOG_TAG, "TelecomManager.ACTION_CHANGE_DEFAULT_DIALER is deprecated; please use" 232 + " RoleManager.createRequestRoleIntent() and Activity.startActivityForResult()" 233 + " instead"); 234 235 mRoleName = RoleManager.ROLE_DIALER; 236 mPackageName = null; 237 238 // Intent.EXTRA_CALLING_PACKAGE is set in PermissionPolicyService.Internal 239 // .isActionRemovedForCallingPackage() and can be trusted. 240 String callingPackageName = intent.getStringExtra(Intent.EXTRA_CALLING_PACKAGE); 241 String extraPackageName = intent.getStringExtra( 242 TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME); 243 if (Objects.equals(extraPackageName, callingPackageName)) { 244 // Requesting for itself is okay. 245 mPackageName = extraPackageName; 246 return true; 247 } 248 249 RoleManager roleManager = getSystemService(RoleManager.class); 250 String holderPackageName = CollectionUtils.firstOrNull(roleManager.getRoleHolders( 251 RoleManager.ROLE_DIALER)); 252 if (Objects.equals(callingPackageName, holderPackageName)) { 253 // Giving away its own role is okay. 254 mPackageName = extraPackageName; 255 return true; 256 } 257 258 // If we reach here it's not okay. 259 return false; 260 } 261 262 /** 263 * Handle compatibility with the old {@link com.android.settings.SmsDefaultDialog}. 264 * 265 * @return whether we should continue requesting the role. The activity should be finished if 266 * {@code false} is returned. 267 */ handleSmsDefaultDialogCompatibility()268 private boolean handleSmsDefaultDialogCompatibility() { 269 Intent intent = getIntent(); 270 if (!Objects.equals(intent.getAction(), Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT)) { 271 return true; 272 } 273 274 Log.w(LOG_TAG, "Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT is deprecated; please use" 275 + " RoleManager.createRequestRoleIntent() and Activity.startActivityForResult()" 276 + " instead"); 277 278 mRoleName = RoleManager.ROLE_SMS; 279 mPackageName = null; 280 281 // Intent.EXTRA_CALLING_PACKAGE is set in PermissionPolicyService.Internal 282 // .isActionRemovedForCallingPackage() and can be trusted. 283 String callingPackageName = intent.getStringExtra(Intent.EXTRA_CALLING_PACKAGE); 284 String extraPackageName = intent.getStringExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME); 285 if (extraPackageName == null) { 286 // Launch the settings activity to show the list. 287 // TODO: Return RESULT_OK if any changes were made? 288 Intent defaultAppActivityIntent = DefaultAppActivity.createIntent( 289 RoleManager.ROLE_SMS, Process.myUserHandle(), this) 290 .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 291 startActivity(defaultAppActivityIntent); 292 return false; 293 } 294 295 if (Objects.equals(extraPackageName, callingPackageName)) { 296 // Requesting for itself is okay. 297 mPackageName = extraPackageName; 298 return true; 299 } 300 301 RoleManager roleManager = getSystemService(RoleManager.class); 302 String holderPackageName = CollectionUtils.firstOrNull(roleManager.getRoleHolders( 303 RoleManager.ROLE_SMS)); 304 if (Objects.equals(callingPackageName, holderPackageName)) { 305 // Giving away its own role is okay. 306 mPackageName = extraPackageName; 307 return true; 308 } 309 310 // If we reach here it's not okay. 311 return false; 312 } 313 reportRequestResult(int result)314 private void reportRequestResult(int result) { 315 RequestRoleFragment.reportRequestResult(getApplicationUid(mPackageName, this), mPackageName, 316 mRoleName, -1, -1, null, -1, null, result); 317 } 318 getApplicationUid(@ullable String packageName, @NonNull Context context)319 private static int getApplicationUid(@Nullable String packageName, @NonNull Context context) { 320 if (packageName == null) { 321 return -1; 322 } 323 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context); 324 if (applicationInfo == null) { 325 return -1; 326 } 327 return applicationInfo.uid; 328 } 329 330 @Override onNewIntent(@onNull Intent intent)331 protected void onNewIntent(@NonNull Intent intent) { 332 super.onNewIntent(intent); 333 334 Log.w(LOG_TAG, "Ignoring new intent: " + intent); 335 } 336 } 337