2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.android
.settingslib
.drawer
;
18 import android
.annotation
.LayoutRes
;
19 import android
.annotation
.Nullable
;
20 import android
.app
.Activity
;
21 import android
.content
.ActivityNotFoundException
;
22 import android
.content
.BroadcastReceiver
;
23 import android
.content
.ComponentName
;
24 import android
.content
.Context
;
25 import android
.content
.Intent
;
26 import android
.content
.IntentFilter
;
27 import android
.content
.pm
.PackageManager
;
28 import android
.content
.res
.TypedArray
;
29 import android
.os
.AsyncTask
;
30 import android
.os
.Bundle
;
31 import android
.os
.UserHandle
;
32 import android
.os
.UserManager
;
33 import android
.provider
.Settings
;
34 import android
.support
.v4
.widget
.DrawerLayout
;
35 import android
.text
.TextUtils
;
36 import android
.util
.ArraySet
;
37 import android
.util
.Log
;
38 import android
.util
.Pair
;
39 import android
.view
.Gravity
;
40 import android
.view
.LayoutInflater
;
41 import android
.view
.MenuItem
;
42 import android
.view
.View
;
43 import android
.view
.ViewGroup
;
44 import android
.view
.Window
;
45 import android
.view
.WindowManager
.LayoutParams
;
46 import android
.widget
.AdapterView
;
47 import android
.widget
.FrameLayout
;
48 import android
.widget
.ListView
;
49 import android
.widget
.Toolbar
;
51 import com
.android
.settingslib
.R
;
52 import com
.android
.settingslib
.applications
.InterestingConfigChanges
;
54 import java
.util
.ArrayList
;
55 import java
.util
.HashMap
;
56 import java
.util
.List
;
58 public class SettingsDrawerActivity
extends Activity
{
60 protected static final boolean DEBUG_TIMING
= false;
61 private static final String TAG
= "SettingsDrawerActivity";
62 private static final boolean DEBUG
= Log
.isLoggable(TAG
, Log
.DEBUG
);
64 public static final String EXTRA_SHOW_MENU
= "show_drawer_menu";
66 private static List
<DashboardCategory
> sDashboardCategories
;
67 private static HashMap
<Pair
<String
, String
>, Tile
> sTileCache
;
68 // Serves as a temporary list of tiles to ignore until we heard back from the PM that they
70 private static ArraySet
<ComponentName
> sTileBlacklist
= new ArraySet
<>();
71 private static InterestingConfigChanges sConfigTracker
;
73 private final PackageReceiver mPackageReceiver
= new PackageReceiver();
74 private final List
<CategoryListener
> mCategoryListeners
= new ArrayList
<>();
76 private SettingsDrawerAdapter mDrawerAdapter
;
77 private FrameLayout mContentHeaderContainer
;
78 private DrawerLayout mDrawerLayout
;
79 private boolean mShowingMenu
;
80 private UserManager mUserManager
;
83 protected void onCreate(@Nullable Bundle savedInstanceState
) {
84 super.onCreate(savedInstanceState
);
86 long startTime
= System
.currentTimeMillis();
88 TypedArray theme
= getTheme().obtainStyledAttributes(android
.R
.styleable
.Theme
);
89 if (!theme
.getBoolean(android
.R
.styleable
.Theme_windowNoTitle
, false)) {
90 getWindow().addFlags(LayoutParams
.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
);
91 getWindow().addFlags(LayoutParams
.FLAG_TRANSLUCENT_STATUS
);
92 requestWindowFeature(Window
.FEATURE_NO_TITLE
);
94 super.setContentView(R
.layout
.settings_with_drawer
);
95 mContentHeaderContainer
= (FrameLayout
) findViewById(R
.id
.content_header_container
);
96 mDrawerLayout
= (DrawerLayout
) findViewById(R
.id
.drawer_layout
);
97 if (mDrawerLayout
== null) {
100 Toolbar toolbar
= (Toolbar
) findViewById(R
.id
.action_bar
);
101 if (theme
.getBoolean(android
.R
.styleable
.Theme_windowNoTitle
, false)) {
102 toolbar
.setVisibility(View
.GONE
);
103 mDrawerLayout
.setDrawerLockMode(DrawerLayout
.LOCK_MODE_LOCKED_CLOSED
);
104 mDrawerLayout
= null;
107 getDashboardCategories();
108 setActionBar(toolbar
);
109 mDrawerAdapter
= new SettingsDrawerAdapter(this);
110 ListView listView
= (ListView
) findViewById(R
.id
.left_drawer
);
111 listView
.setAdapter(mDrawerAdapter
);
112 listView
.setOnItemClickListener(new AdapterView
.OnItemClickListener() {
113 public void onItemClick(android
.widget
.AdapterView
<?
> parent
, View view
, int position
,
115 onTileClicked(mDrawerAdapter
.getTile(position
));
119 mUserManager
= UserManager
.get(this);
120 if (DEBUG_TIMING
) Log
.d(TAG
, "onCreate took " + (System
.currentTimeMillis() - startTime
)
125 public boolean onOptionsItemSelected(MenuItem item
) {
126 if (mShowingMenu
&& mDrawerLayout
!= null && item
.getItemId() == android
.R
.id
.home
127 && mDrawerAdapter
.getCount() != 0) {
131 return super.onOptionsItemSelected(item
);
135 protected void onResume() {
138 if (mDrawerLayout
!= null) {
139 final IntentFilter filter
= new IntentFilter(Intent
.ACTION_PACKAGE_ADDED
);
140 filter
.addAction(Intent
.ACTION_PACKAGE_REMOVED
);
141 filter
.addAction(Intent
.ACTION_PACKAGE_CHANGED
);
142 filter
.addAction(Intent
.ACTION_PACKAGE_REPLACED
);
143 filter
.addDataScheme("package");
144 registerReceiver(mPackageReceiver
, filter
);
146 new CategoriesUpdater().execute();
148 final Intent intent
= getIntent();
149 if (intent
!= null) {
150 if (intent
.hasExtra(EXTRA_SHOW_MENU
)) {
151 if (intent
.getBooleanExtra(EXTRA_SHOW_MENU
, false)) {
152 // Intent explicitly set to show menu.
155 } else if (isTopLevelTile(intent
)) {
162 protected void onPause() {
163 if (mDrawerLayout
!= null) {
164 unregisterReceiver(mPackageReceiver
);
170 private boolean isTopLevelTile(Intent intent
) {
171 final ComponentName componentName
= intent
.getComponent();
172 if (componentName
== null) {
175 // Look for a tile that has the same component as incoming intent
176 final List
<DashboardCategory
> categories
= getDashboardCategories();
177 for (DashboardCategory category
: categories
) {
178 for (Tile tile
: category
.tiles
) {
179 if (TextUtils
.equals(tile
.intent
.getComponent().getClassName(),
180 componentName
.getClassName())) {
182 Log
.d(TAG
, "intent is for top level tile: " + tile
.title
);
189 Log
.d(TAG
, "Intent is not for top level settings " + intent
);
194 public void addCategoryListener(CategoryListener listener
) {
195 mCategoryListeners
.add(listener
);
198 public void remCategoryListener(CategoryListener listener
) {
199 mCategoryListeners
.remove(listener
);
202 public void setIsDrawerPresent(boolean isPresent
) {
204 mDrawerLayout
= (DrawerLayout
) findViewById(R
.id
.drawer_layout
);
207 if (mDrawerLayout
!= null) {
208 mDrawerLayout
.setDrawerLockMode(DrawerLayout
.LOCK_MODE_LOCKED_CLOSED
);
209 mDrawerLayout
= null;
214 public void openDrawer() {
215 if (mDrawerLayout
!= null) {
216 mDrawerLayout
.openDrawer(Gravity
.START
);
220 public void closeDrawer() {
221 if (mDrawerLayout
!= null) {
222 mDrawerLayout
.closeDrawers();
226 public void setContentHeaderView(View headerView
) {
227 mContentHeaderContainer
.removeAllViews();
228 if (headerView
!= null) {
229 mContentHeaderContainer
.addView(headerView
);
234 public void setContentView(@LayoutRes int layoutResID
) {
235 final ViewGroup parent
= (ViewGroup
) findViewById(R
.id
.content_frame
);
236 if (parent
!= null) {
237 parent
.removeAllViews();
239 LayoutInflater
.from(this).inflate(layoutResID
, parent
);
243 public void setContentView(View view
) {
244 ((ViewGroup
) findViewById(R
.id
.content_frame
)).addView(view
);
248 public void setContentView(View view
, ViewGroup
.LayoutParams params
) {
249 ((ViewGroup
) findViewById(R
.id
.content_frame
)).addView(view
, params
);
252 public void updateDrawer() {
253 if (mDrawerLayout
== null) {
256 // TODO: Do this in the background with some loading.
257 mDrawerAdapter
.updateCategories();
258 if (mDrawerAdapter
.getCount() != 0) {
259 mDrawerLayout
.setDrawerLockMode(DrawerLayout
.LOCK_MODE_UNLOCKED
);
261 mDrawerLayout
.setDrawerLockMode(DrawerLayout
.LOCK_MODE_LOCKED_CLOSED
);
265 public void showMenuIcon() {
267 getActionBar().setHomeAsUpIndicator(R
.drawable
.ic_menu
);
268 getActionBar().setHomeActionContentDescription(R
.string
.content_description_menu_button
);
269 getActionBar().setDisplayHomeAsUpEnabled(true);
272 public List
<DashboardCategory
> getDashboardCategories() {
273 if (sDashboardCategories
== null) {
274 sTileCache
= new HashMap
<>();
275 sConfigTracker
= new InterestingConfigChanges();
276 // Apply initial current config.
277 sConfigTracker
.applyNewConfig(getResources());
278 sDashboardCategories
= TileUtils
.getCategories(this, sTileCache
);
280 return sDashboardCategories
;
283 protected void onCategoriesChanged() {
285 final int N
= mCategoryListeners
.size();
286 for (int i
= 0; i
< N
; i
++) {
287 mCategoryListeners
.get(i
).onCategoriesChanged();
291 public boolean openTile(Tile tile
) {
294 startActivity(new Intent(Settings
.ACTION_SETTINGS
).addFlags(
295 Intent
.FLAG_ACTIVITY_CLEAR_TASK
));
299 updateUserHandlesIfNeeded(tile
);
300 int numUserHandles
= tile
.userHandle
.size();
301 if (numUserHandles
> 1) {
302 ProfileSelectDialog
.show(getFragmentManager(), tile
);
304 } else if (numUserHandles
== 1) {
305 // Show menu on top level items.
306 tile
.intent
.putExtra(EXTRA_SHOW_MENU
, true);
307 tile
.intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TASK
);
308 startActivityAsUser(tile
.intent
, tile
.userHandle
.get(0));
310 // Show menu on top level items.
311 tile
.intent
.putExtra(EXTRA_SHOW_MENU
, true);
312 tile
.intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TASK
);
313 startActivity(tile
.intent
);
315 } catch (ActivityNotFoundException e
) {
316 Log
.w(TAG
, "Couldn't find tile " + tile
.intent
, e
);
321 private void updateUserHandlesIfNeeded(Tile tile
) {
322 List
<UserHandle
> userHandles
= tile
.userHandle
;
324 for (int i
= userHandles
.size() - 1; i
>= 0; i
--) {
325 if (mUserManager
.getUserInfo(userHandles
.get(i
).getIdentifier()) == null) {
327 Log
.d(TAG
, "Delete the user: " + userHandles
.get(i
).getIdentifier());
329 userHandles
.remove(i
);
334 protected void onTileClicked(Tile tile
) {
335 if (openTile(tile
)) {
340 public HashMap
<Pair
<String
, String
>, Tile
> getTileCache() {
341 if (sTileCache
== null) {
342 getDashboardCategories();
347 public void onProfileTileOpen() {
351 public void setTileEnabled(ComponentName component
, boolean enabled
) {
352 PackageManager pm
= getPackageManager();
353 int state
= pm
.getComponentEnabledSetting(component
);
354 boolean isEnabled
= state
== PackageManager
.COMPONENT_ENABLED_STATE_ENABLED
;
355 if (isEnabled
!= enabled
|| state
== PackageManager
.COMPONENT_ENABLED_STATE_DEFAULT
) {
357 sTileBlacklist
.remove(component
);
359 sTileBlacklist
.add(component
);
361 pm
.setComponentEnabledSetting(component
, enabled
362 ? PackageManager
.COMPONENT_ENABLED_STATE_ENABLED
363 : PackageManager
.COMPONENT_ENABLED_STATE_DISABLED
,
364 PackageManager
.DONT_KILL_APP
);
365 new CategoriesUpdater().execute();
369 public interface CategoryListener
{
370 void onCategoriesChanged();
373 private class CategoriesUpdater
extends AsyncTask
<Void
, Void
, List
<DashboardCategory
>> {
375 protected List
<DashboardCategory
> doInBackground(Void
... params
) {
376 if (sConfigTracker
.applyNewConfig(getResources())) {
379 return TileUtils
.getCategories(SettingsDrawerActivity
.this, sTileCache
);
383 protected void onPreExecute() {
384 if (sConfigTracker
== null || sTileCache
== null) {
385 getDashboardCategories();
390 protected void onPostExecute(List
<DashboardCategory
> dashboardCategories
) {
391 for (int i
= 0; i
< dashboardCategories
.size(); i
++) {
392 DashboardCategory category
= dashboardCategories
.get(i
);
393 for (int j
= 0; j
< category
.tiles
.size(); j
++) {
394 Tile tile
= category
.tiles
.get(j
);
395 if (sTileBlacklist
.contains(tile
.intent
.getComponent())) {
396 category
.tiles
.remove(j
--);
400 sDashboardCategories
= dashboardCategories
;
401 onCategoriesChanged();
405 private class PackageReceiver
extends BroadcastReceiver
{
407 public void onReceive(Context context
, Intent intent
) {
408 new CategoriesUpdater().execute();