• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2018 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.core;
17 
18 import static android.text.Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;
19 
20 import android.annotation.LayoutRes;
21 import android.app.ActivityManager;
22 import android.content.ComponentName;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.content.res.TypedArray;
26 import android.graphics.text.LineBreakConfig;
27 import android.os.Bundle;
28 import android.text.TextUtils;
29 import android.util.Log;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.view.Window;
34 import android.widget.Toolbar;
35 
36 import androidx.annotation.NonNull;
37 import androidx.annotation.Nullable;
38 import androidx.coordinatorlayout.widget.CoordinatorLayout;
39 import androidx.fragment.app.FragmentActivity;
40 
41 import com.android.settings.R;
42 import com.android.settings.SetupWizardUtils;
43 import com.android.settings.SubSettings;
44 import com.android.settings.core.CategoryMixin.CategoryHandler;
45 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
46 import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
47 
48 import com.google.android.material.appbar.AppBarLayout;
49 import com.google.android.material.appbar.CollapsingToolbarLayout;
50 import com.google.android.material.resources.TextAppearanceConfig;
51 import com.google.android.setupcompat.util.WizardManagerHelper;
52 import com.google.android.setupdesign.util.ThemeHelper;
53 
54 /** Base activity for Settings pages */
55 public class SettingsBaseActivity extends FragmentActivity implements CategoryHandler {
56 
57     /**
58      * What type of page transition should be apply.
59      */
60     public static final String EXTRA_PAGE_TRANSITION_TYPE = "page_transition_type";
61 
62     protected static final boolean DEBUG_TIMING = false;
63     private static final String TAG = "SettingsBaseActivity";
64     private static final int DEFAULT_REQUEST = -1;
65     private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
66 
67     protected CategoryMixin mCategoryMixin;
68     protected CollapsingToolbarLayout mCollapsingToolbarLayout;
69     protected AppBarLayout mAppBarLayout;
70     private Toolbar mToolbar;
71 
72     @Override
getCategoryMixin()73     public CategoryMixin getCategoryMixin() {
74         return mCategoryMixin;
75     }
76 
77     @Override
onCreate(@ullable Bundle savedInstanceState)78     protected void onCreate(@Nullable Bundle savedInstanceState) {
79         super.onCreate(savedInstanceState);
80         if (isFinishing()) {
81             return;
82         }
83         if (isLockTaskModePinned() && !isSettingsRunOnTop()) {
84             Log.w(TAG, "Devices lock task mode pinned.");
85             finish();
86         }
87         final long startTime = System.currentTimeMillis();
88         getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
89         TextAppearanceConfig.setShouldLoadFontSynchronously(true);
90 
91         mCategoryMixin = new CategoryMixin(this);
92         getLifecycle().addObserver(mCategoryMixin);
93 
94         final TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
95         if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
96             requestWindowFeature(Window.FEATURE_NO_TITLE);
97         }
98         // Apply SetupWizard light theme during setup flow. This is for SubSettings pages.
99         final boolean isAnySetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
100         if (isAnySetupWizard && this instanceof SubSettings) {
101             setTheme(SetupWizardUtils.getTheme(this, getIntent()));
102             setTheme(R.style.SettingsPreferenceTheme_SetupWizard);
103             ThemeHelper.trySetDynamicColor(this);
104         }
105 
106         if (isToolbarEnabled() && !isAnySetupWizard) {
107             super.setContentView(R.layout.collapsing_toolbar_base_layout);
108             mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
109             mAppBarLayout = findViewById(R.id.app_bar);
110             if (mCollapsingToolbarLayout != null) {
111                 mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
112                 mCollapsingToolbarLayout.setHyphenationFrequency(HYPHENATION_FREQUENCY_NORMAL_FAST);
113                 mCollapsingToolbarLayout.setStaticLayoutBuilderConfigurer(builder ->
114                         builder.setLineBreakConfig(
115                                 new LineBreakConfig.Builder()
116                                         .setLineBreakWordStyle(
117                                                 LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
118                                         .build()));
119             }
120             disableCollapsingToolbarLayoutScrollingBehavior();
121         } else {
122             super.setContentView(R.layout.settings_base_layout);
123         }
124 
125         // This is to hide the toolbar from those pages which don't need a toolbar originally.
126         final Toolbar toolbar = findViewById(R.id.action_bar);
127         if (!isToolbarEnabled() || isAnySetupWizard) {
128             toolbar.setVisibility(View.GONE);
129             return;
130         }
131         setActionBar(toolbar);
132 
133         if (DEBUG_TIMING) {
134             Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms");
135         }
136     }
137 
138     @Override
setActionBar(@ndroidx.annotation.Nullable Toolbar toolbar)139     public void setActionBar(@androidx.annotation.Nullable Toolbar toolbar) {
140         super.setActionBar(toolbar);
141 
142         mToolbar = toolbar;
143     }
144 
145     @Override
onNavigateUp()146     public boolean onNavigateUp() {
147         if (!super.onNavigateUp()) {
148             finishAfterTransition();
149         }
150         return true;
151     }
152 
153     @Override
startActivityForResult(Intent intent, int requestCode, @androidx.annotation.Nullable Bundle options)154     public void startActivityForResult(Intent intent, int requestCode,
155             @androidx.annotation.Nullable Bundle options) {
156         final int transitionType = getTransitionType(intent);
157         super.startActivityForResult(intent, requestCode, options);
158         if (transitionType == TransitionType.TRANSITION_SLIDE) {
159             overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
160         } else if (transitionType == TransitionType.TRANSITION_FADE) {
161             overridePendingTransition(android.R.anim.fade_in, R.anim.sud_stay);
162         }
163     }
164 
165     @Override
onPause()166     protected void onPause() {
167         // For accessibility activities launched from setup wizard.
168         if (getTransitionType(getIntent()) == TransitionType.TRANSITION_FADE) {
169             overridePendingTransition(R.anim.sud_stay, android.R.anim.fade_out);
170         }
171         super.onPause();
172     }
173 
174     @Override
setContentView(@ayoutRes int layoutResID)175     public void setContentView(@LayoutRes int layoutResID) {
176         final ViewGroup parent = findViewById(R.id.content_frame);
177         if (parent != null) {
178             parent.removeAllViews();
179         }
180         LayoutInflater.from(this).inflate(layoutResID, parent);
181     }
182 
183     @Override
setContentView(View view)184     public void setContentView(View view) {
185         ((ViewGroup) findViewById(R.id.content_frame)).addView(view);
186     }
187 
188     @Override
setContentView(View view, ViewGroup.LayoutParams params)189     public void setContentView(View view, ViewGroup.LayoutParams params) {
190         ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
191     }
192 
193     @Override
setTitle(CharSequence title)194     public void setTitle(CharSequence title) {
195         super.setTitle(title);
196         if (mCollapsingToolbarLayout != null) {
197             mCollapsingToolbarLayout.setTitle(title);
198         }
199     }
200 
201     @Override
setTitle(int titleId)202     public void setTitle(int titleId) {
203         super.setTitle(getText(titleId));
204         if (mCollapsingToolbarLayout != null) {
205             mCollapsingToolbarLayout.setTitle(getText(titleId));
206         }
207     }
208 
209     /**
210      * SubSetting page should show a toolbar by default. If the page wouldn't show a toolbar,
211      * override this method and return false value.
212      *
213      * @return ture by default
214      */
isToolbarEnabled()215     protected boolean isToolbarEnabled() {
216         return true;
217     }
218 
isLockTaskModePinned()219     private boolean isLockTaskModePinned() {
220         final ActivityManager activityManager =
221                 getApplicationContext().getSystemService(ActivityManager.class);
222         return activityManager.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_PINNED;
223     }
224 
isSettingsRunOnTop()225     private boolean isSettingsRunOnTop() {
226         final ActivityManager activityManager =
227                 getApplicationContext().getSystemService(ActivityManager.class);
228         final String taskPkgName = activityManager.getRunningTasks(1 /* maxNum */)
229                 .get(0 /* index */).baseActivity.getPackageName();
230         return TextUtils.equals(getPackageName(), taskPkgName);
231     }
232 
233     /**
234      * @return whether or not the enabled state actually changed.
235      */
setTileEnabled(ComponentName component, boolean enabled)236     public boolean setTileEnabled(ComponentName component, boolean enabled) {
237         final PackageManager pm = getPackageManager();
238         int state = pm.getComponentEnabledSetting(component);
239         boolean isEnabled = state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
240         if (isEnabled != enabled || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
241             if (enabled) {
242                 mCategoryMixin.removeFromDenylist(component);
243             } else {
244                 mCategoryMixin.addToDenylist(component);
245             }
246             pm.setComponentEnabledSetting(component, enabled
247                             ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
248                             : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
249                     PackageManager.DONT_KILL_APP);
250             return true;
251         }
252         return false;
253     }
254 
disableCollapsingToolbarLayoutScrollingBehavior()255     private void disableCollapsingToolbarLayoutScrollingBehavior() {
256         if (mAppBarLayout == null) {
257             return;
258         }
259         final CoordinatorLayout.LayoutParams params =
260                 (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
261         final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
262         behavior.setDragCallback(
263                 new AppBarLayout.Behavior.DragCallback() {
264                     @Override
265                     public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
266                         return false;
267                     }
268                 });
269         params.setBehavior(behavior);
270     }
271 
getTransitionType(Intent intent)272     private int getTransitionType(Intent intent) {
273         if (intent == null) {
274             return TransitionType.TRANSITION_NONE;
275         }
276         return intent.getIntExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_NONE);
277     }
278 }
279