1 /* 2 * Copyright (C) 2021 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 package com.android.settings.applications.appinfo; 17 18 import static android.app.Activity.RESULT_CANCELED; 19 import static android.app.Activity.RESULT_OK; 20 21 import android.app.AppOpsManager; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.os.Bundle; 25 26 import androidx.appcompat.app.AlertDialog; 27 import androidx.preference.Preference; 28 import androidx.preference.Preference.OnPreferenceChangeListener; 29 30 import com.android.settings.R; 31 import com.android.settings.Settings; 32 import com.android.settings.applications.AppInfoWithHeader; 33 import com.android.settings.applications.AppStateAlarmsAndRemindersBridge; 34 import com.android.settingslib.RestrictedSwitchPreference; 35 import com.android.settingslib.applications.ApplicationsState.AppEntry; 36 37 /** 38 * App specific activity to show details about 39 * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}. 40 */ 41 public class AlarmsAndRemindersDetails extends AppInfoWithHeader 42 implements OnPreferenceChangeListener { 43 44 private static final String KEY_SWITCH = "alarms_and_reminders_switch"; 45 private static final String UNCOMMITTED_STATE_KEY = "uncommitted_state"; 46 47 private AppStateAlarmsAndRemindersBridge mAppBridge; 48 private AppOpsManager mAppOpsManager; 49 private RestrictedSwitchPreference mSwitchPref; 50 private AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState mPermissionState; 51 private volatile Boolean mUncommittedState; 52 53 /** 54 * Returns the string that states whether the app has access to 55 * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}. 56 */ getSummary(Context context, AppEntry entry)57 public static CharSequence getSummary(Context context, AppEntry entry) { 58 final AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = 59 new AppStateAlarmsAndRemindersBridge(context, /*appState=*/null, 60 /*callback=*/null).createPermissionState(entry.info.packageName, 61 entry.info.uid); 62 63 return context.getString(state.isAllowed() ? R.string.app_permission_summary_allowed 64 : R.string.app_permission_summary_not_allowed); 65 } 66 67 @Override onCreate(Bundle savedInstanceState)68 public void onCreate(Bundle savedInstanceState) { 69 super.onCreate(savedInstanceState); 70 71 final Context context = getActivity(); 72 mAppBridge = new AppStateAlarmsAndRemindersBridge(context, mState, /*callback=*/null); 73 mAppOpsManager = context.getSystemService(AppOpsManager.class); 74 75 if (savedInstanceState != null) { 76 mUncommittedState = (Boolean) savedInstanceState.get(UNCOMMITTED_STATE_KEY); 77 if (mUncommittedState != null && isAppSpecific()) { 78 setResult(mUncommittedState ? RESULT_OK : RESULT_CANCELED); 79 } 80 } 81 addPreferencesFromResource(R.xml.alarms_and_reminders); 82 mSwitchPref = findPreference(KEY_SWITCH); 83 mSwitchPref.setOnPreferenceChangeListener(this); 84 } 85 86 @Override onSaveInstanceState(Bundle outState)87 public void onSaveInstanceState(Bundle outState) { 88 super.onSaveInstanceState(outState); 89 if (mUncommittedState != null) { 90 outState.putObject(UNCOMMITTED_STATE_KEY, mUncommittedState); 91 } 92 } 93 94 @Override onPreferenceChange(Preference preference, Object newValue)95 public boolean onPreferenceChange(Preference preference, Object newValue) { 96 if (preference == mSwitchPref) { 97 mUncommittedState = (Boolean) newValue; 98 if (isAppSpecific()) { 99 setResult(mUncommittedState ? RESULT_OK : RESULT_CANCELED); 100 } 101 refreshUi(); 102 return true; 103 } 104 return false; 105 } 106 setCanScheduleAlarms(boolean newState)107 private void setCanScheduleAlarms(boolean newState) { 108 final int uid = mPackageInfo.applicationInfo.uid; 109 mAppOpsManager.setUidMode(AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM, uid, 110 newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED); 111 } 112 logPermissionChange(boolean newState, String packageName)113 private void logPermissionChange(boolean newState, String packageName) { 114 mMetricsFeatureProvider.action( 115 mMetricsFeatureProvider.getAttribution(getActivity()), 116 SettingsEnums.ACTION_ALARMS_AND_REMINDERS_TOGGLE, 117 getMetricsCategory(), 118 packageName, 119 newState ? 1 : 0); 120 } 121 isAppSpecific()122 private boolean isAppSpecific() { 123 return Settings.AlarmsAndRemindersAppActivity.class.getName().equals( 124 getIntent().getComponent().getClassName()); 125 } 126 127 @Override onPause()128 public void onPause() { 129 super.onPause(); 130 if (getActivity().isChangingConfigurations()) { 131 return; 132 } 133 if (mPermissionState != null && mUncommittedState != null 134 && mUncommittedState != mPermissionState.isAllowed()) { 135 setCanScheduleAlarms(mUncommittedState); 136 logPermissionChange(mUncommittedState, mPackageName); 137 mUncommittedState = null; 138 } 139 } 140 141 @Override refreshUi()142 protected boolean refreshUi() { 143 if (mPackageInfo == null || mPackageInfo.applicationInfo == null) { 144 return false; 145 } 146 mPermissionState = mAppBridge.createPermissionState(mPackageName, 147 mPackageInfo.applicationInfo.uid); 148 mSwitchPref.setEnabled(mPermissionState.shouldBeVisible()); 149 mSwitchPref.setChecked( 150 mUncommittedState != null ? mUncommittedState : mPermissionState.isAllowed()); 151 return true; 152 } 153 154 @Override createDialog(int id, int errorCode)155 protected AlertDialog createDialog(int id, int errorCode) { 156 return null; 157 } 158 159 @Override getMetricsCategory()160 public int getMetricsCategory() { 161 return SettingsEnums.ALARMS_AND_REMINDERS; 162 } 163 } 164