1c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk/* 2c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk * Copyright (C) 2015 The Android Open Source Project 3c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk * 4dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 5dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * you may not use this file except in compliance with the License. 6dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * You may obtain a copy of the License at 7c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk * 8c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 9c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk * 10dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * Unless required by applicable law or agreed to in writing, software 11dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * distributed under the License is distributed on an "AS IS" BASIS, 12dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * See the License for the specific language governing permissions and 14dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * limitations under the License. 15c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk */ 16c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monkpackage com.android.systemui.qs; 17c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 18c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monkimport android.content.Context; 19dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.content.res.TypedArray; 20dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.graphics.drawable.Drawable; 21dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.graphics.drawable.RippleDrawable; 22c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monkimport android.os.Handler; 23c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monkimport android.os.Looper; 24c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monkimport android.os.Message; 2520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynoldsimport android.text.TextUtils; 26c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monkimport android.view.View; 2720aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynoldsimport android.view.accessibility.AccessibilityEvent; 2820aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynoldsimport android.view.accessibility.AccessibilityNodeInfo; 29dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.widget.LinearLayout; 3020aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynoldsimport android.widget.Switch; 31c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 32dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport com.android.systemui.R; 33c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 34dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkpublic class QSTileBaseView extends LinearLayout { 35c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 36c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk private final H mHandler = new H(); 37dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk private QSIconView mIcon; 38dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk private RippleDrawable mRipple; 39dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk private Drawable mTileBackground; 4020aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds private String mAccessibilityClass; 4120aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds private boolean mTileState; 4220aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds private boolean mCollapsedView; 43c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 44dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk public QSTileBaseView(Context context, QSIconView icon) { 4520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds this(context, icon, false); 4620aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 4720aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds 4820aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds public QSTileBaseView(Context context, QSIconView icon, boolean collapsedView) { 49c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk super(context); 50dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mIcon = icon; 51dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk addView(mIcon); 52dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 53dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mTileBackground = newTileBackground(); 54dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk if (mTileBackground instanceof RippleDrawable) { 55dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setRipple((RippleDrawable) mTileBackground); 56dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 57dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 58dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setBackground(mTileBackground); 59dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 60dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk // Default to Quick Tile padding, and QSTileView will specify its own padding. 61dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding); 62ec87a878d340500be05be3ff622b06f66eae8a96Jason Monk setPadding(0, padding, 0, padding); 63162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk setClipChildren(false); 64162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk setClipToPadding(false); 6520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds mCollapsedView = collapsedView; 66c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 67c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 68dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk private Drawable newTileBackground() { 69dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless }; 70dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final TypedArray ta = mContext.obtainStyledAttributes(attrs); 71dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final Drawable d = ta.getDrawable(0); 72dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk ta.recycle(); 73dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk return d; 74c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 75c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 76dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk private void setRipple(RippleDrawable tileBackground) { 77dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mRipple = tileBackground; 78dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk if (getWidth() != 0) { 79dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk updateRippleSize(getWidth(), getHeight()); 80dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 81dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 82c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 83dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk private void updateRippleSize(int width, int height) { 84dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk // center the touch feedback on the center of the icon, and dial it down a bit 85dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int cx = width / 2; 86dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int cy = height / 2; 87dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int rad = (int)(mIcon.getHeight() * .85f); 88dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad); 89c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 90c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 91dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk public void init(OnClickListener click, OnLongClickListener longClick) { 92dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setClickable(true); 93dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setOnClickListener(click); 9476c67aa361f65dfb2f5e03d06cc1ccebce9cecd9Jason Monk setOnLongClickListener(longClick); 95dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 96dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 97dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk @Override 98dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk protected void onLayout(boolean changed, int l, int t, int r, int b) { 99dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk super.onLayout(changed, l, t, r, b); 100dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int w = getMeasuredWidth(); 101dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int h = getMeasuredHeight(); 102dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 103dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk if (mRipple != null) { 104dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk updateRippleSize(w, h); 105dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 106dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 107c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 108c3081179d8961a291c47c05f52b63c134284cd4dJorim Jaggi @Override 109c3081179d8961a291c47c05f52b63c134284cd4dJorim Jaggi public boolean hasOverlappingRendering() { 110c3081179d8961a291c47c05f52b63c134284cd4dJorim Jaggi // Avoid layers for this layout - we don't need them. 111c3081179d8961a291c47c05f52b63c134284cd4dJorim Jaggi return false; 112c3081179d8961a291c47c05f52b63c134284cd4dJorim Jaggi } 113c3081179d8961a291c47c05f52b63c134284cd4dJorim Jaggi 114dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk /** 115dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * Update the accessibility order for this view. 116dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * 117dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * @param previousView the view which should be before this one 118dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk * @return the last view in this view which is accessible 119dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk */ 120dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk public View updateAccessibilityOrder(View previousView) { 121dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setAccessibilityTraversalAfter(previousView.getId()); 122dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk return this; 123dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 124c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 125dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk public void onStateChanged(QSTile.State state) { 126dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget(); 127c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 128c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 129dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk protected void handleStateChanged(QSTile.State state) { 130dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mIcon.setIcon(state); 13120aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (mCollapsedView && !TextUtils.isEmpty(state.minimalContentDescription)) { 13220aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds setContentDescription(state.minimalContentDescription); 13320aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } else { 13420aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds setContentDescription(state.contentDescription); 13520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 13620aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (mCollapsedView) { 13720aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds mAccessibilityClass = state.minimalAccessibilityClassName; 13820aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } else { 13920aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds mAccessibilityClass = state.expandedAccessibilityClassName; 14020aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 14120aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (state instanceof QSTile.BooleanState) { 14220aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds mTileState = ((QSTile.BooleanState) state).value; 14320aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 144c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 145c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 1461aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk public QSIconView getIcon() { 147162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk return mIcon; 148162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk } 149162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk 15020aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds @Override 15120aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 15220aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds super.onInitializeAccessibilityEvent(event); 15320aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (!TextUtils.isEmpty(mAccessibilityClass)) { 15420aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds event.setClassName(mAccessibilityClass); 15520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (Switch.class.getName().equals(mAccessibilityClass)) { 15620aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds String label = getResources() 157d8834773ebbc139df0052484af8129c240e1b3acJulia Reynolds .getString(!mTileState ? R.string.switch_bar_on : R.string.switch_bar_off); 15820aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds event.setContentDescription(label); 159d8834773ebbc139df0052484af8129c240e1b3acJulia Reynolds event.setChecked(!mTileState); 16020aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 16120aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 16220aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 16320aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds 16420aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds @Override 16520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 16620aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds super.onInitializeAccessibilityNodeInfo(info); 16720aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (!TextUtils.isEmpty(mAccessibilityClass)) { 16820aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds info.setClassName(mAccessibilityClass); 16920aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds if (Switch.class.getName().equals(mAccessibilityClass)) { 17020aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds String label = getResources() 17120aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds .getString(mTileState ? R.string.switch_bar_on : R.string.switch_bar_off); 17220aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds info.setText(label); 17320aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds info.setChecked(mTileState); 17420aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds info.setCheckable(true); 17520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 17620aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 17720aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds } 17820aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds 179c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk private class H extends Handler { 180c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk private static final int STATE_CHANGED = 1; 181c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk public H() { 182c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk super(Looper.getMainLooper()); 183c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 184c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk 185c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk @Override 186c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk public void handleMessage(Message msg) { 187c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk if (msg.what == STATE_CHANGED) { 188c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk handleStateChanged((QSTile.State) msg.obj); 189c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 190c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 191c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk } 192c133d26b3897811e9f567d787bff8eafb364f3e3Jason Monk} 193