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.packageinstaller.permission.ui.wear; 18 19 import android.Manifest; 20 import android.app.Activity; 21 import android.app.Fragment; 22 import android.content.Intent; 23 import android.content.pm.PackageInfo; 24 import android.content.pm.PackageManager; 25 import android.os.Bundle; 26 import android.support.wearable.view.WearableListView; 27 import android.util.Log; 28 import android.view.LayoutInflater; 29 import android.view.View; 30 import android.view.ViewGroup; 31 import android.widget.Toast; 32 33 import com.android.packageinstaller.R; 34 import com.android.packageinstaller.permission.model.AppPermissionGroup; 35 import com.android.packageinstaller.permission.model.AppPermissions; 36 import com.android.packageinstaller.permission.ui.wear.settings.PermissionsSettingsAdapter; 37 import com.android.packageinstaller.permission.ui.wear.settings.SettingsAdapter; 38 import com.android.packageinstaller.permission.utils.LocationUtils; 39 import com.android.packageinstaller.permission.utils.SafetyNetLogger; 40 import com.android.packageinstaller.permission.utils.Utils; 41 42 import java.util.ArrayList; 43 import java.util.List; 44 45 public final class AppPermissionsFragmentWear extends TitledSettingsFragment { 46 47 private static final String LOG_TAG = "ManagePermsFragment"; 48 49 private static final int WARNING_CONFIRMATION_REQUEST = 252; 50 private List<AppPermissionGroup> mToggledGroups; 51 private AppPermissions mAppPermissions; 52 private PermissionsSettingsAdapter mAdapter; 53 54 private boolean mHasConfirmedRevoke; 55 56 public static AppPermissionsFragmentWear newInstance(String packageName) { 57 return setPackageName(new AppPermissionsFragmentWear(), packageName); 58 } 59 60 private static <T extends Fragment> T setPackageName(T fragment, String packageName) { 61 Bundle arguments = new Bundle(); 62 arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); 63 fragment.setArguments(arguments); 64 return fragment; 65 } 66 67 @Override 68 public void onCreate(Bundle savedInstanceState) { 69 super.onCreate(savedInstanceState); 70 71 String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); 72 Activity activity = getActivity(); 73 PackageManager pm = activity.getPackageManager(); 74 PackageInfo packageInfo; 75 76 try { 77 packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); 78 } catch (PackageManager.NameNotFoundException e) { 79 Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); 80 packageInfo = null; 81 } 82 83 if (packageInfo == null) { 84 Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); 85 activity.finish(); 86 return; 87 } 88 89 mAppPermissions = new AppPermissions(activity, packageInfo, null, true, new Runnable() { 90 @Override 91 public void run() { 92 getActivity().finish(); 93 } 94 }); 95 96 mAdapter = new PermissionsSettingsAdapter(getContext()); 97 98 initializePermissionGroupList(); 99 } 100 101 @Override 102 public View onCreateView(LayoutInflater inflater, ViewGroup container, 103 Bundle savedInstanceState) { 104 return inflater.inflate(R.layout.settings, container, false); 105 } 106 107 @Override 108 public void onResume() { 109 super.onResume(); 110 mAppPermissions.refresh(); 111 112 // Also refresh the UI 113 final int count = mAdapter.getItemCount(); 114 for (int i = 0; i < count; ++i) { 115 updatePermissionGroupSetting(i); 116 } 117 } 118 119 @Override 120 public void onViewCreated(View view, Bundle savedInstanceState) { 121 super.onViewCreated(view, savedInstanceState); 122 if (mAppPermissions != null) { 123 initializeLayout(mAdapter); 124 mHeader.setText(R.string.app_permissions); 125 mDetails.setText(R.string.no_permissions); 126 if (mAdapter.getItemCount() == 0) { 127 mDetails.setVisibility(View.VISIBLE); 128 mWheel.setVisibility(View.GONE); 129 } else { 130 mDetails.setVisibility(View.GONE); 131 mWheel.setVisibility(View.VISIBLE); 132 } 133 } 134 } 135 136 private void initializePermissionGroupList() { 137 final String packageName = mAppPermissions.getPackageInfo().packageName; 138 List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); 139 List<SettingsAdapter.Setting<AppPermissionGroup>> nonSystemGroups = new ArrayList<>(); 140 141 final int count = groups.size(); 142 for (int i = 0; i < count; ++i) { 143 final AppPermissionGroup group = groups.get(i); 144 if (!Utils.shouldShowPermission(group, packageName)) { 145 continue; 146 } 147 148 boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); 149 150 SettingsAdapter.Setting<AppPermissionGroup> setting = 151 new SettingsAdapter.Setting<AppPermissionGroup>( 152 group.getLabel(), 153 getPermissionGroupIcon(group), 154 i); 155 setting.data = group; 156 157 // The UI shows System settings first, then non-system settings 158 if (isPlatform) { 159 mAdapter.addSetting(setting); 160 } else { 161 nonSystemGroups.add(setting); 162 } 163 } 164 165 // Now add the non-system settings to the end of the list 166 final int nonSystemCount = nonSystemGroups.size(); 167 for (int i = 0; i < nonSystemCount; ++i) { 168 final SettingsAdapter.Setting<AppPermissionGroup> setting = nonSystemGroups.get(i); 169 mAdapter.addSetting(setting); 170 } 171 } 172 173 @Override 174 public void onPause() { 175 super.onPause(); 176 logAndClearToggledGroups(); 177 } 178 179 @Override 180 public void onClick(WearableListView.ViewHolder view) { 181 final int index = view.getPosition(); 182 SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index); 183 final AppPermissionGroup group = setting.data; 184 185 if (group == null) { 186 Log.e(LOG_TAG, "Error: AppPermissionGroup is null"); 187 return; 188 } 189 190 // The way WearableListView is designed, there is no way to avoid this click handler 191 // Since the policy is fixed, ignore the click as the user is not able to change the state 192 // of this permission group 193 if (group.isPolicyFixed()) { 194 return; 195 } 196 197 addToggledGroup(group); 198 199 if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) { 200 LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel()); 201 return; 202 } 203 204 if (!group.areRuntimePermissionsGranted()) { 205 group.grantRuntimePermissions(false); 206 } else { 207 final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); 208 if (grantedByDefault || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) { 209 Intent intent = new Intent(getActivity(), WarningConfirmationActivity.class); 210 intent.putExtra(WarningConfirmationActivity.EXTRA_WARNING_MESSAGE, 211 getString(grantedByDefault ? 212 R.string.system_warning : R.string.old_sdk_deny_warning)); 213 intent.putExtra(WarningConfirmationActivity.EXTRA_INDEX, index); 214 startActivityForResult(intent, WARNING_CONFIRMATION_REQUEST); 215 } else { 216 group.revokeRuntimePermissions(false); 217 } 218 } 219 220 updatePermissionGroupSetting(index); 221 } 222 223 @Override 224 public void onActivityResult(int requestCode, int resultCode, Intent data) { 225 if (requestCode == WARNING_CONFIRMATION_REQUEST) { 226 if (resultCode == Activity.RESULT_OK) { 227 int index = data.getIntExtra(WarningConfirmationActivity.EXTRA_INDEX, -1); 228 if (index == -1) { 229 Log.e(LOG_TAG, "Warning confirmation request came back with no index."); 230 return; 231 } 232 233 SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index); 234 final AppPermissionGroup group = setting.data; 235 group.revokeRuntimePermissions(false); 236 if (!group.hasGrantedByDefaultPermission()) { 237 mHasConfirmedRevoke = true; 238 } 239 240 updatePermissionGroupSetting(index); 241 } 242 } else { 243 super.onActivityResult(requestCode, resultCode, data); 244 } 245 } 246 247 private void updatePermissionGroupSetting(int index) { 248 SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index); 249 AppPermissionGroup group = setting.data; 250 mAdapter.updateSetting( 251 index, 252 group.getLabel(), 253 getPermissionGroupIcon(group), 254 group); 255 } 256 257 private void addToggledGroup(AppPermissionGroup group) { 258 if (mToggledGroups == null) { 259 mToggledGroups = new ArrayList<>(); 260 } 261 // Double toggle is back to initial state. 262 if (mToggledGroups.contains(group)) { 263 mToggledGroups.remove(group); 264 } else { 265 mToggledGroups.add(group); 266 } 267 } 268 269 private void logAndClearToggledGroups() { 270 if (mToggledGroups != null) { 271 String packageName = mAppPermissions.getPackageInfo().packageName; 272 SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups); 273 mToggledGroups = null; 274 } 275 } 276 277 private int getPermissionGroupIcon(AppPermissionGroup group) { 278 String groupName = group.getName(); 279 boolean isEnabled = group.areRuntimePermissionsGranted(); 280 int resId; 281 282 switch (groupName) { 283 case Manifest.permission_group.CALENDAR: 284 resId = isEnabled ? R.drawable.ic_permission_calendar 285 : R.drawable.ic_permission_calendardisable; 286 break; 287 case Manifest.permission_group.CAMERA: 288 resId = isEnabled ? R.drawable.ic_permission_camera 289 : R.drawable.ic_permission_cameradisable; 290 break; 291 case Manifest.permission_group.CONTACTS: 292 resId = isEnabled ? R.drawable.ic_permission_contact 293 : R.drawable.ic_permission_contactdisable; 294 break; 295 case Manifest.permission_group.LOCATION: 296 resId = isEnabled ? R.drawable.ic_permission_location 297 : R.drawable.ic_permission_locationdisable; 298 break; 299 case Manifest.permission_group.MICROPHONE: 300 resId = isEnabled ? R.drawable.ic_permission_mic 301 : R.drawable.ic_permission_micdisable; 302 break; 303 case Manifest.permission_group.PHONE: 304 resId = isEnabled ? R.drawable.ic_permission_call 305 : R.drawable.ic_permission_calldisable; 306 break; 307 case Manifest.permission_group.SENSORS: 308 resId = isEnabled ? R.drawable.ic_permission_sensor 309 : R.drawable.ic_permission_sensordisable; 310 break; 311 case Manifest.permission_group.SMS: 312 resId = isEnabled ? R.drawable.ic_permission_sms 313 : R.drawable.ic_permission_smsdisable; 314 break; 315 case Manifest.permission_group.STORAGE: 316 resId = isEnabled ? R.drawable.ic_permission_storage 317 : R.drawable.ic_permission_storagedisable; 318 break; 319 default: 320 resId = isEnabled ? R.drawable.ic_permission_shield 321 : R.drawable.ic_permission_shielddisable; 322 } 323 324 return resId; 325 } 326 } 327