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.launcher3; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.app.Dialog; 22 import android.app.DialogFragment; 23 import android.app.FragmentManager; 24 import android.content.ComponentName; 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.DialogInterface; 28 import android.content.Intent; 29 import android.os.Bundle; 30 import android.preference.ListPreference; 31 import android.preference.Preference; 32 import android.preference.PreferenceFragment; 33 import android.provider.Settings; 34 35 import com.android.launcher3.graphics.IconShapeOverride; 36 import com.android.launcher3.notification.NotificationListener; 37 import com.android.launcher3.util.SettingsObserver; 38 import com.android.launcher3.views.ButtonPreference; 39 40 /** 41 * Settings activity for Launcher. Currently implements the following setting: Allow rotation 42 */ 43 public class SettingsActivity extends Activity { 44 45 private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging"; 46 /** Hidden field Settings.Secure.NOTIFICATION_BADGING */ 47 public static final String NOTIFICATION_BADGING = "notification_badging"; 48 /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */ 49 private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners"; 50 51 @Override 52 protected void onCreate(Bundle savedInstanceState) { 53 super.onCreate(savedInstanceState); 54 55 if (savedInstanceState == null) { 56 // Display the fragment as the main content. 57 getFragmentManager().beginTransaction() 58 .replace(android.R.id.content, new LauncherSettingsFragment()) 59 .commit(); 60 } 61 } 62 63 /** 64 * This fragment shows the launcher preferences. 65 */ 66 public static class LauncherSettingsFragment extends PreferenceFragment { 67 68 private SystemDisplayRotationLockObserver mRotationLockObserver; 69 private IconBadgingObserver mIconBadgingObserver; 70 71 @Override 72 public void onCreate(Bundle savedInstanceState) { 73 super.onCreate(savedInstanceState); 74 getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); 75 addPreferencesFromResource(R.xml.launcher_preferences); 76 77 ContentResolver resolver = getActivity().getContentResolver(); 78 79 // Setup allow rotation preference 80 Preference rotationPref = findPreference(Utilities.ALLOW_ROTATION_PREFERENCE_KEY); 81 if (getResources().getBoolean(R.bool.allow_rotation)) { 82 // Launcher supports rotation by default. No need to show this setting. 83 getPreferenceScreen().removePreference(rotationPref); 84 } else { 85 mRotationLockObserver = new SystemDisplayRotationLockObserver(rotationPref, resolver); 86 87 // Register a content observer to listen for system setting changes while 88 // this UI is active. 89 mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION); 90 91 // Initialize the UI once 92 rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity())); 93 } 94 95 ButtonPreference iconBadgingPref = 96 (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY); 97 if (!Utilities.ATLEAST_OREO) { 98 getPreferenceScreen().removePreference( 99 findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY)); 100 getPreferenceScreen().removePreference(iconBadgingPref); 101 } else if (!getResources().getBoolean(R.bool.notification_badging_enabled)) { 102 getPreferenceScreen().removePreference(iconBadgingPref); 103 } else { 104 // Listen to system notification badge settings while this UI is active. 105 mIconBadgingObserver = new IconBadgingObserver( 106 iconBadgingPref, resolver, getFragmentManager()); 107 mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS); 108 } 109 110 Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE); 111 if (iconShapeOverride != null) { 112 if (IconShapeOverride.isSupported(getActivity())) { 113 IconShapeOverride.handlePreferenceUi((ListPreference) iconShapeOverride); 114 } else { 115 getPreferenceScreen().removePreference(iconShapeOverride); 116 } 117 } 118 } 119 120 @Override 121 public void onDestroy() { 122 if (mRotationLockObserver != null) { 123 mRotationLockObserver.unregister(); 124 mRotationLockObserver = null; 125 } 126 if (mIconBadgingObserver != null) { 127 mIconBadgingObserver.unregister(); 128 mIconBadgingObserver = null; 129 } 130 super.onDestroy(); 131 } 132 } 133 134 /** 135 * Content observer which listens for system auto-rotate setting changes, and enables/disables 136 * the launcher rotation setting accordingly. 137 */ 138 private static class SystemDisplayRotationLockObserver extends SettingsObserver.System { 139 140 private final Preference mRotationPref; 141 142 public SystemDisplayRotationLockObserver( 143 Preference rotationPref, ContentResolver resolver) { 144 super(resolver); 145 mRotationPref = rotationPref; 146 } 147 148 @Override 149 public void onSettingChanged(boolean enabled) { 150 mRotationPref.setEnabled(enabled); 151 mRotationPref.setSummary(enabled 152 ? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc); 153 } 154 } 155 156 /** 157 * Content observer which listens for system badging setting changes, 158 * and updates the launcher badging setting subtext accordingly. 159 */ 160 private static class IconBadgingObserver extends SettingsObserver.Secure 161 implements Preference.OnPreferenceClickListener { 162 163 private final ButtonPreference mBadgingPref; 164 private final ContentResolver mResolver; 165 private final FragmentManager mFragmentManager; 166 167 public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver, 168 FragmentManager fragmentManager) { 169 super(resolver); 170 mBadgingPref = badgingPref; 171 mResolver = resolver; 172 mFragmentManager = fragmentManager; 173 } 174 175 @Override 176 public void onSettingChanged(boolean enabled) { 177 int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off; 178 179 boolean serviceEnabled = true; 180 if (enabled) { 181 // Check if the listener is enabled or not. 182 String enabledListeners = 183 Settings.Secure.getString(mResolver, NOTIFICATION_ENABLED_LISTENERS); 184 ComponentName myListener = 185 new ComponentName(mBadgingPref.getContext(), NotificationListener.class); 186 serviceEnabled = enabledListeners != null && 187 (enabledListeners.contains(myListener.flattenToString()) || 188 enabledListeners.contains(myListener.flattenToShortString())); 189 if (!serviceEnabled) { 190 summary = R.string.title_missing_notification_access; 191 } 192 } 193 mBadgingPref.setWidgetFrameVisible(!serviceEnabled); 194 mBadgingPref.setOnPreferenceClickListener(serviceEnabled ? null : this); 195 mBadgingPref.setSummary(summary); 196 197 } 198 199 @Override 200 public boolean onPreferenceClick(Preference preference) { 201 new NotificationAccessConfirmation().show(mFragmentManager, "notification_access"); 202 return true; 203 } 204 } 205 206 public static class NotificationAccessConfirmation 207 extends DialogFragment implements DialogInterface.OnClickListener { 208 209 @Override 210 public Dialog onCreateDialog(Bundle savedInstanceState) { 211 final Context context = getActivity(); 212 String msg = context.getString(R.string.msg_missing_notification_access, 213 context.getString(R.string.derived_app_name)); 214 return new AlertDialog.Builder(context) 215 .setTitle(R.string.title_missing_notification_access) 216 .setMessage(msg) 217 .setNegativeButton(android.R.string.cancel, null) 218 .setPositiveButton(R.string.title_change_settings, this) 219 .create(); 220 } 221 222 @Override 223 public void onClick(DialogInterface dialogInterface, int i) { 224 ComponentName cn = new ComponentName(getActivity(), NotificationListener.class); 225 Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS) 226 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 227 .putExtra(":settings:fragment_args_key", cn.flattenToString()); 228 getActivity().startActivity(intent); 229 } 230 } 231 } 232