blob: 83ac45c5c8c69af3bc1692eb9961879cc79f1335 [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 Monka8321e62016-03-11 08:56:25 -050028import android.view.LayoutInflater;
Jason Monkb53b6c52016-02-24 17:25:49 -050029import android.view.Menu;
30import android.view.MenuItem;
Jason Monk5db8a412015-10-21 15:16:23 -070031import android.view.View;
Jason Monkbd6dbb02015-09-03 15:46:25 -040032import android.widget.LinearLayout;
Jason Monkb53b6c52016-02-24 17:25:49 -050033import android.widget.Toolbar;
34import android.widget.Toolbar.OnMenuItemClickListener;
Jason Monk96defbe2016-03-29 16:51:03 -040035import com.android.internal.logging.MetricsLogger;
36import com.android.internal.logging.MetricsProto;
Jason Monkbd6dbb02015-09-03 15:46:25 -040037import com.android.systemui.R;
Jason Monk8b9d67f2016-03-02 08:59:08 -050038import com.android.systemui.qs.QSContainer;
Jason Monkb9c00192015-10-07 11:45:33 -040039import com.android.systemui.qs.QSDetailClipper;
Jason Monk62b63a02016-02-02 15:15:31 -050040import com.android.systemui.qs.QSTile;
Jason Monk8b9d67f2016-03-02 08:59:08 -050041import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
Jason Monkbd6dbb02015-09-03 15:46:25 -040042import com.android.systemui.statusbar.phone.PhoneStatusBar;
43import com.android.systemui.statusbar.phone.QSTileHost;
Jason Monkbd6dbb02015-09-03 15:46:25 -040044
45import java.util.ArrayList;
Jason Monk62b63a02016-02-02 15:15:31 -050046import java.util.List;
Jason Monkbd6dbb02015-09-03 15:46:25 -040047
48/**
49 * Allows full-screen customization of QS, through show() and hide().
50 *
51 * This adds itself to the status bar window, so it can appear on top of quick settings and
52 * *someday* do fancy animations to get into/out of it.
53 */
Jason Monkb53b6c52016-02-24 17:25:49 -050054public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
55
56 private static final int MENU_RESET = Menu.FIRST;
Jason Monkbd6dbb02015-09-03 15:46:25 -040057
Jason Monkb9c00192015-10-07 11:45:33 -040058 private final QSDetailClipper mClipper;
Jason Monkbd6dbb02015-09-03 15:46:25 -040059
60 private PhoneStatusBar mPhoneStatusBar;
61
Jason Monkbd6dbb02015-09-03 15:46:25 -040062 private boolean isShown;
Jason Monkbbadff82015-11-06 15:47:26 -050063 private QSTileHost mHost;
Jason Monk62b63a02016-02-02 15:15:31 -050064 private RecyclerView mRecyclerView;
65 private TileAdapter mTileAdapter;
Jason Monkb53b6c52016-02-24 17:25:49 -050066 private Toolbar mToolbar;
Jason Monk8b9d67f2016-03-02 08:59:08 -050067 private boolean mCustomizing;
68 private NotificationsQuickSettingsContainer mNotifQsContainer;
69 private QSContainer mQsContainer;
Jason Monkbd6dbb02015-09-03 15:46:25 -040070
71 public QSCustomizer(Context context, AttributeSet attrs) {
Jason Monka8321e62016-03-11 08:56:25 -050072 super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
Jason Monkb9c00192015-10-07 11:45:33 -040073 mClipper = new QSDetailClipper(this);
Jason Monkbd6dbb02015-09-03 15:46:25 -040074
Jason Monka8321e62016-03-11 08:56:25 -050075 LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
Jason Monkbd6dbb02015-09-03 15:46:25 -040076
Jason Monkb53b6c52016-02-24 17:25:49 -050077 mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
78 TypedValue value = new TypedValue();
79 mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
80 mToolbar.setNavigationIcon(
Jason Monk04fd2492016-02-29 14:29:26 -050081 getResources().getDrawable(value.resourceId, mContext.getTheme()));
Jason Monkb53b6c52016-02-24 17:25:49 -050082 mToolbar.setNavigationOnClickListener(new OnClickListener() {
83 @Override
84 public void onClick(View v) {
Jason Monkb53b6c52016-02-24 17:25:49 -050085 hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
86 }
87 });
88 mToolbar.setOnMenuItemClickListener(this);
89 mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
90 mContext.getString(com.android.internal.R.string.reset));
Jason Monkf923db52016-03-02 14:11:14 -050091 mToolbar.setTitle(R.string.qs_edit);
Jason Monkbd6dbb02015-09-03 15:46:25 -040092
Jason Monk62b63a02016-02-02 15:15:31 -050093 mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
94 mTileAdapter = new TileAdapter(getContext());
95 mRecyclerView.setAdapter(mTileAdapter);
Jason Monkb53b6c52016-02-24 17:25:49 -050096 mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
Jason Monk62b63a02016-02-02 15:15:31 -050097 GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
98 layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
99 mRecyclerView.setLayoutManager(layout);
100 mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
101 DefaultItemAnimator animator = new DefaultItemAnimator();
102 animator.setMoveDuration(TileAdapter.MOVE_DURATION);
103 mRecyclerView.setItemAnimator(animator);
Jason Monkbd6dbb02015-09-03 15:46:25 -0400104 }
105
Jason Monka8321e62016-03-11 08:56:25 -0500106 public void setHost(QSTileHost host) {
107 mHost = host;
108 mPhoneStatusBar = host.getPhoneStatusBar();
109 }
110
111 public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
112 mNotifQsContainer = notificationsQsContainer;
113 }
114
115 public void setQsContainer(QSContainer qsContainer) {
116 mQsContainer = qsContainer;
117 }
118
Jason Monkb9c00192015-10-07 11:45:33 -0400119 public void show(int x, int y) {
Jason Monk8c7e47f2016-02-17 10:39:31 -0500120 if (!isShown) {
Jason Monk96defbe2016-03-29 16:51:03 -0400121 MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500122 isShown = true;
Jason Monk8c7e47f2016-02-17 10:39:31 -0500123 setTileSpecs();
Jason Monk8b9d67f2016-03-02 08:59:08 -0500124 setVisibility(View.VISIBLE);
125 mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500126 new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
Jason Monk8b9d67f2016-03-02 08:59:08 -0500127 mNotifQsContainer.setCustomizerAnimating(true);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500128 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400129 }
130
Jason Monkb9c00192015-10-07 11:45:33 -0400131 public void hide(int x, int y) {
Jason Monk8c7e47f2016-02-17 10:39:31 -0500132 if (isShown) {
Jason Monk96defbe2016-03-29 16:51:03 -0400133 MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500134 isShown = false;
Jason Monkdf8cbc32016-03-16 16:10:56 -0400135 mToolbar.dismissPopupMenus();
Jason Monk8b9d67f2016-03-02 08:59:08 -0500136 setCustomizing(false);
Jason Monk04fd2492016-02-29 14:29:26 -0500137 save();
Jason Monk77a2c5f2016-02-22 15:18:36 -0500138 mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
Jason Monk8b9d67f2016-03-02 08:59:08 -0500139 mNotifQsContainer.setCustomizerAnimating(true);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500140 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400141 }
142
Jason Monk8b9d67f2016-03-02 08:59:08 -0500143 private void setCustomizing(boolean customizing) {
144 mCustomizing = customizing;
145 mQsContainer.notifyCustomizeChanged();
146 }
147
Jason Monkbd6dbb02015-09-03 15:46:25 -0400148 public boolean isCustomizing() {
Jason Monk8b9d67f2016-03-02 08:59:08 -0500149 return mCustomizing;
Jason Monkbd6dbb02015-09-03 15:46:25 -0400150 }
151
Jason Monkb53b6c52016-02-24 17:25:49 -0500152 @Override
153 public boolean onMenuItemClick(MenuItem item) {
154 switch (item.getItemId()) {
155 case MENU_RESET:
Jason Monk96defbe2016-03-29 16:51:03 -0400156 MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_QS_EDIT_RESET);
Jason Monkb53b6c52016-02-24 17:25:49 -0500157 reset();
158 break;
159 }
160 return false;
161 }
162
Jason Monkbd6dbb02015-09-03 15:46:25 -0400163 private void reset() {
164 ArrayList<String> tiles = new ArrayList<>();
Jason Monk9d02a432016-01-20 16:33:46 -0500165 String defTiles = mContext.getString(R.string.quick_settings_tiles_default);
166 for (String tile : defTiles.split(",")) {
Jason Monkbd6dbb02015-09-03 15:46:25 -0400167 tiles.add(tile);
168 }
Jason Monk62b63a02016-02-02 15:15:31 -0500169 mTileAdapter.setTileSpecs(tiles);
Jason Monkbd6dbb02015-09-03 15:46:25 -0400170 }
171
Jason Monk62b63a02016-02-02 15:15:31 -0500172 private void setTileSpecs() {
173 List<String> specs = new ArrayList<>();
174 for (QSTile tile : mHost.getTiles()) {
175 specs.add(tile.getTileSpec());
176 }
177 mTileAdapter.setTileSpecs(specs);
Jason Monkf7fe83f2015-09-09 13:03:20 -0400178 }
179
Jason Monkbd6dbb02015-09-03 15:46:25 -0400180 private void save() {
Jason Monk62b63a02016-02-02 15:15:31 -0500181 mTileAdapter.saveSpecs(mHost);
Jason Monk2681dcb2015-09-09 13:50:34 -0400182 }
Jason Monkb9c00192015-10-07 11:45:33 -0400183
Jason Monk8b9d67f2016-03-02 08:59:08 -0500184 private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
185 @Override
186 public void onAnimationEnd(Animator animation) {
187 setCustomizing(true);
188 mNotifQsContainer.setCustomizerAnimating(false);
189 }
190
191 @Override
192 public void onAnimationCancel(Animator animation) {
193 mNotifQsContainer.setCustomizerAnimating(false);
194 }
195 };
196
Jason Monk77a2c5f2016-02-22 15:18:36 -0500197 private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
198 @Override
199 public void onAnimationEnd(Animator animation) {
200 if (!isShown) {
Jason Monk8b9d67f2016-03-02 08:59:08 -0500201 setVisibility(View.GONE);
Jason Monk77a2c5f2016-02-22 15:18:36 -0500202 }
Jason Monk8b9d67f2016-03-02 08:59:08 -0500203 mNotifQsContainer.setCustomizerAnimating(false);
Jason Monkb9c00192015-10-07 11:45:33 -0400204 }
Jason Monkb9c00192015-10-07 11:45:33 -0400205
Jason Monk77a2c5f2016-02-22 15:18:36 -0500206 @Override
207 public void onAnimationCancel(Animator animation) {
208 if (!isShown) {
Jason Monk8b9d67f2016-03-02 08:59:08 -0500209 setVisibility(View.GONE);
Jason Monk77a2c5f2016-02-22 15:18:36 -0500210 }
Jason Monk8b9d67f2016-03-02 08:59:08 -0500211 mNotifQsContainer.setCustomizerAnimating(false);
Jason Monkb9c00192015-10-07 11:45:33 -0400212 }
Jason Monk77a2c5f2016-02-22 15:18:36 -0500213 };
Jason Monk62b63a02016-02-02 15:15:31 -0500214}