blob: 716185f343b52b475dcad9c9acbc0dc5b4aa90a3 [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 Monk428914d2016-03-30 09:35:36 -0400128 mNotifQsContainer.setCustomizerShowing(true);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500129 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400130 }
131
Jason Monkb9c00192015-10-07 11:45:33 -0400132 public void hide(int x, int y) {
Jason Monk8c7e47f2016-02-17 10:39:31 -0500133 if (isShown) {
Jason Monk96defbe2016-03-29 16:51:03 -0400134 MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500135 isShown = false;
Jason Monkdf8cbc32016-03-16 16:10:56 -0400136 mToolbar.dismissPopupMenus();
Jason Monk8b9d67f2016-03-02 08:59:08 -0500137 setCustomizing(false);
Jason Monk04fd2492016-02-29 14:29:26 -0500138 save();
Jason Monk77a2c5f2016-02-22 15:18:36 -0500139 mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
Jason Monk8b9d67f2016-03-02 08:59:08 -0500140 mNotifQsContainer.setCustomizerAnimating(true);
Jason Monk428914d2016-03-30 09:35:36 -0400141 mNotifQsContainer.setCustomizerShowing(false);
Jason Monk8c7e47f2016-02-17 10:39:31 -0500142 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400143 }
144
Jason Monk8b9d67f2016-03-02 08:59:08 -0500145 private void setCustomizing(boolean customizing) {
146 mCustomizing = customizing;
147 mQsContainer.notifyCustomizeChanged();
148 }
149
Jason Monkbd6dbb02015-09-03 15:46:25 -0400150 public boolean isCustomizing() {
Jason Monk8b9d67f2016-03-02 08:59:08 -0500151 return mCustomizing;
Jason Monkbd6dbb02015-09-03 15:46:25 -0400152 }
153
Jason Monkb53b6c52016-02-24 17:25:49 -0500154 @Override
155 public boolean onMenuItemClick(MenuItem item) {
156 switch (item.getItemId()) {
157 case MENU_RESET:
Jason Monk96defbe2016-03-29 16:51:03 -0400158 MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_QS_EDIT_RESET);
Jason Monkb53b6c52016-02-24 17:25:49 -0500159 reset();
160 break;
161 }
162 return false;
163 }
164
Jason Monkbd6dbb02015-09-03 15:46:25 -0400165 private void reset() {
166 ArrayList<String> tiles = new ArrayList<>();
Jason Monk9d02a432016-01-20 16:33:46 -0500167 String defTiles = mContext.getString(R.string.quick_settings_tiles_default);
168 for (String tile : defTiles.split(",")) {
Jason Monkbd6dbb02015-09-03 15:46:25 -0400169 tiles.add(tile);
170 }
Jason Monk62b63a02016-02-02 15:15:31 -0500171 mTileAdapter.setTileSpecs(tiles);
Jason Monkbd6dbb02015-09-03 15:46:25 -0400172 }
173
Jason Monk62b63a02016-02-02 15:15:31 -0500174 private void setTileSpecs() {
175 List<String> specs = new ArrayList<>();
176 for (QSTile tile : mHost.getTiles()) {
177 specs.add(tile.getTileSpec());
178 }
179 mTileAdapter.setTileSpecs(specs);
Jason Monk4efc9242016-03-31 14:10:37 -0400180 mRecyclerView.setAdapter(mTileAdapter);
Jason Monkf7fe83f2015-09-09 13:03:20 -0400181 }
182
Jason Monkbd6dbb02015-09-03 15:46:25 -0400183 private void save() {
Jason Monk62b63a02016-02-02 15:15:31 -0500184 mTileAdapter.saveSpecs(mHost);
Jason Monk2681dcb2015-09-09 13:50:34 -0400185 }
Jason Monkb9c00192015-10-07 11:45:33 -0400186
Jason Monk8b9d67f2016-03-02 08:59:08 -0500187 private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
188 @Override
189 public void onAnimationEnd(Animator animation) {
190 setCustomizing(true);
191 mNotifQsContainer.setCustomizerAnimating(false);
192 }
193
194 @Override
195 public void onAnimationCancel(Animator animation) {
196 mNotifQsContainer.setCustomizerAnimating(false);
197 }
198 };
199
Jason Monk77a2c5f2016-02-22 15:18:36 -0500200 private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
201 @Override
202 public void onAnimationEnd(Animator animation) {
203 if (!isShown) {
Jason Monk8b9d67f2016-03-02 08:59:08 -0500204 setVisibility(View.GONE);
Jason Monk77a2c5f2016-02-22 15:18:36 -0500205 }
Jason Monk8b9d67f2016-03-02 08:59:08 -0500206 mNotifQsContainer.setCustomizerAnimating(false);
Jason Monkb9c00192015-10-07 11:45:33 -0400207 }
Jason Monkb9c00192015-10-07 11:45:33 -0400208
Jason Monk77a2c5f2016-02-22 15:18:36 -0500209 @Override
210 public void onAnimationCancel(Animator animation) {
211 if (!isShown) {
Jason Monk8b9d67f2016-03-02 08:59:08 -0500212 setVisibility(View.GONE);
Jason Monk77a2c5f2016-02-22 15:18:36 -0500213 }
Jason Monk8b9d67f2016-03-02 08:59:08 -0500214 mNotifQsContainer.setCustomizerAnimating(false);
Jason Monkb9c00192015-10-07 11:45:33 -0400215 }
Jason Monk77a2c5f2016-02-22 15:18:36 -0500216 };
Jason Monk62b63a02016-02-02 15:15:31 -0500217}