blob: 8589b7ee636a9e8b0216807ee37a9eaaea66bbf6 [file] [log] [blame]
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -07001/*
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
17package com.android.launcher3;
18
Sunny Goyal40253322018-04-19 09:27:38 -070019import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
20import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaultValue;
21
Sunny Goyalba406e22018-04-02 11:36:12 -070022import android.annotation.TargetApi;
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070023import android.app.Activity;
Sunny Goyal848cad52017-07-07 03:12:21 -070024import android.app.AlertDialog;
25import android.app.Dialog;
26import android.app.DialogFragment;
Sunny Goyal7f920b82018-06-27 15:47:49 -070027import android.app.Fragment;
Sunny Goyal848cad52017-07-07 03:12:21 -070028import android.app.FragmentManager;
29import android.content.ComponentName;
Sunny Goyalf48e5922016-05-12 15:36:20 -070030import android.content.ContentResolver;
Sunny Goyal848cad52017-07-07 03:12:21 -070031import android.content.Context;
32import android.content.DialogInterface;
33import android.content.Intent;
Sunny Goyalba406e22018-04-02 11:36:12 -070034import android.os.Build;
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070035import android.os.Bundle;
Sunny Goyalca187462017-03-31 20:09:34 -070036import android.preference.ListPreference;
Rahul Chaturvedi799aa042015-06-01 21:26:41 -040037import android.preference.Preference;
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070038import android.preference.PreferenceFragment;
Sunny Goyalba406e22018-04-02 11:36:12 -070039import android.preference.PreferenceScreen;
Sunny Goyalf48e5922016-05-12 15:36:20 -070040import android.provider.Settings;
Sunny Goyal3fbca152017-11-02 18:55:44 -070041import android.text.TextUtils;
Sunny Goyal3fbca152017-11-02 18:55:44 -070042import android.view.View;
Sunny Goyal3fbca152017-11-02 18:55:44 -070043import android.widget.Adapter;
Sunny Goyalba406e22018-04-02 11:36:12 -070044import android.widget.ListView;
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070045
Sunny Goyalca187462017-03-31 20:09:34 -070046import com.android.launcher3.graphics.IconShapeOverride;
Sunny Goyal848cad52017-07-07 03:12:21 -070047import com.android.launcher3.notification.NotificationListener;
Sunny Goyalba406e22018-04-02 11:36:12 -070048import com.android.launcher3.util.ListViewHighlighter;
Tonyd48710c2017-07-27 23:23:58 -070049import com.android.launcher3.util.SettingsObserver;
Sunny Goyal848cad52017-07-07 03:12:21 -070050import com.android.launcher3.views.ButtonPreference;
Sunny Goyalba406e22018-04-02 11:36:12 -070051
52import java.util.Objects;
Sunny Goyalca187462017-03-31 20:09:34 -070053
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070054/**
Rahul Chaturvedi799aa042015-06-01 21:26:41 -040055 * Settings activity for Launcher. Currently implements the following setting: Allow rotation
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070056 */
Sunny Goyal7f920b82018-06-27 15:47:49 -070057public class SettingsActivity extends Activity
58 implements PreferenceFragment.OnPreferenceStartFragmentCallback {
Tony Wickham2ab84822017-05-12 14:59:09 -070059
60 private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
Tonyd48710c2017-07-27 23:23:58 -070061 /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
62 public static final String NOTIFICATION_BADGING = "notification_badging";
Sunny Goyal848cad52017-07-07 03:12:21 -070063 /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
64 private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
Tony Wickham2ab84822017-05-12 14:59:09 -070065
Sunny Goyal3fbca152017-11-02 18:55:44 -070066 private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
Sunny Goyald47f2d22018-04-18 14:11:37 -070067 private static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
Sunny Goyal3fbca152017-11-02 18:55:44 -070068 private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
69 private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
70
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070071 @Override
72 protected void onCreate(Bundle savedInstanceState) {
73 super.onCreate(savedInstanceState);
74
Mario Bertschler2de2d672017-06-30 18:51:46 -070075 if (savedInstanceState == null) {
Sunny Goyal7f920b82018-06-27 15:47:49 -070076 Fragment f = Fragment.instantiate(this, getString(R.string.settings_fragment_name));
Mario Bertschler2de2d672017-06-30 18:51:46 -070077 // Display the fragment as the main content.
78 getFragmentManager().beginTransaction()
Sunny Goyal7f920b82018-06-27 15:47:49 -070079 .replace(android.R.id.content, f)
Mario Bertschler2de2d672017-06-30 18:51:46 -070080 .commit();
81 }
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -070082 }
83
Sunny Goyal3fbca152017-11-02 18:55:44 -070084 protected PreferenceFragment getNewFragment() {
85 return new LauncherSettingsFragment();
86 }
87
Sunny Goyal7f920b82018-06-27 15:47:49 -070088 @Override
89 public boolean onPreferenceStartFragment(
90 PreferenceFragment preferenceFragment, Preference pref) {
91 Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
92 if (f instanceof DialogFragment) {
93 ((DialogFragment) f).show(getFragmentManager(), pref.getKey());
94 } else {
95 getFragmentManager()
96 .beginTransaction()
97 .replace(android.R.id.content, f)
98 .addToBackStack(pref.getKey())
99 .commit();
100 }
101 return true;
102 }
103
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -0700104 /**
105 * This fragment shows the launcher preferences.
106 */
Sunny Goyalf48e5922016-05-12 15:36:20 -0700107 public static class LauncherSettingsFragment extends PreferenceFragment {
108
Tony Wickham2ab84822017-05-12 14:59:09 -0700109 private IconBadgingObserver mIconBadgingObserver;
Sunny Goyalf48e5922016-05-12 15:36:20 -0700110
Sunny Goyal3fbca152017-11-02 18:55:44 -0700111 private String mPreferenceKey;
112 private boolean mPreferenceHighlighted = false;
113
114 @Override
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -0700115 public void onCreate(Bundle savedInstanceState) {
116 super.onCreate(savedInstanceState);
Sunny Goyal3fbca152017-11-02 18:55:44 -0700117 if (savedInstanceState != null) {
118 mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY);
119 }
120
Sunny Goyalf48e5922016-05-12 15:36:20 -0700121 getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -0700122 addPreferencesFromResource(R.xml.launcher_preferences);
Sunny Goyal7779d622015-06-11 16:18:39 -0700123
Tony Wickham2ab84822017-05-12 14:59:09 -0700124 ContentResolver resolver = getActivity().getContentResolver();
125
Sunny Goyal848cad52017-07-07 03:12:21 -0700126 ButtonPreference iconBadgingPref =
127 (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY);
Hyunyoung Songe24cb632017-09-11 11:18:03 -0700128 if (!Utilities.ATLEAST_OREO) {
Sunny Goyal4179e9b2017-03-08 14:25:09 -0800129 getPreferenceScreen().removePreference(
130 findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
Tony Wickham2ab84822017-05-12 14:59:09 -0700131 getPreferenceScreen().removePreference(iconBadgingPref);
Tony Wickhamc1385152017-08-14 14:31:03 -0700132 } else if (!getResources().getBoolean(R.bool.notification_badging_enabled)) {
133 getPreferenceScreen().removePreference(iconBadgingPref);
Tony Wickham2ab84822017-05-12 14:59:09 -0700134 } else {
135 // Listen to system notification badge settings while this UI is active.
Sunny Goyal848cad52017-07-07 03:12:21 -0700136 mIconBadgingObserver = new IconBadgingObserver(
137 iconBadgingPref, resolver, getFragmentManager());
Tonyd48710c2017-07-27 23:23:58 -0700138 mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS);
Sunny Goyal4179e9b2017-03-08 14:25:09 -0800139 }
Sunny Goyalca187462017-03-31 20:09:34 -0700140
141 Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
142 if (iconShapeOverride != null) {
143 if (IconShapeOverride.isSupported(getActivity())) {
144 IconShapeOverride.handlePreferenceUi((ListPreference) iconShapeOverride);
145 } else {
146 getPreferenceScreen().removePreference(iconShapeOverride);
147 }
148 }
Sunny Goyal40253322018-04-19 09:27:38 -0700149
150 // Setup allow rotation preference
151 Preference rotationPref = findPreference(ALLOW_ROTATION_PREFERENCE_KEY);
152 if (getResources().getBoolean(R.bool.allow_rotation)) {
153 // Launcher supports rotation by default. No need to show this setting.
154 getPreferenceScreen().removePreference(rotationPref);
155 } else {
Sunny Goyal40253322018-04-19 09:27:38 -0700156 // Initialize the UI once
157 rotationPref.setDefaultValue(getAllowRotationDefaultValue());
158 }
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -0700159 }
Rahul Chaturvedi799aa042015-06-01 21:26:41 -0400160
161 @Override
Sunny Goyal3fbca152017-11-02 18:55:44 -0700162 public void onSaveInstanceState(Bundle outState) {
163 super.onSaveInstanceState(outState);
164 outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
165 }
166
167 @Override
168 public void onResume() {
169 super.onResume();
170
171 Intent intent = getActivity().getIntent();
172 mPreferenceKey = intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY);
173 if (isAdded() && !mPreferenceHighlighted && !TextUtils.isEmpty(mPreferenceKey)) {
174 getView().postDelayed(this::highlightPreference, DELAY_HIGHLIGHT_DURATION_MILLIS);
175 }
176 }
177
178 private void highlightPreference() {
Sunny Goyal3fbca152017-11-02 18:55:44 -0700179 Preference pref = findPreference(mPreferenceKey);
Sunny Goyalba406e22018-04-02 11:36:12 -0700180 if (pref == null || getPreferenceScreen() == null) {
Sunny Goyal3fbca152017-11-02 18:55:44 -0700181 return;
182 }
Sunny Goyalba406e22018-04-02 11:36:12 -0700183 PreferenceScreen screen = getPreferenceScreen();
184 if (Utilities.ATLEAST_OREO) {
185 screen = selectPreferenceRecursive(pref, screen);
186 }
187 if (screen == null) {
188 return;
189 }
190
191 View root = screen.getDialog() != null
192 ? screen.getDialog().getWindow().getDecorView() : getView();
193 ListView list = root.findViewById(android.R.id.list);
194 if (list == null || list.getAdapter() == null) {
195 return;
196 }
197 Adapter adapter = list.getAdapter();
Sunny Goyal3fbca152017-11-02 18:55:44 -0700198
199 // Find the position
200 int position = -1;
201 for (int i = adapter.getCount() - 1; i >= 0; i--) {
202 if (pref == adapter.getItem(i)) {
203 position = i;
204 break;
205 }
206 }
Sunny Goyalba406e22018-04-02 11:36:12 -0700207 new ListViewHighlighter(list, position);
Sunny Goyal3fbca152017-11-02 18:55:44 -0700208 mPreferenceHighlighted = true;
209 }
210
211 @Override
Sunny Goyalf48e5922016-05-12 15:36:20 -0700212 public void onDestroy() {
Tony Wickham2ab84822017-05-12 14:59:09 -0700213 if (mIconBadgingObserver != null) {
Tonyd48710c2017-07-27 23:23:58 -0700214 mIconBadgingObserver.unregister();
Tony Wickham2ab84822017-05-12 14:59:09 -0700215 mIconBadgingObserver = null;
216 }
Sunny Goyalf48e5922016-05-12 15:36:20 -0700217 super.onDestroy();
218 }
Sunny Goyalba406e22018-04-02 11:36:12 -0700219
220 @TargetApi(Build.VERSION_CODES.O)
221 private PreferenceScreen selectPreferenceRecursive(
222 Preference pref, PreferenceScreen topParent) {
223 if (!(pref.getParent() instanceof PreferenceScreen)) {
224 return null;
225 }
226
227 PreferenceScreen parent = (PreferenceScreen) pref.getParent();
228 if (Objects.equals(parent.getKey(), topParent.getKey())) {
229 return parent;
230 } else if (selectPreferenceRecursive(parent, topParent) != null) {
231 ((PreferenceScreen) parent.getParent())
232 .onItemClick(null, null, parent.getOrder(), 0);
233 return parent;
234 } else {
235 return null;
236 }
237 }
Sunny Goyalf48e5922016-05-12 15:36:20 -0700238 }
239
240 /**
Tony Wickham2ab84822017-05-12 14:59:09 -0700241 * Content observer which listens for system badging setting changes,
242 * and updates the launcher badging setting subtext accordingly.
243 */
Tonyd48710c2017-07-27 23:23:58 -0700244 private static class IconBadgingObserver extends SettingsObserver.Secure
Sunny Goyalb65e13c2017-08-01 11:04:15 -0700245 implements Preference.OnPreferenceClickListener {
Tony Wickham2ab84822017-05-12 14:59:09 -0700246
Sunny Goyal848cad52017-07-07 03:12:21 -0700247 private final ButtonPreference mBadgingPref;
Tony Wickham2ab84822017-05-12 14:59:09 -0700248 private final ContentResolver mResolver;
Sunny Goyal848cad52017-07-07 03:12:21 -0700249 private final FragmentManager mFragmentManager;
Tony Wickham2ab84822017-05-12 14:59:09 -0700250
Sunny Goyal848cad52017-07-07 03:12:21 -0700251 public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
252 FragmentManager fragmentManager) {
Tonyd48710c2017-07-27 23:23:58 -0700253 super(resolver);
Tony Wickham2ab84822017-05-12 14:59:09 -0700254 mBadgingPref = badgingPref;
255 mResolver = resolver;
Sunny Goyal848cad52017-07-07 03:12:21 -0700256 mFragmentManager = fragmentManager;
Tony Wickham2ab84822017-05-12 14:59:09 -0700257 }
258
259 @Override
Tonyd48710c2017-07-27 23:23:58 -0700260 public void onSettingChanged(boolean enabled) {
Sunny Goyal848cad52017-07-07 03:12:21 -0700261 int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
262
263 boolean serviceEnabled = true;
264 if (enabled) {
265 // Check if the listener is enabled or not.
266 String enabledListeners =
267 Settings.Secure.getString(mResolver, NOTIFICATION_ENABLED_LISTENERS);
268 ComponentName myListener =
269 new ComponentName(mBadgingPref.getContext(), NotificationListener.class);
270 serviceEnabled = enabledListeners != null &&
271 (enabledListeners.contains(myListener.flattenToString()) ||
272 enabledListeners.contains(myListener.flattenToShortString()));
273 if (!serviceEnabled) {
274 summary = R.string.title_missing_notification_access;
275 }
276 }
Sunny Goyalb65e13c2017-08-01 11:04:15 -0700277 mBadgingPref.setWidgetFrameVisible(!serviceEnabled);
278 mBadgingPref.setOnPreferenceClickListener(serviceEnabled ? null : this);
Sunny Goyal848cad52017-07-07 03:12:21 -0700279 mBadgingPref.setSummary(summary);
280
281 }
282
283 @Override
Sunny Goyalb65e13c2017-08-01 11:04:15 -0700284 public boolean onPreferenceClick(Preference preference) {
Sunny Goyal848cad52017-07-07 03:12:21 -0700285 new NotificationAccessConfirmation().show(mFragmentManager, "notification_access");
Sunny Goyalb65e13c2017-08-01 11:04:15 -0700286 return true;
Tony Wickham2ab84822017-05-12 14:59:09 -0700287 }
288 }
289
Sunny Goyal848cad52017-07-07 03:12:21 -0700290 public static class NotificationAccessConfirmation
291 extends DialogFragment implements DialogInterface.OnClickListener {
292
293 @Override
294 public Dialog onCreateDialog(Bundle savedInstanceState) {
295 final Context context = getActivity();
296 String msg = context.getString(R.string.msg_missing_notification_access,
297 context.getString(R.string.derived_app_name));
298 return new AlertDialog.Builder(context)
299 .setTitle(R.string.title_missing_notification_access)
300 .setMessage(msg)
301 .setNegativeButton(android.R.string.cancel, null)
302 .setPositiveButton(R.string.title_change_settings, this)
303 .create();
304 }
305
306 @Override
307 public void onClick(DialogInterface dialogInterface, int i) {
308 ComponentName cn = new ComponentName(getActivity(), NotificationListener.class);
Sunny Goyald47f2d22018-04-18 14:11:37 -0700309 Bundle showFragmentArgs = new Bundle();
310 showFragmentArgs.putString(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString());
311
Sunny Goyal848cad52017-07-07 03:12:21 -0700312 Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
313 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Sunny Goyald47f2d22018-04-18 14:11:37 -0700314 .putExtra(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString())
315 .putExtra(EXTRA_SHOW_FRAGMENT_ARGS, showFragmentArgs);
Sunny Goyal848cad52017-07-07 03:12:21 -0700316 getActivity().startActivity(intent);
317 }
318 }
Rahul Chaturvedi7fc77ca2015-05-19 18:02:16 -0700319}