SettingsDrawerActivity.java revision c10db985f399a3257a5dcfa80c3388e8b8ee3db4
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 */
16package com.android.settingslib.drawer;
17
18import android.annotation.LayoutRes;
19import android.annotation.Nullable;
20import android.app.Activity;
21import android.content.ActivityNotFoundException;
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.PackageManager;
28import android.content.res.TypedArray;
29import android.os.AsyncTask;
30import android.os.Bundle;
31import android.provider.Settings;
32import android.support.v4.widget.DrawerLayout;
33import android.util.ArraySet;
34import android.util.Log;
35import android.util.Pair;
36import android.view.Gravity;
37import android.view.LayoutInflater;
38import android.view.MenuItem;
39import android.view.View;
40import android.view.ViewGroup;
41import android.view.Window;
42import android.view.WindowManager.LayoutParams;
43import android.widget.AdapterView;
44import android.widget.FrameLayout;
45import android.widget.ListView;
46import android.widget.Toolbar;
47
48import com.android.settingslib.R;
49import com.android.settingslib.applications.InterestingConfigChanges;
50
51import java.util.ArrayList;
52import java.util.HashMap;
53import java.util.List;
54
55public class SettingsDrawerActivity extends Activity {
56
57    protected static final boolean DEBUG_TIMING = false;
58    private static final String TAG = "SettingsDrawerActivity";
59
60    public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
61
62    private static List<DashboardCategory> sDashboardCategories;
63    private static HashMap<Pair<String, String>, Tile> sTileCache;
64    // Serves as a temporary list of tiles to ignore until we heard back from the PM that they
65    // are disabled.
66    private static ArraySet<ComponentName> sTileBlacklist = new ArraySet<>();
67    private static InterestingConfigChanges sConfigTracker;
68
69    private final PackageReceiver mPackageReceiver = new PackageReceiver();
70    private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
71
72    private SettingsDrawerAdapter mDrawerAdapter;
73    private FrameLayout mContentHeaderContainer;
74    private DrawerLayout mDrawerLayout;
75    private boolean mShowingMenu;
76
77    @Override
78    protected void onCreate(@Nullable Bundle savedInstanceState) {
79        super.onCreate(savedInstanceState);
80
81        long startTime = System.currentTimeMillis();
82
83        TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
84        if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
85            getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
86            getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
87            requestWindowFeature(Window.FEATURE_NO_TITLE);
88        }
89        super.setContentView(R.layout.settings_with_drawer);
90        mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
91        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
92        if (mDrawerLayout == null) {
93            return;
94        }
95        Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
96        if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
97            toolbar.setVisibility(View.GONE);
98            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
99            mDrawerLayout = null;
100            return;
101        }
102        getDashboardCategories();
103        setActionBar(toolbar);
104        mDrawerAdapter = new SettingsDrawerAdapter(this);
105        ListView listView = (ListView) findViewById(R.id.left_drawer);
106        listView.setAdapter(mDrawerAdapter);
107        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
108            public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
109                    long id) {
110                onTileClicked(mDrawerAdapter.getTile(position));
111            };
112        });
113        if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
114                + " ms");
115    }
116
117    @Override
118    public boolean onOptionsItemSelected(MenuItem item) {
119        if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
120                && mDrawerAdapter.getCount() != 0) {
121            openDrawer();
122            return true;
123        }
124        return super.onOptionsItemSelected(item);
125    }
126
127    @Override
128    protected void onResume() {
129        super.onResume();
130
131        if (mDrawerLayout != null) {
132            final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
133            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
134            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
135            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
136            filter.addDataScheme("package");
137            registerReceiver(mPackageReceiver, filter);
138
139            new CategoriesUpdater().execute();
140        }
141        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_SHOW_MENU, false)) {
142            showMenuIcon();
143        }
144    }
145
146    @Override
147    protected void onPause() {
148        if (mDrawerLayout != null) {
149            unregisterReceiver(mPackageReceiver);
150        }
151
152        super.onPause();
153    }
154
155    public void addCategoryListener(CategoryListener listener) {
156        mCategoryListeners.add(listener);
157    }
158
159    public void remCategoryListener(CategoryListener listener) {
160        mCategoryListeners.remove(listener);
161    }
162
163    public void setIsDrawerPresent(boolean isPresent) {
164        if (isPresent) {
165            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
166            updateDrawer();
167        } else {
168            if (mDrawerLayout != null) {
169                mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
170                mDrawerLayout = null;
171            }
172        }
173    }
174
175    public void openDrawer() {
176        if (mDrawerLayout != null) {
177            mDrawerLayout.openDrawer(Gravity.START);
178        }
179    }
180
181    public void closeDrawer() {
182        if (mDrawerLayout != null) {
183            mDrawerLayout.closeDrawers();
184        }
185    }
186
187    public void setContentHeaderView(View headerView) {
188        mContentHeaderContainer.removeAllViews();
189        if (headerView != null) {
190            mContentHeaderContainer.addView(headerView);
191        }
192    }
193
194    @Override
195    public void setContentView(@LayoutRes int layoutResID) {
196        final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
197        if (parent != null) {
198            parent.removeAllViews();
199        }
200        LayoutInflater.from(this).inflate(layoutResID, parent);
201    }
202
203    @Override
204    public void setContentView(View view) {
205        ((ViewGroup) findViewById(R.id.content_frame)).addView(view);
206    }
207
208    @Override
209    public void setContentView(View view, ViewGroup.LayoutParams params) {
210        ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
211    }
212
213    public void updateDrawer() {
214        if (mDrawerLayout == null) {
215            return;
216        }
217        // TODO: Do this in the background with some loading.
218        mDrawerAdapter.updateCategories();
219        if (mDrawerAdapter.getCount() != 0) {
220            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
221        } else {
222            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
223        }
224    }
225
226    public void showMenuIcon() {
227        mShowingMenu = true;
228        getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
229        getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
230        getActionBar().setDisplayHomeAsUpEnabled(true);
231    }
232
233    public List<DashboardCategory> getDashboardCategories() {
234        if (sDashboardCategories == null) {
235            sTileCache = new HashMap<>();
236            sConfigTracker = new InterestingConfigChanges();
237            // Apply initial current config.
238            sConfigTracker.applyNewConfig(getResources());
239            sDashboardCategories = TileUtils.getCategories(this, sTileCache);
240        }
241        return sDashboardCategories;
242    }
243
244    protected void onCategoriesChanged() {
245        updateDrawer();
246        final int N = mCategoryListeners.size();
247        for (int i = 0; i < N; i++) {
248            mCategoryListeners.get(i).onCategoriesChanged();
249        }
250    }
251
252    public boolean openTile(Tile tile) {
253        closeDrawer();
254        if (tile == null) {
255            startActivity(new Intent(Settings.ACTION_SETTINGS).addFlags(
256                    Intent.FLAG_ACTIVITY_CLEAR_TASK));
257            return true;
258        }
259        try {
260            int numUserHandles = tile.userHandle.size();
261            if (numUserHandles > 1) {
262                ProfileSelectDialog.show(getFragmentManager(), tile);
263                return false;
264            } else if (numUserHandles == 1) {
265                // Show menu on top level items.
266                tile.intent.putExtra(EXTRA_SHOW_MENU, true);
267                tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
268                startActivityAsUser(tile.intent, tile.userHandle.get(0));
269            } else {
270                // Show menu on top level items.
271                tile.intent.putExtra(EXTRA_SHOW_MENU, true);
272                tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
273                startActivity(tile.intent);
274            }
275        } catch (ActivityNotFoundException e) {
276            Log.w(TAG, "Couldn't find tile " + tile.intent, e);
277        }
278        return true;
279    }
280
281    protected void onTileClicked(Tile tile) {
282        if (openTile(tile)) {
283            finish();
284        }
285    }
286
287    public HashMap<Pair<String, String>, Tile> getTileCache() {
288        if (sTileCache == null) {
289            getDashboardCategories();
290        }
291        return sTileCache;
292    }
293
294    public void onProfileTileOpen() {
295        finish();
296    }
297
298    public void setTileEnabled(ComponentName component, boolean enabled) {
299        PackageManager pm = getPackageManager();
300        int state = pm.getComponentEnabledSetting(component);
301        boolean isEnabled = state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
302        if (isEnabled != enabled || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
303            if (enabled) {
304                sTileBlacklist.remove(component);
305            } else {
306                sTileBlacklist.add(component);
307            }
308            pm.setComponentEnabledSetting(component, enabled
309                    ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
310                    : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
311                    PackageManager.DONT_KILL_APP);
312            new CategoriesUpdater().execute();
313        }
314    }
315
316    public interface CategoryListener {
317        void onCategoriesChanged();
318    }
319
320    private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
321        @Override
322        protected List<DashboardCategory> doInBackground(Void... params) {
323            if (sConfigTracker.applyNewConfig(getResources())) {
324                sTileCache.clear();
325            }
326            return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
327        }
328
329        @Override
330        protected void onPreExecute() {
331            if (sConfigTracker == null || sTileCache == null) {
332                getDashboardCategories();
333            }
334        }
335
336        @Override
337        protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
338            for (int i = 0; i < dashboardCategories.size(); i++) {
339                DashboardCategory category = dashboardCategories.get(i);
340                for (int j = 0; j < category.tiles.size(); j++) {
341                    Tile tile = category.tiles.get(j);
342                    if (sTileBlacklist.contains(tile.intent.getComponent())) {
343                        category.tiles.remove(j--);
344                    }
345                }
346            }
347            sDashboardCategories = dashboardCategories;
348            onCategoriesChanged();
349        }
350    }
351
352    private class PackageReceiver extends BroadcastReceiver {
353        @Override
354        public void onReceive(Context context, Intent intent) {
355            new CategoriesUpdater().execute();
356        }
357    }
358}
359