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