QSCustomizer.java revision deba7a42ed9fdde9017f2b627fc5f63a31a82c4b
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.systemui.qs.customize;
17
18import android.animation.Animator;
19import android.content.ClipData;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.DialogInterface.OnCancelListener;
23import android.content.DialogInterface.OnDismissListener;
24import android.util.AttributeSet;
25import android.util.Log;
26import android.util.TypedValue;
27import android.view.ContextThemeWrapper;
28import android.view.DragEvent;
29import android.view.LayoutInflater;
30import android.view.Menu;
31import android.view.MenuItem;
32import android.view.View;
33import android.view.View.OnClickListener;
34import android.view.ViewGroup;
35import android.view.WindowManager;
36import android.widget.LinearLayout;
37import android.widget.ListView;
38import android.widget.Toolbar;
39import android.widget.Toolbar.OnMenuItemClickListener;
40import com.android.systemui.R;
41import com.android.systemui.qs.QSDetailClipper;
42import com.android.systemui.qs.QSTile.Host.Callback;
43import com.android.systemui.qs.customize.DropButton.OnDropListener;
44import com.android.systemui.qs.customize.TileAdapter.TileSelectedListener;
45import com.android.systemui.statusbar.phone.PhoneStatusBar;
46import com.android.systemui.statusbar.phone.QSTileHost;
47import com.android.systemui.statusbar.phone.SystemUIDialog;
48import com.android.systemui.tuner.QSPagingSwitch;
49
50import java.util.ArrayList;
51
52/**
53 * Allows full-screen customization of QS, through show() and hide().
54 *
55 * This adds itself to the status bar window, so it can appear on top of quick settings and
56 * *someday* do fancy animations to get into/out of it.
57 */
58public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener, Callback,
59        OnDropListener, OnClickListener, Animator.AnimatorListener, TileSelectedListener,
60        OnCancelListener, OnDismissListener {
61
62    private static final int MENU_SAVE = Menu.FIRST;
63    private static final int MENU_RESET = Menu.FIRST + 1;
64    private final QSDetailClipper mClipper;
65
66    private PhoneStatusBar mPhoneStatusBar;
67
68    private Toolbar mToolbar;
69    private ViewGroup mDragButtons;
70    private CustomQSPanel mQsPanel;
71
72    private boolean isShown;
73    private DropButton mInfoButton;
74    private DropButton mRemoveButton;
75    private FloatingActionButton mFab;
76    private SystemUIDialog mDialog;
77    private QSTileHost mHost;
78
79    public QSCustomizer(Context context, AttributeSet attrs) {
80        super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
81        mClipper = new QSDetailClipper(this);
82    }
83
84    public void setHost(QSTileHost host) {
85        mHost = host;
86        mHost.addCallback(this);
87        mPhoneStatusBar = host.getPhoneStatusBar();
88        mQsPanel.setTiles(mHost.getTiles());
89        mQsPanel.setHost(mHost);
90        mQsPanel.setSavedTiles();
91    }
92
93    @Override
94    protected void onFinishInflate() {
95        super.onFinishInflate();
96        mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
97        TypedValue value = new TypedValue();
98        mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
99        mToolbar.setNavigationIcon(
100                getResources().getDrawable(R.drawable.ic_close_white, mContext.getTheme()));
101        mToolbar.setNavigationOnClickListener(new OnClickListener() {
102            @Override
103            public void onClick(View v) {
104                hide(0, 0);
105            }
106        });
107        mToolbar.setOnMenuItemClickListener(this);
108        mToolbar.getMenu().add(Menu.NONE, MENU_SAVE, 0, mContext.getString(R.string.save))
109                .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
110        mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
111                mContext.getString(com.android.internal.R.string.reset));
112
113        mQsPanel = (CustomQSPanel) findViewById(R.id.quick_settings_panel);
114
115        mDragButtons = (ViewGroup) findViewById(R.id.drag_buttons);
116        setDragging(false);
117
118        mInfoButton = (DropButton) findViewById(R.id.info_button);
119        mInfoButton.setOnDropListener(this);
120        mRemoveButton = (DropButton) findViewById(R.id.remove_button);
121        mRemoveButton.setOnDropListener(this);
122
123        mFab = (FloatingActionButton) findViewById(R.id.fab);
124        mFab.setImageResource(R.drawable.ic_add);
125        mFab.setOnClickListener(this);
126    }
127
128    public void show(int x, int y) {
129        isShown = true;
130        mQsPanel.setSavedTiles();
131        mPhoneStatusBar.getStatusBarWindow().addView(this);
132        mQsPanel.setListening(true);
133        mClipper.animateCircularClip(x, y, true, this);
134    }
135
136    public void hide(int x, int y) {
137        isShown = false;
138        mQsPanel.setListening(false);
139        mClipper.animateCircularClip(x, y, false, this);
140    }
141
142    public boolean isCustomizing() {
143        return isShown;
144    }
145
146    private void reset() {
147        ArrayList<String> tiles = new ArrayList<>();
148        for (String tile : QSPagingSwitch.QS_PAGE_TILES.split(",")) {
149            tiles.add(tile);
150        }
151        mQsPanel.setTiles(tiles);
152    }
153
154    private void setDragging(boolean dragging) {
155        mToolbar.setVisibility(!dragging ? View.VISIBLE : View.INVISIBLE);
156    }
157
158    private void save() {
159        Log.d("CustomQSPanel", "Save!");
160        mQsPanel.saveCurrentTiles();
161        // TODO: At save button.
162        hide(0, 0);
163    }
164
165    @Override
166    public boolean onMenuItemClick(MenuItem item) {
167        switch (item.getItemId()) {
168            case MENU_SAVE:
169                Log.d("CustomQSPanel", "Save...");
170                save();
171                break;
172            case MENU_RESET:
173                reset();
174                break;
175        }
176        return true;
177    }
178
179    @Override
180    public void onTileSelected(String spec) {
181        if (mDialog != null) {
182            mQsPanel.addTile(spec);
183            mDialog.dismiss();
184        }
185    }
186
187    @Override
188    public void onTilesChanged() {
189        mQsPanel.setTiles(mHost.getTiles());
190    }
191
192    public boolean onDragEvent(DragEvent event) {
193        switch (event.getAction()) {
194            case DragEvent.ACTION_DRAG_STARTED:
195                setDragging(true);
196                break;
197            case DragEvent.ACTION_DRAG_ENDED:
198                setDragging(false);
199                break;
200        }
201        return true;
202    }
203
204    public void onDrop(View v, ClipData data) {
205        if (v == mRemoveButton) {
206            mQsPanel.remove(mQsPanel.getSpec(data));
207        } else if (v == mInfoButton) {
208            mQsPanel.unstashTiles();
209            SystemUIDialog dialog = new SystemUIDialog(mContext);
210            dialog.setTitle(mQsPanel.getSpec(data));
211            dialog.setPositiveButton(R.string.ok, null);
212            dialog.show();
213        }
214    }
215
216    @Override
217    public void onClick(View v) {
218        if (mFab == v) {
219            mDialog = new SystemUIDialog(mContext,
220                    android.R.style.Theme_Material_Dialog);
221            View view = LayoutInflater.from(mContext).inflate(R.layout.qs_add_tiles_list, null);
222            ListView listView = (ListView) view.findViewById(android.R.id.list);
223            TileAdapter adapter = new TileAdapter(mContext, mQsPanel.getTiles(), mHost);
224            adapter.setListener(this);
225            listView.setDivider(null);
226            listView.setDividerHeight(0);
227            listView.setAdapter(adapter);
228            listView.setEmptyView(view.findViewById(R.id.empty_text));
229            mDialog.setView(view);
230            mDialog.setOnDismissListener(this);
231            mDialog.setOnCancelListener(this);
232            mDialog.show();
233            // Too lazy to figure out what this will be now, but it should probably be something
234            // besides just a dialog.
235            // For now, just make it big.
236            WindowManager.LayoutParams params = mDialog.getWindow().getAttributes();
237            params.width = WindowManager.LayoutParams.MATCH_PARENT;
238            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
239            mDialog.getWindow().setAttributes(params);
240        }
241    }
242
243    @Override
244    public void onDismiss(DialogInterface dialog) {
245        mDialog = null;
246    }
247
248    @Override
249    public void onCancel(DialogInterface dialog) {
250        mDialog = null;
251    }
252
253    @Override
254    public void onAnimationEnd(Animator animation) {
255        if (!isShown) {
256            mPhoneStatusBar.getStatusBarWindow().removeView(this);
257        }
258    }
259
260    @Override
261    public void onAnimationCancel(Animator animation) {
262        if (!isShown) {
263            mPhoneStatusBar.getStatusBarWindow().removeView(this);
264        }
265    }
266
267    @Override
268    public void onAnimationStart(Animator animation) {
269        // Don't care.
270    }
271
272    @Override
273    public void onAnimationRepeat(Animator animation) {
274        // Don't care.
275    }
276}