QSCustomizer.java revision 63554eda8d74b7449766865b03736aa1b3a3f1d8
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.LayoutInflater; 29import android.view.Menu; 30import android.view.MenuItem; 31import android.view.View; 32import android.widget.LinearLayout; 33import android.widget.Toolbar; 34import android.widget.Toolbar.OnMenuItemClickListener; 35import com.android.internal.logging.MetricsLogger; 36import com.android.internal.logging.MetricsProto; 37import com.android.systemui.R; 38import com.android.systemui.qs.QSContainer; 39import com.android.systemui.qs.QSDetailClipper; 40import com.android.systemui.qs.QSTile; 41import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; 42import com.android.systemui.statusbar.phone.PhoneStatusBar; 43import com.android.systemui.statusbar.phone.QSTileHost; 44 45import java.util.ArrayList; 46import java.util.List; 47 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 */ 54public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener { 55 56 private static final int MENU_RESET = Menu.FIRST; 57 58 private final QSDetailClipper mClipper; 59 60 private PhoneStatusBar mPhoneStatusBar; 61 62 private boolean isShown; 63 private QSTileHost mHost; 64 private RecyclerView mRecyclerView; 65 private TileAdapter mTileAdapter; 66 private Toolbar mToolbar; 67 private boolean mCustomizing; 68 private NotificationsQuickSettingsContainer mNotifQsContainer; 69 private QSContainer mQsContainer; 70 71 public QSCustomizer(Context context, AttributeSet attrs) { 72 super(new ContextThemeWrapper(context, R.style.edit_theme), attrs); 73 mClipper = new QSDetailClipper(this); 74 75 LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this); 76 77 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( 81 getResources().getDrawable(value.resourceId, mContext.getTheme())); 82 mToolbar.setNavigationOnClickListener(new OnClickListener() { 83 @Override 84 public void onClick(View v) { 85 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)); 91 mToolbar.setTitle(R.string.qs_edit); 92 93 mRecyclerView = (RecyclerView) findViewById(android.R.id.list); 94 mTileAdapter = new TileAdapter(getContext()); 95 mRecyclerView.setAdapter(mTileAdapter); 96 mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView); 97 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); 104 } 105 106 public void setHost(QSTileHost host) { 107 mHost = host; 108 mPhoneStatusBar = host.getPhoneStatusBar(); 109 mTileAdapter.setHost(host); 110 } 111 112 public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) { 113 mNotifQsContainer = notificationsQsContainer; 114 } 115 116 public void setQsContainer(QSContainer qsContainer) { 117 mQsContainer = qsContainer; 118 } 119 120 public void show(int x, int y) { 121 if (!isShown) { 122 MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT); 123 isShown = true; 124 setTileSpecs(); 125 setVisibility(View.VISIBLE); 126 mClipper.animateCircularClip(x, y, true, mExpandAnimationListener); 127 new TileQueryHelper(mContext, mHost).setListener(mTileAdapter); 128 mNotifQsContainer.setCustomizerAnimating(true); 129 mNotifQsContainer.setCustomizerShowing(true); 130 } 131 } 132 133 public void hide(int x, int y) { 134 if (isShown) { 135 MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT); 136 isShown = false; 137 mToolbar.dismissPopupMenus(); 138 setCustomizing(false); 139 save(); 140 mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener); 141 mNotifQsContainer.setCustomizerAnimating(true); 142 mNotifQsContainer.setCustomizerShowing(false); 143 } 144 } 145 146 private void setCustomizing(boolean customizing) { 147 mCustomizing = customizing; 148 mQsContainer.notifyCustomizeChanged(); 149 } 150 151 public boolean isCustomizing() { 152 return mCustomizing; 153 } 154 155 @Override 156 public boolean onMenuItemClick(MenuItem item) { 157 switch (item.getItemId()) { 158 case MENU_RESET: 159 MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_QS_EDIT_RESET); 160 reset(); 161 break; 162 } 163 return false; 164 } 165 166 private void reset() { 167 ArrayList<String> tiles = new ArrayList<>(); 168 String defTiles = mContext.getString(R.string.quick_settings_tiles_default); 169 for (String tile : defTiles.split(",")) { 170 tiles.add(tile); 171 } 172 mTileAdapter.setTileSpecs(tiles); 173 } 174 175 private void setTileSpecs() { 176 List<String> specs = new ArrayList<>(); 177 for (QSTile tile : mHost.getTiles()) { 178 specs.add(tile.getTileSpec()); 179 } 180 mTileAdapter.setTileSpecs(specs); 181 mRecyclerView.setAdapter(mTileAdapter); 182 } 183 184 private void save() { 185 mTileAdapter.saveSpecs(mHost); 186 } 187 188 private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() { 189 @Override 190 public void onAnimationEnd(Animator animation) { 191 setCustomizing(true); 192 mNotifQsContainer.setCustomizerAnimating(false); 193 } 194 195 @Override 196 public void onAnimationCancel(Animator animation) { 197 mNotifQsContainer.setCustomizerAnimating(false); 198 } 199 }; 200 201 private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() { 202 @Override 203 public void onAnimationEnd(Animator animation) { 204 if (!isShown) { 205 setVisibility(View.GONE); 206 } 207 mNotifQsContainer.setCustomizerAnimating(false); 208 } 209 210 @Override 211 public void onAnimationCancel(Animator animation) { 212 if (!isShown) { 213 setVisibility(View.GONE); 214 } 215 mNotifQsContainer.setCustomizerAnimating(false); 216 } 217 }; 218} 219