/**
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settingslib.drawer;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.Toolbar;
import com.android.settingslib.R;
import com.android.settingslib.applications.InterestingConfigChanges;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class SettingsDrawerActivity extends Activity {
protected static final boolean DEBUG_TIMING = false;
private static final String TAG = "SettingsDrawerActivity";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
private static List<DashboardCategory> sDashboardCategories;
private static HashMap<Pair<String, String>, Tile> sTileCache;
// Serves as a temporary list of tiles to ignore until we heard back from the PM that they
// are disabled.
private static ArraySet<ComponentName> sTileBlacklist = new ArraySet<>();
private static InterestingConfigChanges sConfigTracker;
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
private SettingsDrawerAdapter mDrawerAdapter;
private FrameLayout mContentHeaderContainer;
private DrawerLayout mDrawerLayout;
private boolean mShowingMenu;
private UserManager mUserManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
long startTime = System.currentTimeMillis();
TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
super.setContentView(R.layout.settings_with_drawer);
mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
if (mDrawerLayout == null) {
return;
}
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
toolbar.setVisibility(View.GONE);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerLayout = null;
return;
}
getDashboardCategories();
setActionBar(toolbar);
mDrawerAdapter = new SettingsDrawerAdapter(this);
ListView listView = (ListView) findViewById(R.id.left_drawer);
listView.setAdapter(mDrawerAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
long id) {
onTileClicked(mDrawerAdapter.getTile(position));
}
});
mUserManager = UserManager.get(this);
if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
+ " ms");
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
&& mDrawerAdapter.getCount() != 0) {
openDrawer();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
if (mDrawerLayout != null) {
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addDataScheme("package");
registerReceiver(mPackageReceiver, filter);
new CategoriesUpdater().execute();
}
final Intent intent = getIntent();
if (intent != null) {
if (intent.hasExtra(EXTRA_SHOW_MENU)) {
if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
// Intent explicitly set to show menu.
showMenuIcon();
}
} else if (isTopLevelTile(intent)) {
showMenuIcon();
}
}
}
@Override
protected void onPause() {
if (mDrawerLayout != null) {
unregisterReceiver(mPackageReceiver);
}
super.onPause();
}
private boolean isTopLevelTile(Intent intent) {
final ComponentName componentName = intent.getComponent();
if (componentName == null) {
return false;
}
// Look for a tile that has the same component as incoming intent
final List<DashboardCategory> categories = getDashboardCategories();
for (DashboardCategory category : categories) {
for (Tile tile : category.tiles) {
if (TextUtils.equals(tile.intent.getComponent().getClassName(),
componentName.getClassName())) {
if (DEBUG) {
Log.d(TAG, "intent is for top level tile: " + tile.title);
}
return true;
}
}
}
if (DEBUG) {
Log.d(TAG, "Intent is not for top level settings " + intent);
}
return false;
}
public void addCategoryListener(CategoryListener listener) {
mCategoryListeners.add(listener);
}
public void remCategoryListener(CategoryListener listener) {
mCategoryListeners.remove(listener);
}
public void setIsDrawerPresent(boolean isPresent) {
if (isPresent) {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
updateDrawer();
} else {
if (mDrawerLayout != null) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerLayout = null;
}
}
}
public void openDrawer() {
if (mDrawerLayout != null) {
mDrawerLayout.openDrawer(Gravity.START);
}
}
public void closeDrawer() {
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawers();
}
}
public void setContentHeaderView(View headerView) {
mContentHeaderContainer.removeAllViews();
if (headerView != null) {
mContentHeaderContainer.addView(headerView);
}
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
if (parent != null) {
parent.removeAllViews();
}
LayoutInflater.from(this).inflate(layoutResID, parent);
}
@Override
public void setContentView(View view) {
((ViewGroup) findViewById(R.id.content_frame)).addView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
public void updateDrawer() {
if (mDrawerLayout == null) {
return;
}
// TODO: Do this in the background with some loading.
mDrawerAdapter.updateCategories();
if (mDrawerAdapter.getCount() != 0) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
}
public void showMenuIcon() {
mShowingMenu = true;
getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
public List<DashboardCategory> getDashboardCategories() {
if (sDashboardCategories == null) {
sTileCache = new HashMap<>();
sConfigTracker = new InterestingConfigChanges();
// Apply initial current config.
sConfigTracker.applyNewConfig(getResources());
sDashboardCategories = TileUtils.getCategories(this, sTileCache);
}
return sDashboardCategories;
}
protected void onCategoriesChanged() {
updateDrawer();
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
mCategoryListeners.get(i).onCategoriesChanged();
}
}
public boolean openTile(Tile tile) {
closeDrawer();
if (tile == null) {
startActivity(new Intent(Settings.ACTION_SETTINGS).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TASK));
return true;
}
try {
updateUserHandlesIfNeeded(tile);
int numUserHandles = tile.userHandle.size();
if (numUserHandles > 1) {
ProfileSelectDialog.show(getFragmentManager(), tile);
return false;
} else if (numUserHandles == 1) {
// Show menu on top level items.
tile.intent.putExtra(EXTRA_SHOW_MENU, true);
tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivityAsUser(tile.intent, tile.userHandle.get(0));
} else {
// Show menu on top level items.
tile.intent.putExtra(EXTRA_SHOW_MENU, true);
tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(tile.intent);
}
} catch (ActivityNotFoundException e) {
Log.w(TAG, "Couldn't find tile " + tile.intent, e);
}
return true;
}
private void updateUserHandlesIfNeeded(Tile tile) {
List<UserHandle> userHandles = tile.userHandle;
for (int i = userHandles.size() - 1; i >= 0; i--) {
if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) {
if (DEBUG) {
Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
}
userHandles.remove(i);
}
}
}
protected void onTileClicked(Tile tile) {
if (openTile(tile)) {
finish();
}
}
public HashMap<Pair<String, String>, Tile> getTileCache() {
if (sTileCache == null) {
getDashboardCategories();
}
return sTileCache;
}
public void onProfileTileOpen() {
finish();
}
public void setTileEnabled(ComponentName component, boolean enabled) {
PackageManager pm = getPackageManager();
int state = pm.getComponentEnabledSetting(component);
boolean isEnabled = state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
if (isEnabled != enabled || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
if (enabled) {
sTileBlacklist.remove(component);
} else {
sTileBlacklist.add(component);
}
pm.setComponentEnabledSetting(component, enabled
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
new CategoriesUpdater().execute();
}
}
public interface CategoryListener {
void onCategoriesChanged();
}
private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
@Override
protected List<DashboardCategory> doInBackground(Void... params) {
if (sConfigTracker.applyNewConfig(getResources())) {
sTileCache.clear();
}
return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
}
@Override
protected void onPreExecute() {
if (sConfigTracker == null || sTileCache == null) {
getDashboardCategories();
}
}
@Override
protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
for (int i = 0; i < dashboardCategories.size(); i++) {
DashboardCategory category = dashboardCategories.get(i);
for (int j = 0; j < category.tiles.size(); j++) {
Tile tile = category.tiles.get(j);
if (sTileBlacklist.contains(tile.intent.getComponent())) {
category.tiles.remove(j--);
}
}
}
sDashboardCategories = dashboardCategories;
onCategoriesChanged();
}
}
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
new CategoriesUpdater().execute();
}
}
}