blob: 225c10fc49e43cf6adde59602b830af7c9605b05 [file] [log] [blame]
Jason Monkbd6dbb02015-09-03 15:46:25 -04001/*
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.systemui.qs.customize;
17
Jason Monkb9c00192015-10-07 11:45:33 -040018import android.animation.Animator;
Jason Monk62b63a02016-02-02 15:15:31 -050019import android.animation.Animator.AnimatorListener;
Jason Monk77a2c5f2016-02-22 15:18:36 -050020import android.animation.AnimatorListenerAdapter;
Jason Monkbd6dbb02015-09-03 15:46:25 -040021import android.content.Context;
Jason Monk62b63a02016-02-02 15:15:31 -050022import android.support.v7.widget.DefaultItemAnimator;
23import android.support.v7.widget.GridLayoutManager;
24import android.support.v7.widget.RecyclerView;
Jason Monkbd6dbb02015-09-03 15:46:25 -040025import android.util.AttributeSet;
Jason Monkb53b6c52016-02-24 17:25:49 -050026import android.util.TypedValue;
Jason Monk5db8a412015-10-21 15:16:23 -070027import android.view.ContextThemeWrapper;
Jason Monkb53b6c52016-02-24 17:25:49 -050028import android.view.Menu;
29import android.view.MenuItem;
Jason Monk5db8a412015-10-21 15:16:23 -070030import android.view.View;
Jason Monkbd6dbb02015-09-03 15:46:25 -040031import android.widget.LinearLayout;
Jason Monkb53b6c52016-02-24 17:25:49 -050032import android.widget.Toolbar;
33import android.widget.Toolbar.OnMenuItemClickListener;
Jason Monkbd6dbb02015-09-03 15:46:25 -040034import com.android.systemui.R;
Jason Monkb9c00192015-10-07 11:45:33 -040035import com.android.systemui.qs.QSDetailClipper;
Jason Monk62b63a02016-02-02 15:15:31 -050036import com.android.systemui.qs.QSTile;
Jason Monkbd6dbb02015-09-03 15:46:25 -040037import com.android.systemui.statusbar.phone.PhoneStatusBar;
38import com.android.systemui.statusbar.phone.QSTileHost;
Jason Monkbd6dbb02015-09-03 15:46:25 -040039
40import java.util.ArrayList;
Jason Monk62b63a02016-02-02 15:15:31 -050041import java.util.List;
Jason Monkbd6dbb02015-09-03 15:46:25 -040042
43/**
44 * Allows full-screen customization of QS, through show() and hide().
45 *
46 * This adds itself to the status bar window, so it can appear on top of quick settings and
47 * *someday* do fancy animations to get into/out of it.
48 */
Jason Monkb53b6c52016-02-24 17:25:49 -050049public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
50
51 private static final int MENU_RESET = Menu.FIRST;
Jason Monkbd6dbb02015-09-03 15:46:25 -040052
Jason Monkb9c00192015-10-07 11:45:33 -040053 private final QSDetailClipper mClipper;
Jason Monkbd6dbb02015-09-03 15:46:25 -040054
55 private PhoneStatusBar mPhoneStatusBar;
56
Jason Monkbd6dbb02015-09-03 15:46:25 -040057 private boolean isShown;
Jason Monkbbadff82015-11-06 15:47:26 -050058 private QSTileHost mHost;
Jason Monk62b63a02016-02-02 15:15:31 -050059 private RecyclerView mRecyclerView;
60 private TileAdapter mTileAdapter;
Jason Monkb53b6c52016-02-24 17:25:49 -050061 private Toolbar mToolbar;
Jason Monkbd6dbb02015-09-03 15:46:25 -040062
63 public QSCustomizer(Context context, AttributeSet attrs) {
64 super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
Jason Monkb9c00192015-10-07 11:45:33 -040065 mClipper = new QSDetailClipper(this);
Jason Monkbd6dbb02015-09-03 15:46:25 -040066 }
67
68 public void setHost(QSTileHost host) {
Jason Monkbbadff82015-11-06 15:47:26 -050069 mHost = host;
Jason Monkdeba7a42015-12-08 16:14:10 -050070 mPhoneStatusBar = host.getPhoneStatusBar();
Jason Monkbd6dbb02015-09-03 15:46:25 -040071 }
72
73 @Override
74 protected void onFinishInflate() {
75 super.onFinishInflate();
Jason Monkb53b6c52016-02-24 17:25:49 -050076 mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
77 TypedValue value = new TypedValue();
78 mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
79 mToolbar.setNavigationIcon(
Jason Monk04fd2492016-02-29 14:29:26 -050080 getResources().getDrawable(value.resourceId, mContext.getTheme()));
Jason Monkb53b6c52016-02-24 17:25:49 -050081 mToolbar.setNavigationOnClickListener(new OnClickListener() {
82 @Override
83 public void onClick(View v) {
Jason Monkb53b6c52016-02-24 17:25:49 -050084 hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
85 }
86 });
87 mToolbar.setOnMenuItemClickListener(this);
88 mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
89 mContext.getString(com.android.internal.R.string.reset));
Jason Monkbd6dbb02015-09-03 15:46:25 -040090
Jason Monk62b63a02016-02-02 15:15:31 -050091 mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
92 mTileAdapter = new TileAdapter(getContext());
93 mRecyclerView.setAdapter(mTileAdapter);
Jason Monkb53b6c52016-02-24 17:25:49 -050094 mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
Jason Monk62b63a02016-02-02 15:15:31 -050095 GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
96 layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
97 mRecyclerView.setLayoutManager(layout);
98 mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
99 DefaultItemAnimator animator = new DefaultItemAnimator();
100 animator.setMoveDuration(TileAdapter.MOVE_DURATION);
101 mRecyclerView.setItemAnimator(animator);
Jason Monkbd6dbb02015-09-03 15:46:25 -0400102 }
103
Jason Monkb9c00192015-10-07 11:45:33 -0400104 public void show(int x, int y) {
Jason Monk8c7e47f2016-02-17 10:39:31 -0500105 if (!isShown) {
106 isShown = true;
107 mPhoneStatusBar.getStatusBarWindow().addView(this);
108 setTileSpecs();
Jason Monk77a2c5f2016-02-22 15:18:36 -0500109 mClipper.animateCircularClip(x, y, true, null);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500110 new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
111 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400112 }
113
Jason Monkb9c00192015-10-07 11:45:33 -0400114 public void hide(int x, int y) {
Jason Monk8c7e47f2016-02-17 10:39:31 -0500115 if (isShown) {
116 isShown = false;
Jason Monk04fd2492016-02-29 14:29:26 -0500117 save();
Jason Monk77a2c5f2016-02-22 15:18:36 -0500118 mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500119 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400120 }
121
122 public boolean isCustomizing() {
123 return isShown;
124 }
125
Jason Monkb53b6c52016-02-24 17:25:49 -0500126 @Override
127 public boolean onMenuItemClick(MenuItem item) {
128 switch (item.getItemId()) {
129 case MENU_RESET:
130 reset();
131 break;
132 }
133 return false;
134 }
135
Jason Monkbd6dbb02015-09-03 15:46:25 -0400136 private void reset() {
137 ArrayList<String> tiles = new ArrayList<>();
Jason Monk9d02a432016-01-20 16:33:46 -0500138 String defTiles = mContext.getString(R.string.quick_settings_tiles_default);
139 for (String tile : defTiles.split(",")) {
Jason Monkbd6dbb02015-09-03 15:46:25 -0400140 tiles.add(tile);
141 }
Jason Monk62b63a02016-02-02 15:15:31 -0500142 mTileAdapter.setTileSpecs(tiles);
Jason Monkbd6dbb02015-09-03 15:46:25 -0400143 }
144
Jason Monk62b63a02016-02-02 15:15:31 -0500145 private void setTileSpecs() {
146 List<String> specs = new ArrayList<>();
147 for (QSTile tile : mHost.getTiles()) {
148 specs.add(tile.getTileSpec());
149 }
150 mTileAdapter.setTileSpecs(specs);
Jason Monkf7fe83f2015-09-09 13:03:20 -0400151 }
152
Jason Monkbd6dbb02015-09-03 15:46:25 -0400153 private void save() {
Jason Monk62b63a02016-02-02 15:15:31 -0500154 mTileAdapter.saveSpecs(mHost);
Jason Monk2681dcb2015-09-09 13:50:34 -0400155 }
Jason Monkb9c00192015-10-07 11:45:33 -0400156
Jason Monk77a2c5f2016-02-22 15:18:36 -0500157 private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
158 @Override
159 public void onAnimationEnd(Animator animation) {
160 if (!isShown) {
161 mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
162 }
Jason Monkb9c00192015-10-07 11:45:33 -0400163 }
Jason Monkb9c00192015-10-07 11:45:33 -0400164
Jason Monk77a2c5f2016-02-22 15:18:36 -0500165 @Override
166 public void onAnimationCancel(Animator animation) {
167 if (!isShown) {
168 mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
169 }
Jason Monkb9c00192015-10-07 11:45:33 -0400170 }
Jason Monk77a2c5f2016-02-22 15:18:36 -0500171 };
Jason Monk62b63a02016-02-02 15:15:31 -0500172}