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