QSCustomizer.java revision 8b9d67fb636a89fe6537e7affb9d01a75f263d93
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.animation.Animator.AnimatorListener;
20import android.animation.AnimatorListenerAdapter;
21import android.content.Context;
22import android.support.v7.widget.DefaultItemAnimator;
23import android.support.v7.widget.GridLayoutManager;
24import android.support.v7.widget.RecyclerView;
25import android.util.AttributeSet;
26import android.util.TypedValue;
27import android.view.ContextThemeWrapper;
28import android.view.Menu;
29import android.view.MenuItem;
30import android.view.View;
31import android.widget.LinearLayout;
32import android.widget.Toolbar;
33import android.widget.Toolbar.OnMenuItemClickListener;
34import com.android.systemui.R;
35import com.android.systemui.qs.QSContainer;
36import com.android.systemui.qs.QSDetailClipper;
37import com.android.systemui.qs.QSTile;
38import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
39import com.android.systemui.statusbar.phone.PhoneStatusBar;
40import com.android.systemui.statusbar.phone.QSTileHost;
41
42import java.util.ArrayList;
43import java.util.List;
44
45/**
46 * Allows full-screen customization of QS, through show() and hide().
47 *
48 * This adds itself to the status bar window, so it can appear on top of quick settings and
49 * *someday* do fancy animations to get into/out of it.
50 */
51public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
52
53    private static final int MENU_RESET = Menu.FIRST;
54
55    private final QSDetailClipper mClipper;
56
57    private PhoneStatusBar mPhoneStatusBar;
58
59    private boolean isShown;
60    private QSTileHost mHost;
61    private RecyclerView mRecyclerView;
62    private TileAdapter mTileAdapter;
63    private Toolbar mToolbar;
64    private boolean mCustomizing;
65    private NotificationsQuickSettingsContainer mNotifQsContainer;
66    private QSContainer mQsContainer;
67
68    public QSCustomizer(Context context, AttributeSet attrs) {
69        super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
70        mClipper = new QSDetailClipper(this);
71    }
72
73    public void setHost(QSTileHost host) {
74        mHost = host;
75        mPhoneStatusBar = host.getPhoneStatusBar();
76    }
77
78    public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
79        mNotifQsContainer = notificationsQsContainer;
80    }
81
82    public void setQsContainer(QSContainer qsContainer) {
83        mQsContainer = qsContainer;
84    }
85
86    @Override
87    protected void onFinishInflate() {
88        super.onFinishInflate();
89        mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
90        TypedValue value = new TypedValue();
91        mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
92        mToolbar.setNavigationIcon(
93                getResources().getDrawable(value.resourceId, mContext.getTheme()));
94        mToolbar.setNavigationOnClickListener(new OnClickListener() {
95            @Override
96            public void onClick(View v) {
97                hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
98            }
99        });
100        mToolbar.setOnMenuItemClickListener(this);
101        mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
102                mContext.getString(com.android.internal.R.string.reset));
103        mToolbar.setTitle(R.string.qs_edit);
104
105        mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
106        mTileAdapter = new TileAdapter(getContext());
107        mRecyclerView.setAdapter(mTileAdapter);
108        mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
109        GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
110        layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
111        mRecyclerView.setLayoutManager(layout);
112        mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
113        DefaultItemAnimator animator = new DefaultItemAnimator();
114        animator.setMoveDuration(TileAdapter.MOVE_DURATION);
115        mRecyclerView.setItemAnimator(animator);
116    }
117
118    public void show(int x, int y) {
119        if (!isShown) {
120            isShown = true;
121            setTileSpecs();
122            setVisibility(View.VISIBLE);
123            mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
124            new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
125            mNotifQsContainer.setCustomizerAnimating(true);
126        }
127    }
128
129    public void hide(int x, int y) {
130        if (isShown) {
131            isShown = false;
132            setCustomizing(false);
133            save();
134            mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
135            mNotifQsContainer.setCustomizerAnimating(true);
136        }
137    }
138
139    private void setCustomizing(boolean customizing) {
140        mCustomizing = customizing;
141        mQsContainer.notifyCustomizeChanged();
142    }
143
144    public boolean isCustomizing() {
145        return mCustomizing;
146    }
147
148    @Override
149    public boolean onMenuItemClick(MenuItem item) {
150        switch (item.getItemId()) {
151            case MENU_RESET:
152                reset();
153                break;
154        }
155        return false;
156    }
157
158    private void reset() {
159        ArrayList<String> tiles = new ArrayList<>();
160        String defTiles = mContext.getString(R.string.quick_settings_tiles_default);
161        for (String tile : defTiles.split(",")) {
162            tiles.add(tile);
163        }
164        mTileAdapter.setTileSpecs(tiles);
165    }
166
167    private void setTileSpecs() {
168        List<String> specs = new ArrayList<>();
169        for (QSTile tile : mHost.getTiles()) {
170            specs.add(tile.getTileSpec());
171        }
172        mTileAdapter.setTileSpecs(specs);
173    }
174
175    private void save() {
176        mTileAdapter.saveSpecs(mHost);
177    }
178
179    private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
180        @Override
181        public void onAnimationEnd(Animator animation) {
182            setCustomizing(true);
183            mNotifQsContainer.setCustomizerAnimating(false);
184        }
185
186        @Override
187        public void onAnimationCancel(Animator animation) {
188            mNotifQsContainer.setCustomizerAnimating(false);
189        }
190    };
191
192    private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
193        @Override
194        public void onAnimationEnd(Animator animation) {
195            if (!isShown) {
196                setVisibility(View.GONE);
197            }
198            mNotifQsContainer.setCustomizerAnimating(false);
199        }
200
201        @Override
202        public void onAnimationCancel(Animator animation) {
203            if (!isShown) {
204                setVisibility(View.GONE);
205            }
206            mNotifQsContainer.setCustomizerAnimating(false);
207        }
208    };
209}
210