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