• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.settingslib.drawer;
17 
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;
50 
51 import com.android.settingslib.R;
52 import com.android.settingslib.applications.InterestingConfigChanges;
53 
54 import java.util.ArrayList;
55 import java.util.HashMap;
56 import java.util.List;
57 
58 public class SettingsDrawerActivity extends Activity {
59 
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);
63 
64     public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
65 
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
69     // are disabled.
70     private static ArraySet<ComponentName> sTileBlacklist = new ArraySet<>();
71     private static InterestingConfigChanges sConfigTracker;
72 
73     private final PackageReceiver mPackageReceiver = new PackageReceiver();
74     private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
75 
76     private SettingsDrawerAdapter mDrawerAdapter;
77     private FrameLayout mContentHeaderContainer;
78     private DrawerLayout mDrawerLayout;
79     private boolean mShowingMenu;
80     private UserManager mUserManager;
81 
82     @Override
onCreate(@ullable Bundle savedInstanceState)83     protected void onCreate(@Nullable Bundle savedInstanceState) {
84         super.onCreate(savedInstanceState);
85 
86         long startTime = System.currentTimeMillis();
87 
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);
93         }
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) {
98             return;
99         }
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;
105             return;
106         }
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,
114                     long id) {
115                 onTileClicked(mDrawerAdapter.getTile(position));
116             }
117         });
118 
119         mUserManager = UserManager.get(this);
120         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
121                 + " ms");
122     }
123 
124     @Override
onOptionsItemSelected(MenuItem item)125     public boolean onOptionsItemSelected(MenuItem item) {
126         if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
127                 && mDrawerAdapter.getCount() != 0) {
128             openDrawer();
129             return true;
130         }
131         return super.onOptionsItemSelected(item);
132     }
133 
134     @Override
onResume()135     protected void onResume() {
136         super.onResume();
137 
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);
145 
146             new CategoriesUpdater().execute();
147         }
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.
153                     showMenuIcon();
154                 }
155             } else if (isTopLevelTile(intent)) {
156                 showMenuIcon();
157             }
158         }
159     }
160 
161     @Override
onPause()162     protected void onPause() {
163         if (mDrawerLayout != null) {
164             unregisterReceiver(mPackageReceiver);
165         }
166 
167         super.onPause();
168     }
169 
isTopLevelTile(Intent intent)170     private boolean isTopLevelTile(Intent intent) {
171         final ComponentName componentName = intent.getComponent();
172         if (componentName == null) {
173             return false;
174         }
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())) {
181                     if (DEBUG) {
182                         Log.d(TAG, "intent is for top level tile: " + tile.title);
183                     }
184                     return true;
185                 }
186             }
187         }
188         if (DEBUG) {
189             Log.d(TAG, "Intent is not for top level settings " + intent);
190         }
191         return false;
192     }
193 
addCategoryListener(CategoryListener listener)194     public void addCategoryListener(CategoryListener listener) {
195         mCategoryListeners.add(listener);
196     }
197 
remCategoryListener(CategoryListener listener)198     public void remCategoryListener(CategoryListener listener) {
199         mCategoryListeners.remove(listener);
200     }
201 
setIsDrawerPresent(boolean isPresent)202     public void setIsDrawerPresent(boolean isPresent) {
203         if (isPresent) {
204             mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
205             updateDrawer();
206         } else {
207             if (mDrawerLayout != null) {
208                 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
209                 mDrawerLayout = null;
210             }
211         }
212     }
213 
openDrawer()214     public void openDrawer() {
215         if (mDrawerLayout != null) {
216             mDrawerLayout.openDrawer(Gravity.START);
217         }
218     }
219 
closeDrawer()220     public void closeDrawer() {
221         if (mDrawerLayout != null) {
222             mDrawerLayout.closeDrawers();
223         }
224     }
225 
setContentHeaderView(View headerView)226     public void setContentHeaderView(View headerView) {
227         mContentHeaderContainer.removeAllViews();
228         if (headerView != null) {
229             mContentHeaderContainer.addView(headerView);
230         }
231     }
232 
233     @Override
setContentView(@ayoutRes int layoutResID)234     public void setContentView(@LayoutRes int layoutResID) {
235         final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
236         if (parent != null) {
237             parent.removeAllViews();
238         }
239         LayoutInflater.from(this).inflate(layoutResID, parent);
240     }
241 
242     @Override
setContentView(View view)243     public void setContentView(View view) {
244         ((ViewGroup) findViewById(R.id.content_frame)).addView(view);
245     }
246 
247     @Override
setContentView(View view, ViewGroup.LayoutParams params)248     public void setContentView(View view, ViewGroup.LayoutParams params) {
249         ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
250     }
251 
updateDrawer()252     public void updateDrawer() {
253         if (mDrawerLayout == null) {
254             return;
255         }
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);
260         } else {
261             mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
262         }
263     }
264 
showMenuIcon()265     public void showMenuIcon() {
266         mShowingMenu = true;
267         getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
268         getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
269         getActionBar().setDisplayHomeAsUpEnabled(true);
270     }
271 
getDashboardCategories()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);
279         }
280         return sDashboardCategories;
281     }
282 
onCategoriesChanged()283     protected void onCategoriesChanged() {
284         updateDrawer();
285         final int N = mCategoryListeners.size();
286         for (int i = 0; i < N; i++) {
287             mCategoryListeners.get(i).onCategoriesChanged();
288         }
289     }
290 
openTile(Tile tile)291     public boolean openTile(Tile tile) {
292         closeDrawer();
293         if (tile == null) {
294             startActivity(new Intent(Settings.ACTION_SETTINGS).addFlags(
295                     Intent.FLAG_ACTIVITY_CLEAR_TASK));
296             return true;
297         }
298         try {
299             updateUserHandlesIfNeeded(tile);
300             int numUserHandles = tile.userHandle.size();
301             if (numUserHandles > 1) {
302                 ProfileSelectDialog.show(getFragmentManager(), tile);
303                 return false;
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));
309             } else {
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);
314             }
315         } catch (ActivityNotFoundException e) {
316             Log.w(TAG, "Couldn't find tile " + tile.intent, e);
317         }
318         return true;
319     }
320 
updateUserHandlesIfNeeded(Tile tile)321     private void updateUserHandlesIfNeeded(Tile tile) {
322         List<UserHandle> userHandles = tile.userHandle;
323 
324         for (int i = userHandles.size() - 1; i >= 0; i--) {
325             if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) {
326                 if (DEBUG) {
327                     Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
328                 }
329                 userHandles.remove(i);
330             }
331         }
332     }
333 
onTileClicked(Tile tile)334     protected void onTileClicked(Tile tile) {
335         if (openTile(tile)) {
336             finish();
337         }
338     }
339 
getTileCache()340     public HashMap<Pair<String, String>, Tile> getTileCache() {
341         if (sTileCache == null) {
342             getDashboardCategories();
343         }
344         return sTileCache;
345     }
346 
onProfileTileOpen()347     public void onProfileTileOpen() {
348         finish();
349     }
350 
setTileEnabled(ComponentName component, boolean enabled)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) {
356             if (enabled) {
357                 sTileBlacklist.remove(component);
358             } else {
359                 sTileBlacklist.add(component);
360             }
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();
366         }
367     }
368 
369     public interface CategoryListener {
onCategoriesChanged()370         void onCategoriesChanged();
371     }
372 
373     private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
374         @Override
doInBackground(Void... params)375         protected List<DashboardCategory> doInBackground(Void... params) {
376             if (sConfigTracker.applyNewConfig(getResources())) {
377                 sTileCache.clear();
378             }
379             return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
380         }
381 
382         @Override
onPreExecute()383         protected void onPreExecute() {
384             if (sConfigTracker == null || sTileCache == null) {
385                 getDashboardCategories();
386             }
387         }
388 
389         @Override
onPostExecute(List<DashboardCategory> dashboardCategories)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--);
397                     }
398                 }
399             }
400             sDashboardCategories = dashboardCategories;
401             onCategoriesChanged();
402         }
403     }
404 
405     private class PackageReceiver extends BroadcastReceiver {
406         @Override
onReceive(Context context, Intent intent)407         public void onReceive(Context context, Intent intent) {
408             new CategoriesUpdater().execute();
409         }
410     }
411 }
412