1bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov/* 2bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * Copyright (C) 2015 The Android Open Source Project 3bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * 4bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 5bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * you may not use this file except in compliance with the License. 6bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * You may obtain a copy of the License at 7bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * 8bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * http://www.apache.org/licenses/LICENSE-2.0 9bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * 10bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * Unless required by applicable law or agreed to in writing, software 11bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * distributed under the License is distributed on an "AS IS" BASIS, 12bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * See the License for the specific language governing permissions and 14bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov * limitations under the License. 15bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov */ 16bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 17bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovpackage com.android.packageinstaller.permission.ui; 18bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 19bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.app.Activity; 20bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 21bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.app.DialogFragment; 22bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.app.Fragment; 23bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.content.Intent; 24bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.content.IntentSender; 25bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.content.pm.PackageInfo; 26bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.content.pm.PackageManager; 27bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.graphics.drawable.Drawable; 28bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.os.Bundle; 29bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.os.RemoteCallback; 30bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.Preference; 31bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.PreferenceCategory; 32bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.PreferenceFragment; 33bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.PreferenceGroup; 34bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.PreferenceScreen; 35bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.SwitchPreference; 36bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.preference.TwoStatePreference; 37bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.text.SpannableString; 38bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.text.TextUtils; 39bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.text.style.ForegroundColorSpan; 40bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.util.TypedValue; 41bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.view.View; 42bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.widget.Button; 43bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.widget.ImageView; 44bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport android.widget.TextView; 45bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport com.android.packageinstaller.R; 46bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport com.android.packageinstaller.permission.model.AppPermissionGroup; 47bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport com.android.packageinstaller.permission.model.AppPermissions; 48f9bf4f795615bac03d1b35a0138318473b1ef6bfSvet Ganovimport com.android.packageinstaller.permission.utils.Utils; 49bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport com.android.packageinstaller.permission.ui.ConfirmActionDialogFragment.OnActionConfirmedListener; 50bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 51bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovimport java.util.List; 52bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 53bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganovpublic final class ReviewPermissionsActivity extends Activity 54bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov implements OnActionConfirmedListener { 55bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 56bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 57bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov protected void onCreate(Bundle savedInstanceState) { 58bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov super.onCreate(savedInstanceState); 59bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 60bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PackageInfo packageInfo = getTargetPackageInfo(); 61bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (packageInfo == null) { 62bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov finish(); 63bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return; 64bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 65bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 66bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov setContentView(R.layout.review_permissions); 67bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (getFragmentManager().findFragmentById(R.id.preferences_frame) == null) { 68bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov getFragmentManager().beginTransaction().add(R.id.preferences_frame, 69bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ReviewPermissionsFragment.newInstance(packageInfo)).commit(); 70bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 71bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 72bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 73bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 74bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public void onActionConfirmed(String action) { 75bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Fragment fragment = getFragmentManager().findFragmentById(R.id.preferences_frame); 76bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (fragment instanceof OnActionConfirmedListener) { 77bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ((OnActionConfirmedListener) fragment).onActionConfirmed(action); 78bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 79bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 80bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 81bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private PackageInfo getTargetPackageInfo() { 82bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); 83bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (TextUtils.isEmpty(packageName)) { 84bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return null; 85bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 86bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov try { 87bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return getPackageManager().getPackageInfo(packageName, 88bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PackageManager.GET_PERMISSIONS); 89bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } catch (PackageManager.NameNotFoundException e) { 90bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return null; 91bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 92bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 93bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 94bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public static final class ReviewPermissionsFragment extends PreferenceFragment 95bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov implements View.OnClickListener, Preference.OnPreferenceChangeListener, 96bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ConfirmActionDialogFragment.OnActionConfirmedListener { 97bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public static final String EXTRA_PACKAGE_INFO = 98bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov "com.android.packageinstaller.permission.ui.extra.PACKAGE_INFO"; 99bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 100bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private AppPermissions mAppPermissions; 101bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 102bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private Button mContinueButton; 103bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private Button mCancelButton; 104bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 105bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private PreferenceCategory mNewPermissionsCategory; 106bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 107bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private boolean mHasConfirmedRevoke; 108bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 109bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public static ReviewPermissionsFragment newInstance(PackageInfo packageInfo) { 110bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Bundle arguments = new Bundle(); 111bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov arguments.putParcelable(ReviewPermissionsFragment.EXTRA_PACKAGE_INFO, packageInfo); 112bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ReviewPermissionsFragment instance = new ReviewPermissionsFragment(); 113bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov instance.setArguments(arguments); 114bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov instance.setRetainInstance(true); 115bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return instance; 116bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 117bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 118bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 119f9bf4f795615bac03d1b35a0138318473b1ef6bfSvet Ganov public void onCreate(Bundle savedInstanceState) { 120bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov super.onCreate(savedInstanceState); 121bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 12215fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov Activity activity = getActivity(); 12315fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov if (activity == null) { 12415fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov return; 12515fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov } 12615fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov 127bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PackageInfo packageInfo = getArguments().getParcelable(EXTRA_PACKAGE_INFO); 128bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (packageInfo == null) { 12915fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov activity.finish(); 130bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return; 131bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 132bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 13315fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov mAppPermissions = new AppPermissions(activity, packageInfo, null, false, 134bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov new Runnable() { 135bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 136bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public void run() { 137bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov getActivity().finish(); 138bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 139bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov }); 140bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 141bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (mAppPermissions.getPermissionGroups().isEmpty()) { 14215fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov activity.finish(); 143bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return; 144bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 145bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 146dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov boolean reviewRequired = false; 147bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { 148bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (group.isReviewRequired()) { 149bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov reviewRequired = true; 150bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov break; 151bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 152bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 153bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 154bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (!reviewRequired) { 15515fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov activity.finish(); 156bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 157bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 158bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 159bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 160f9bf4f795615bac03d1b35a0138318473b1ef6bfSvet Ganov public void onViewCreated(View view, Bundle savedInstanceState) { 161bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov super.onViewCreated(view, savedInstanceState); 162bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov bindUi(); 163bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 164bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 165bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 166bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public void onResume() { 167bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov super.onResume(); 168dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov mAppPermissions.refresh(); 169bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov loadPreferences(); 170bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 171bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 172bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 173bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public void onClick(View view) { 17415fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov Activity activity = getActivity(); 17515fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov if (activity == null) { 17615fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov return; 17715fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov } 178bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (view == mContinueButton) { 179bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov confirmPermissionsReview(); 180bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov executeCallback(true); 181bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else if (view == mCancelButton) { 182bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov executeCallback(false); 18315fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov activity.setResult(Activity.RESULT_CANCELED); 184bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 18515fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov activity.finish(); 186bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 187bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 188bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 189bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public boolean onPreferenceChange(Preference preference, Object newValue) { 190bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (mHasConfirmedRevoke) { 191bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return true; 192bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 193bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (preference instanceof SwitchPreference) { 194bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov SwitchPreference switchPreference = (SwitchPreference) preference; 195bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (switchPreference.isChecked()) { 196bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov showWarnRevokeDialog(switchPreference.getKey()); 19715fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov } else { 19815fa03702aae07fb325d6be98d8c0cdeb344d20dSvetoslav Ganov return true; 199bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 200bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 201bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return false; 202bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 203bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 204bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov @Override 205bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov public void onActionConfirmed(String action) { 206bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Preference preference = getPreferenceManager().findPreference(action); 207bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (preference instanceof SwitchPreference) { 208bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov SwitchPreference switchPreference = (SwitchPreference) preference; 209bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov switchPreference.setChecked(false); 210bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mHasConfirmedRevoke = true; 211bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 212bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 213bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 214bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private void showWarnRevokeDialog(final String groupName) { 215bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov DialogFragment fragment = ConfirmActionDialogFragment.newInstance( 216bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov getString(R.string.old_sdk_deny_warning), groupName); 217bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov fragment.show(getFragmentManager(), fragment.getClass().getName()); 218bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 219bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 220bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private void confirmPermissionsReview() { 221bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PreferenceGroup preferenceGroup = mNewPermissionsCategory != null 222bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ? mNewPermissionsCategory : getPreferenceScreen(); 223bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 224bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final int preferenceCount = preferenceGroup.getPreferenceCount(); 225bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov for (int i = 0; i < preferenceCount; i++) { 226bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Preference preference = preferenceGroup.getPreference(i); 227bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (preference instanceof TwoStatePreference) { 228bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov TwoStatePreference twoStatePreference = (TwoStatePreference) preference; 229bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov String groupName = preference.getKey(); 230bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName); 231bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (twoStatePreference.isChecked()) { 232bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov group.grantRuntimePermissions(false); 233bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else { 234bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov group.revokeRuntimePermissions(false); 235bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 236bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov group.resetReviewRequired(); 237bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 238bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 239bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 240bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 241bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private void bindUi() { 242bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Activity activity = getActivity(); 243dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov if (activity == null) { 244dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov return; 245dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov } 246bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 247bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov // Set icon 248bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Drawable icon = mAppPermissions.getPackageInfo().applicationInfo.loadIcon( 249bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov activity.getPackageManager()); 250bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ImageView iconView = (ImageView) activity.findViewById(R.id.app_icon); 251bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov iconView.setImageDrawable(icon); 252bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 253bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov // Set message 254bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov String appLabel = mAppPermissions.getAppLabel().toString(); 255bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final int labelTemplateResId = isPackageUpdated() 256bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ? R.string.permission_review_title_template_update 257bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov : R.string.permission_review_title_template_install; 258bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov SpannableString message = new SpannableString(getString(labelTemplateResId, appLabel)); 259bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov // Set the permission message as the title so it can be announced. 260bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov activity.setTitle(message); 261bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 262bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov // Color the app name. 263bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final int appLabelStart = message.toString().indexOf(appLabel, 0); 264bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final int appLabelLength = appLabel.length(); 265bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 266bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov TypedValue typedValue = new TypedValue(); 267bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov activity.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true); 268bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final int color = activity.getColor(typedValue.resourceId); 269bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 270bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov message.setSpan(new ForegroundColorSpan(color), appLabelStart, 271bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov appLabelStart + appLabelLength, 0); 272bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov TextView permissionsMessageView = (TextView) activity.findViewById( 273bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov R.id.permissions_message); 274bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov permissionsMessageView.setText(message); 275bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 276bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 277bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mContinueButton = (Button) getActivity().findViewById(R.id.continue_button); 278bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mContinueButton.setOnClickListener(this); 279bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 280bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mCancelButton = (Button) getActivity().findViewById(R.id.cancel_button); 281bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mCancelButton.setOnClickListener(this); 282bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 283bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 284bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private void loadPreferences() { 285dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov Activity activity = getActivity(); 286dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov if (activity == null) { 287dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov return; 288dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov } 289dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov 290bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PreferenceScreen screen = getPreferenceScreen(); 291bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (screen == null) { 292bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov screen = getPreferenceManager().createPreferenceScreen(getActivity()); 293bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov setPreferenceScreen(screen); 294bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else { 295bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov screen.removeAll(); 296bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 297bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 298bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PreferenceGroup currentPermissionsCategory = null; 299bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov PreferenceGroup oldNewPermissionsCategory = mNewPermissionsCategory; 300bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mNewPermissionsCategory = null; 301bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 302bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final boolean isPackageUpdated = isPackageUpdated(); 303bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 304bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { 305df804e6a76051adb1e626a5713d32a6bf8b3ab9aSvet Ganov if (!Utils.shouldShowPermission(group, mAppPermissions.getPackageInfo().packageName) 306df804e6a76051adb1e626a5713d32a6bf8b3ab9aSvet Ganov || !Utils.OS_PKG.equals(group.getDeclaringPackage())) { 307bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov continue; 308bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 309bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 310bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov // TODO: Sort permissions - platform first then third-party ones 311bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 312bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final SwitchPreference preference; 313bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Preference cachedPreference = oldNewPermissionsCategory != null 314bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov ? oldNewPermissionsCategory.findPreference(group.getName()) : null; 315bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (cachedPreference instanceof SwitchPreference) { 316bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference = (SwitchPreference) cachedPreference; 317bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else { 318bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference = new SwitchPreference(getActivity()); 319bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 320bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setKey(group.getName()); 321dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov Drawable icon = Utils.loadDrawable(activity.getPackageManager(), 322bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov group.getIconPkg(), group.getIconResId()); 323bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setIcon(Utils.applyTint(getContext(), icon, 324bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov android.R.attr.colorControlNormal)); 325bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setTitle(group.getLabel()); 326bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setSummary(group.getDescription()); 327bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setPersistent(false); 328bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 329bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setOnPreferenceChangeListener(this); 330bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 331bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 332dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov preference.setChecked(group.areRuntimePermissionsGranted()); 333dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov 334bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov // Mutable state 335bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (group.isPolicyFixed()) { 336bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setEnabled(false); 337bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setSummary(getString( 338bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov R.string.permission_summary_enforced_by_policy)); 339bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else { 340bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov preference.setEnabled(true); 341bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 342bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 343bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (group.isReviewRequired()) { 344bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (!isPackageUpdated) { 345bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov screen.addPreference(preference); 346bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else { 347bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (mNewPermissionsCategory == null) { 348dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov mNewPermissionsCategory = new PreferenceCategory(activity); 349bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mNewPermissionsCategory.setTitle(R.string.new_permissions_category); 350bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mNewPermissionsCategory.setOrder(1); 351bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov screen.addPreference(mNewPermissionsCategory); 352bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 353bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov mNewPermissionsCategory.addPreference(preference); 354bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 355bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } else { 356bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (currentPermissionsCategory == null) { 357dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov currentPermissionsCategory = new PreferenceCategory(activity); 358bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov currentPermissionsCategory.setTitle(R.string.current_permissions_category); 359bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov currentPermissionsCategory.setOrder(2); 360bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov screen.addPreference(currentPermissionsCategory); 361bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 362bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov currentPermissionsCategory.addPreference(preference); 363bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 364bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 365bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 366bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 367bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private boolean isPackageUpdated() { 368bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); 369bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov final int groupCount = groups.size(); 370bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov for (int i = 0; i < groupCount; i++) { 371bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov AppPermissionGroup group = groups.get(i); 372bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (!group.isReviewRequired()) { 373bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return true; 374bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 375bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 376bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return false; 377bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 378bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov 379bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov private void executeCallback(boolean success) { 380bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Activity activity = getActivity(); 381dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov if (activity == null) { 382dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov return; 383dcc39fe43bc27412b7237195392b11299fd56ebfSvetoslav Ganov } 384bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (success) { 385bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov IntentSender intent = activity.getIntent().getParcelableExtra(Intent.EXTRA_INTENT); 386bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (intent != null) { 387bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov try { 388bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov int flagMask = 0; 389bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov int flagValues = 0; 390bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (activity.getIntent().getBooleanExtra( 391bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Intent.EXTRA_RESULT_NEEDED, false)) { 392bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov flagMask = Intent.FLAG_ACTIVITY_FORWARD_RESULT; 393bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov flagValues = Intent.FLAG_ACTIVITY_FORWARD_RESULT; 394bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 395bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov activity.startIntentSenderForResult(intent, -1, null, 396bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov flagMask, flagValues, 0); 397bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } catch (IntentSender.SendIntentException e) { 398bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov /* ignore */ 399bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 400bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov return; 401bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 402bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 403bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov RemoteCallback callback = activity.getIntent().getParcelableExtra( 404bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Intent.EXTRA_REMOTE_CALLBACK); 405bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov if (callback != null) { 406bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov Bundle result = new Bundle(); 407bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov result.putBoolean(Intent.EXTRA_RETURN_RESULT, success); 408bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov callback.sendResult(result); 409bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 410bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 411bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov } 412bf7316751f0c73b435b693fd20b0c9b2fa973e85Svet Ganov} 413