Merge "Move zen-mode systemui affordance to quick settings."

This commit is contained in:
John Spurlock
2014-03-12 23:05:58 +00:00
committed by Android (Google) Code Review
8 changed files with 255 additions and 412 deletions

View File

@@ -58,12 +58,6 @@
android:layout_height="@dimen/notification_panel_header_height"
/>
<com.android.systemui.statusbar.phone.ZenModeView
android:id="@+id/zenmode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/emergency_calls_only"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"

View File

@@ -15,7 +15,7 @@
** limitations under the License.
-->
<com.android.systemui.statusbar.phone.PanelHeaderView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/header"
@@ -106,4 +106,4 @@
android:contentDescription="@string/accessibility_notifications_button"
/>
</FrameLayout>
</com.android.systemui.statusbar.phone.PanelHeaderView>
</LinearLayout>

View File

@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.EventLog;
import android.view.MotionEvent;
@@ -57,17 +56,6 @@ public class NotificationPanelView extends PanelView {
mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
mHandleView = findViewById(R.id.handle);
PanelHeaderView header = (PanelHeaderView) findViewById(R.id.header);
ZenModeView zenModeView = (ZenModeView) findViewById(R.id.zenmode);
zenModeView.setAdapter(new ZenModeViewAdapter(mContext) {
@Override
public void configure() {
if (mStatusBar != null) {
mStatusBar.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
}
}
});
header.setZenModeView(zenModeView);
}
@Override

View File

@@ -1,70 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class PanelHeaderView extends LinearLayout {
private static final String TAG = "PanelHeaderView";
private static final boolean DEBUG = false;
private ZenModeView mZenModeView;
public PanelHeaderView(Context context) {
super(context);
}
public PanelHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setZenModeView(ZenModeView zmv) {
mZenModeView = zmv;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final boolean rt = super.dispatchTouchEvent(ev);
if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev);
if (mZenModeView != null) {
mZenModeView.dispatchExternalTouchEvent(ev);
}
return rt;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final boolean rt = super.onInterceptTouchEvent(ev);
if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev);
return rt;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean rt = super.onTouchEvent(event);
if (DEBUG) logTouchEvent("onTouchEvent", rt, event);
return true;
}
private void logTouchEvent(String method, boolean rt, MotionEvent ev) {
Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + ev);
}
}

View File

@@ -52,13 +52,16 @@ import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Profile;
import android.provider.Settings;
import android.security.KeyChain;
import android.text.TextUtils.TruncateAt;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@@ -586,6 +589,31 @@ class QuickSettings {
});
parent.addView(airplaneTile);
// Zen Mode
final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
zenModeTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showZenModeDialog();
}
});
mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
@Override
public void refreshView(QuickSettingsTileView unused, State state) {
zenModeTile.setImageResource(state.iconId);
// TODO cut new assets
zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
zenModeTile.getImageView().setScaleX(1.5f);
zenModeTile.getImageView().setScaleY(1.5f);
// for landscape version
zenModeTile.getTextView().setMaxLines(2);
zenModeTile.getTextView().setEllipsize(TruncateAt.END);
// TODO content description
zenModeTile.setText(state.label);
}
});
parent.addView(zenModeTile);
// Bluetooth
if (mModel.deviceSupportsBluetooth()
|| DEBUG_GONE_TILES) {
@@ -864,6 +892,31 @@ class QuickSettings {
dialog.show();
}
private void showZenModeDialog() {
final Dialog d = new Dialog(mContext);
d.requestWindowFeature(Window.FEATURE_NO_TITLE);
d.setCancelable(true);
d.setCanceledOnTouchOutside(true);
final ZenModeView v = new ZenModeView(mContext);
v.setAdapter(new ZenModeViewAdapter(mContext) {
@Override
public void configure() {
if (mStatusBarService != null) {
mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
}
d.dismiss();
}
@Override
public void close() {
d.dismiss();
}
});
d.setContentView(v);
d.create();
d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
d.show();
}
private void applyBluetoothStatus() {
mModel.onBluetoothStateChange(mBluetoothState);
}

View File

@@ -38,6 +38,7 @@ import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
@@ -112,6 +113,9 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
public static class RotationLockState extends State {
boolean visible = false;
}
public static class ZenModeState extends State {
int zenMode = Settings.Global.ZEN_MODE_OFF;
}
/** The callback to update a given tile. */
interface RefreshCallback {
@@ -294,6 +298,25 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
}
}
/** ContentObserver to watch display color space adjustment */
private class ZenModeObserver extends ContentObserver {
public ZenModeObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
onZenModeChanged();
}
public void startObserving() {
final ContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver(this);
cr.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this);
}
}
/** Callback for changes to remote display routes. */
private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
@Override
@@ -327,6 +350,7 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
private final DisplayInversionObserver mInversionObserver;
private final DisplayContrastObserver mContrastObserver;
private final DisplayColorSpaceObserver mColorSpaceObserver;
private final ZenModeObserver mZenModeObserver;
private final MediaRouter mMediaRouter;
private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
@@ -349,6 +373,10 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
private RefreshCallback mAirplaneModeCallback;
private State mAirplaneModeState = new State();
private QuickSettingsTileView mZenModeTile;
private RefreshCallback mZenModeCallback;
private ZenModeState mZenModeState = new ZenModeState();
private QuickSettingsTileView mWifiTile;
private RefreshCallback mWifiCallback;
private WifiState mWifiState = new WifiState();
@@ -445,6 +473,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
mContrastObserver.startObserving();
mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
mColorSpaceObserver.startObserving();
mZenModeObserver = new ZenModeObserver(mHandler);
mZenModeObserver.startObserving();
mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
rebindMediaRouterAsCurrentUser();
@@ -567,6 +597,30 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
}
// Zen Mode
void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) {
mZenModeTile = view;
mZenModeCallback = cb;
onZenModeChanged();
}
private void onZenModeChanged() {
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF;
mZenModeState.zenMode = mode;
if (mode == Settings.Global.ZEN_MODE_FULL) {
mZenModeState.iconId = R.drawable.stat_sys_zen_full;
mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_FULL);
} else if (mode == Settings.Global.ZEN_MODE_LIMITED) {
mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_LIMITED);
} else {
mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_LIMITED);
}
mZenModeCallback.refreshView(mZenModeTile, mZenModeState);
}
// Wifi
void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
mWifiTile = view;

View File

@@ -19,22 +19,16 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.os.AsyncTask;
import android.os.Vibrator;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextPaint;
import android.text.method.LinkMovementMethod;
import android.text.style.RelativeSizeSpan;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
@@ -62,7 +56,7 @@ public class ZenModeView extends RelativeLayout {
private static final Typeface CONDENSED =
Typeface.create("sans-serif-condensed", Typeface.NORMAL);
private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network
private static final int BACKGROUND = 0xff1d3741; //0x3333b5e5;
private static final int BACKGROUND = 0xff282828;
private static final long DURATION = new ValueAnimator().getDuration();
private static final long BOUNCE_DURATION = DURATION / 3;
private static final float BOUNCE_SCALE = 0.8f;
@@ -73,23 +67,14 @@ public class ZenModeView extends RelativeLayout {
private final Context mContext;
private final Paint mPathPaint;
private final TextView mHintText;
private final ModeSpinner mModeSpinner;
private final ImageView mCloseButton;
private final ImageView mSettingsButton;
private final Rect mLayoutRect = new Rect();
private final ModeSpinner mModeSpinner;
private final TextView mActionButton;
private final View mDivider;
private final UntilPager mUntilPager;
private final AlarmWarning mAlarmWarning;
private final int mPopDuration;
private float mDownY;
private int mDownBottom;
private boolean mPeekable = true;
private boolean mClosing;
private int mBottom;
private int mWidthSpec;
private Adapter mAdapter;
private boolean mPopped;
public ZenModeView(Context context) {
this(context, null);
@@ -100,34 +85,22 @@ public class ZenModeView extends RelativeLayout {
if (DEBUG) log("new %s()", getClass().getSimpleName());
mContext = context;
mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setColor(GRAY);
mPathPaint.setStrokeWidth(5);
final int iconSize = mContext.getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
final int topRowSize = iconSize * 2 / 3;
final int p = topRowSize / 7;
mCloseButton = new ImageView(mContext);
mCloseButton.setAlpha(0f);
mCloseButton.setImageDrawable(sd(closePath(topRowSize), topRowSize, mPathPaint));
addView(mCloseButton, new LayoutParams(topRowSize, topRowSize));
mCloseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bounce(v, null);
close();
}
});
mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setColor(GRAY);
mPathPaint.setStrokeWidth(p / 2);
mSettingsButton = new ImageView(mContext);
mSettingsButton.setAlpha(0f);
final int p = topRowSize / 7;
mSettingsButton.setPadding(p, p, p, p);
mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal);
LayoutParams lp = new LayoutParams(topRowSize, topRowSize);
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
lp.topMargin = p;
lp.leftMargin = p;
addView(mSettingsButton, lp);
mSettingsButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -140,65 +113,65 @@ public class ZenModeView extends RelativeLayout {
});
mModeSpinner = new ModeSpinner(mContext);
mModeSpinner.setAlpha(0);
mModeSpinner.setEnabled(false);
mModeSpinner.setId(android.R.id.title);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
lp.topMargin = p;
lp.addRule(CENTER_HORIZONTAL);
addView(mModeSpinner, lp);
mUntilPager = new UntilPager(mContext, mPathPaint, iconSize);
mUntilPager.setId(android.R.id.tabhost);
mUntilPager.setAlpha(0);
lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
mActionButton = new TextView(mContext);
mActionButton.setTextColor(GRAY);
mActionButton.setTypeface(CONDENSED);
mActionButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mActionButton.getTextSize() * 1.2f);
mActionButton.setAllCaps(true);
mActionButton.setGravity(Gravity.CENTER);
mActionButton.setPadding(p, 0, p * 2, 0);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
lp.topMargin = p;
lp.addRule(ALIGN_PARENT_RIGHT);
lp.addRule(ALIGN_BASELINE, mModeSpinner.getId());
addView(mActionButton, lp);
mActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bounce(v, null);
beginOrEnd();
}
});
mDivider = new View(mContext);
mDivider.setId(android.R.id.empty);
mDivider.setBackgroundColor(GRAY);
lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
lp.addRule(BELOW, mModeSpinner.getId());
lp.topMargin = p;
lp.bottomMargin = p;
addView(mDivider, lp);
mUntilPager = new UntilPager(mContext, mPathPaint, iconSize * 3 / 4);
mUntilPager.setId(android.R.id.tabhost);
lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
lp.addRule(BELOW, mDivider.getId());
addView(mUntilPager, lp);
mAlarmWarning = new AlarmWarning(mContext);
mAlarmWarning.setAlpha(0);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(CENTER_HORIZONTAL);
lp.addRule(BELOW, mUntilPager.getId());
lp.bottomMargin = p;
addView(mAlarmWarning, lp);
mHintText = new TextView(mContext);
mHintText.setTypeface(CONDENSED);
mHintText.setText("Swipe down for Limited Interruptions");
mHintText.setGravity(Gravity.CENTER);
mHintText.setTextColor(GRAY);
addView(mHintText, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
}
private boolean isApplicable() {
return mAdapter != null && mAdapter.isApplicable();
}
private void close() {
mClosing = true;
final int startBottom = mBottom;
final int max = mPeekable ? getExpandedBottom() : startBottom;
mHintText.animate().alpha(1).setUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final float f = animation.getAnimatedFraction();
final int hintBottom = mHintText.getBottom();
final boolean isDone = f == 1;
setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max, isDone);
if (isDone) {
mPeekable = true;
mPopped = false;
mClosing = false;
mModeSpinner.updateState();
if (mAdapter != null) {
mAdapter.cancel();
}
}
}
}).start();
mUntilPager.animate().alpha(0).start();
mAlarmWarning.animate().alpha(0).start();
private void beginOrEnd() {
if (mAdapter == null) return;
if (mAdapter.getMode() == mAdapter.getCommittedMode()) {
// end
mAdapter.setCommittedMode(Adapter.MODE_OFF);
} else {
// begin
mAdapter.setCommittedMode(mAdapter.getMode());
}
mAdapter.close();
}
public void setAdapter(Adapter adapter) {
@@ -218,180 +191,41 @@ public class ZenModeView extends RelativeLayout {
}
private void updateState(boolean animate) {
final boolean applicable = isApplicable();
setVisibility(applicable ? VISIBLE : GONE);
if (!applicable) {
return;
}
if (mAdapter != null && mAdapter.getMode() == Adapter.MODE_OFF && !mPeekable) {
close();
} else {
mModeSpinner.updateState();
mUntilPager.updateState();
mAlarmWarning.updateState(animate);
final float settingsAlpha = getSettingsButtonAlpha();
if (settingsAlpha != mSettingsButton.getAlpha()) {
if (animate) {
mSettingsButton.animate().alpha(settingsAlpha).start();
} else {
mSettingsButton.setAlpha(settingsAlpha);
}
}
if (mPeekable && mAdapter != null && mAdapter.getMode() != Adapter.MODE_OFF) {
if (DEBUG) log("panic expand!");
mPeekable = false;
mModeSpinner.setEnabled(true);
mBottom = getExpandedBottom();
setExpanded(1);
mModeSpinner.updateState();
mUntilPager.updateState();
mAlarmWarning.updateState(animate);
final float settingsAlpha = isFull() ? 0 : SETTINGS_ALPHA;
if (settingsAlpha != mSettingsButton.getAlpha()) {
if (animate) {
mSettingsButton.animate().alpha(settingsAlpha).start();
} else {
mSettingsButton.setAlpha(settingsAlpha);
}
}
final boolean committed = mAdapter != null
&& mAdapter.getMode() == mAdapter.getCommittedMode();
mActionButton.setText(committed ? "End" : "Begin");
}
private float getSettingsButtonAlpha() {
final boolean full = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
final boolean collapsed = mHintText.getAlpha() == 1;
return full || collapsed ? 0 : SETTINGS_ALPHA;
}
private static Path closePath(int size) {
final int pad = size / 4;
final Path p = new Path();
p.moveTo(pad, pad);
p.lineTo(size - pad, size - pad);
p.moveTo(size - pad, pad);
p.lineTo(pad, size - pad);
return p;
private boolean isFull() {
return mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (DEBUG) log("onMeasure %s %s",
MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec));
final boolean widthExact = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
if (!widthExact || (widthMeasureSpec != mWidthSpec)) {
if (DEBUG) log(" super.onMeasure");
final int hms = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
super.onMeasure(widthMeasureSpec, hms);
mBottom = mPeekable ? mHintText.getMeasuredHeight() : getExpandedBottom();
mWidthSpec = widthMeasureSpec;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!isFull()) {
final LayoutParams lp = (LayoutParams) mModeSpinner.getLayoutParams();
final int mh = vh(mModeSpinner) + vh(mDivider) + vh(mUntilPager) + lp.topMargin;
setMeasuredDimension(getMeasuredWidth(), mh);
}
if (DEBUG) log("mBottom (OM) = " + mBottom);
setMeasuredDimension(getMeasuredWidth(), mBottom);
if (DEBUG) log(" mw=%s mh=%s",
toString(getMeasuredWidthAndState()), toString(getMeasuredHeightAndState()));
}
private static String toString(int sizeAndState) {
final int size = sizeAndState & MEASURED_SIZE_MASK;
final boolean tooSmall = (sizeAndState & MEASURED_STATE_TOO_SMALL) != 0;
return size + (tooSmall ? "TOO SMALL" : "");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
mLayoutRect.set(left, top, right, bottom);
if (DEBUG) log("onLayout %s %s %dx%d", changed,
mLayoutRect.toShortString(), mLayoutRect.width(), mLayoutRect.height());
super.onLayout(changed, left, top, right, bottom);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final boolean rt = super.dispatchTouchEvent(ev);
if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev);
return rt;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final boolean rt = super.onInterceptTouchEvent(ev);
if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev);
if (isApplicable()
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.getY() > mCloseButton.getBottom()
&& mPeekable) {
return true;
}
return rt;
}
private static void logTouchEvent(String method, boolean rt, MotionEvent event) {
final String action = MotionEvent.actionToString(event.getAction());
Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + action);
}
private int getExpandedBottom() {
int b = mModeSpinner.getMeasuredHeight() + mUntilPager.getMeasuredHeight();
if (mAlarmWarning.getAlpha() == 1) b += mAlarmWarning.getMeasuredHeight();
return b;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean rt = super.onTouchEvent(event);
if (DEBUG) logTouchEvent("onTouchEvent", rt, event);
if (!isApplicable() || !mPeekable) {
return rt;
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mDownY = event.getY();
if (DEBUG) log(" mDownY=" + mDownY);
mDownBottom = mBottom;
return true;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
final float dy = event.getY() - mDownY;
if (!mPopped) {
mPopped = true;
AsyncTask.execute(mPopVibration);
}
setPeeked(mDownBottom + (int)dy, getExpandedBottom(), false);
} else if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
final float dy = event.getY() - mDownY;
setPeeked(mDownBottom + (int)dy, getExpandedBottom(), true);
if (mPeekable) {
close();
}
}
return rt;
}
private void setPeeked(int peeked, int max, boolean isDone) {
if (DEBUG) log("setPeeked=" + peeked);
final int min = mHintText.getBottom();
peeked = Math.max(min, Math.min(peeked, max));
if (!isDone && mBottom == peeked) {
return;
}
if (peeked == max && isDone) {
mPeekable = false;
mModeSpinner.setEnabled(true);
if (mAdapter != null) {
mAdapter.setMode(Adapter.MODE_LIMITED);
}
}
if (peeked == min) {
mPeekable = true;
mModeSpinner.setEnabled(false);
}
if (DEBUG) log(" mBottom=" + peeked);
mBottom = peeked;
final float f = (peeked - min) / (float)(max - min);
setExpanded(f);
requestLayout();
}
private void setExpanded(float f) {
if (DEBUG) log("setExpanded " + f);
final int a = (int)(Color.alpha(BACKGROUND) * f);
setBackgroundColor(Color.argb(a,
Color.red(BACKGROUND), Color.green(BACKGROUND), Color.blue(BACKGROUND)));
mHintText.setAlpha(1 - f);
mCloseButton.setAlpha(f);
mModeSpinner.setAlpha(f);
mUntilPager.setAlpha(f);
mSettingsButton.setAlpha(f * getSettingsButtonAlpha());
private int vh(View v) {
LayoutParams lp = (LayoutParams) v.getLayoutParams();
return v.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
}
private static void log(String msg, Object... args) {
@@ -406,12 +240,6 @@ public class ZenModeView extends RelativeLayout {
return sd;
}
public void dispatchExternalTouchEvent(MotionEvent ev) {
if (isApplicable()) {
onTouchEvent(ev);
}
}
private static void bounce(final View v, final Runnable midBounce) {
v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3)
.setListener(new AnimatorListenerAdapter() {
@@ -429,13 +257,18 @@ public class ZenModeView extends RelativeLayout {
}).start();
}
private final Runnable mPopVibration = new Runnable() {
@Override
public void run() {
Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(mPopDuration);
}
};
public static String modeToString(int mode) {
if (mode == Adapter.MODE_OFF) return "MODE_OFF";
if (mode == Adapter.MODE_LIMITED) return "MODE_LIMITED";
if (mode == Adapter.MODE_FULL) return "MODE_FULL";
throw new IllegalArgumentException("Invalid mode: " + mode);
}
public static String modeToLabel(int mode) {
if (mode == Adapter.MODE_LIMITED) return "Limited interruptions";
if (mode == Adapter.MODE_FULL) return "Zero interruptions";
throw new UnsupportedOperationException("Unsupported mode: " + mode);
}
private final class UntilPager extends RelativeLayout {
private final ImageView mPrev;
@@ -448,6 +281,7 @@ public class ZenModeView extends RelativeLayout {
public UntilPager(Context context, Paint pathPaint, int iconSize) {
super(context);
mText1 = new TextView(mContext);
mText1.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText1.getTextSize() * 1.2f);
mText1.setTypeface(CONDENSED);
mText1.setTextColor(GRAY);
mText1.setGravity(Gravity.CENTER);
@@ -456,6 +290,7 @@ public class ZenModeView extends RelativeLayout {
mText = mText1;
mText2 = new TextView(mContext);
mText2.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText1.getTextSize());
mText2.setTypeface(CONDENSED);
mText2.setTextColor(GRAY);
mText2.setAlpha(0);
@@ -478,7 +313,7 @@ public class ZenModeView extends RelativeLayout {
});
lp = new LayoutParams(iconSize, iconSize);
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
lp.addRule(ALIGN_PARENT_RIGHT);
final View v2 = new View(mContext);
v2.setBackgroundColor(BACKGROUND);
addView(v2, lp);
@@ -532,9 +367,7 @@ public class ZenModeView extends RelativeLayout {
}
private void setText(final TextView textView, final ExitCondition ec) {
SpannableStringBuilder ss = new SpannableStringBuilder(ec.line1 + "\n" + ec.line2);
ss.setSpan(new RelativeSizeSpan(1.5f), (ec.line1 + "\n").length(), ss.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary);
if (ec.action != null) {
ss.setSpan(new CustomLinkSpan() {
@Override
@@ -542,7 +375,7 @@ public class ZenModeView extends RelativeLayout {
// TODO wire up links
Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show();
}
}, (ec.line1 + "\n").length(), ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setMovementMethod(LinkMovementMethod.getInstance());
} else {
textView.setMovementMethod(null);
@@ -558,7 +391,7 @@ public class ZenModeView extends RelativeLayout {
}
private Path prevPath(int size) {
final int hp = size / 3;
final int hp = size * 3 / 8;
final int vp = size / 4;
final Path p = new Path();
p.moveTo(size - hp, vp);
@@ -568,7 +401,7 @@ public class ZenModeView extends RelativeLayout {
}
private Path nextPath(int size) {
final int hp = size / 3;
final int hp = size * 3 / 8;
final int vp = size / 4;
Path p = new Path();
p.moveTo(hp, vp);
@@ -603,12 +436,14 @@ public class ZenModeView extends RelativeLayout {
public static final int MODE_LIMITED = 1;
public static final int MODE_FULL = 2;
boolean isApplicable();
void configure();
void close();
int getMode();
void setMode(int mode);
int getCommittedMode();
void setCommittedMode(int mode);
void select(ExitCondition ec);
void cancel();
void init();
void setCallbacks(Callbacks callbacks);
ExitCondition getExitCondition(int d);
int getExitConditionCount();
@@ -637,38 +472,38 @@ public class ZenModeView extends RelativeLayout {
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
public View getDropDownView(final int position, View convertView, ViewGroup parent) {
if (DEBUG) log("getDropDownView %s cv=%s parent=%s",
position, convertView, parent);
final TextView tv = convertView != null ? (TextView) convertView
: new TextView(context);
final int mode = getItem(position);
tv.setText(modeToString(mode));
tv.setText(modeToLabel(mode));
final boolean inDropdown = parent instanceof ListView;
if (convertView == null) {
if (DEBUG) log(" setting up view");
tv.setTextColor(GRAY);
tv.setTypeface(CONDENSED);
tv.setAllCaps(true);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.2f);
final int p = (int) tv.getTextSize() / 2;
if (parent instanceof ListView) {
tv.setPadding(p, p, p, p);
if (inDropdown) {
tv.setPadding(p, p, 0, p);
} else {
tv.setGravity(Gravity.CENTER_HORIZONTAL);
tv.setPadding(p, 0, p, 0);
tv.setPadding(p, 0, 0, 0);
}
}
tv.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
if (DEBUG) log("onTouch %s %s", tv.getText(),
MotionEvent.actionToString(event.getAction()));
if (mAdapter != null) {
if (DEBUG) log("onTouch %s %s inDropdown=%s", tv.getText(),
MotionEvent.actionToString(event.getAction()), inDropdown);
if (inDropdown && mAdapter != null) {
mAdapter.setMode(mode);
}
return false;
}
});
return tv;
}
@@ -688,16 +523,10 @@ public class ZenModeView extends RelativeLayout {
if (getAdapter().getItem(i).equals(mode)) {
if (DEBUG) log(" setting selection = " + i);
setSelection(i, true);
return;
onDetachedFromWindow();
}
}
}
private String modeToString(int mode) {
if (mode == Adapter.MODE_LIMITED) return "Limited interruptions";
if (mode == Adapter.MODE_FULL) return "Zero interruptions";
throw new UnsupportedOperationException("Unsupported mode: " + mode);
}
}
private final class AlarmWarning extends LinearLayout {
@@ -724,29 +553,12 @@ public class ZenModeView extends RelativeLayout {
}
public void updateState(boolean animate) {
final boolean visible = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
final float alpha = visible ? 1 : 0;
final float alpha = isFull() ? 1 : 0;
if (alpha == getAlpha()) {
return;
}
if (animate) {
final boolean in = alpha == 1;
animate().alpha(alpha).setUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (mPeekable || mClosing) {
return;
}
float f = animation.getAnimatedFraction();
if (!in) {
f = 1 - f;
}
ZenModeView.this.mBottom = mUntilPager.getBottom()
+ (int)(mAlarmWarning.getMeasuredHeight() * f);
if (DEBUG) log("mBottom (AW) = " + mBottom);
requestLayout();
}
}).start();
animate().alpha(alpha).start();
} else {
setAlpha(alpha);
requestLayout();

View File

@@ -35,23 +35,19 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
private final Handler mHandler = new Handler();
private final SettingsObserver mObserver;
private final List<ExitCondition> mExits = Arrays.asList(
newExit("Until you delete this", "Until", "You delete this"));
newExit("Until you turn this off", "Until", "You turn this off"));
private Callbacks mCallbacks;
private int mExitIndex;
private boolean mDeviceProvisioned;
private int mMode;
private int mCommittedMode;
public ZenModeViewAdapter(Context context) {
mContext = context;
mResolver = mContext.getContentResolver();
mObserver = new SettingsObserver(mHandler);
mObserver.init();
}
@Override
public boolean isApplicable() {
return mDeviceProvisioned;
init();
}
@Override
@@ -61,6 +57,18 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
@Override
public void setMode(int mode) {
if (mode == mMode) return;
mMode = mode;
dispatchChanged();
}
@Override
public int getCommittedMode() {
return mCommittedMode;
}
@Override
public void setCommittedMode(int mode) {
final int v = mode == MODE_LIMITED ? Settings.Global.ZEN_MODE_LIMITED
: mode == MODE_FULL ? Settings.Global.ZEN_MODE_FULL
: Settings.Global.ZEN_MODE_OFF;
@@ -74,12 +82,21 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
}
@Override
public void cancel() {
public void init() {
if (mExitIndex != 0) {
mExitIndex = 0;
mHandler.post(mChange);
dispatchChanged();
}
setMode(MODE_OFF);
final int mode = mCommittedMode == MODE_FULL ? MODE_FULL : MODE_LIMITED;
if (mode != mMode) {
mMode = mode;
dispatchChanged();
}
}
private void dispatchChanged() {
mHandler.removeCallbacks(mChanged);
mHandler.post(mChanged);
}
@Override
@@ -111,7 +128,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
return;
}
mExitIndex = i;
mHandler.post(mChange);
dispatchChanged();
}
private static ExitCondition newExit(String summary, String line1, String line2) {
@@ -122,7 +139,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
return rt;
}
private final Runnable mChange = new Runnable() {
private final Runnable mChanged = new Runnable() {
public void run() {
if (mCallbacks == null) {
return;
@@ -145,24 +162,19 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
mResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
false, this);
mResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
false, this);
}
@Override
public void onChange(boolean selfChange) {
loadSettings();
mChange.run(); // already on handler
mChanged.run(); // already on handler
}
private void loadSettings() {
mDeviceProvisioned = Settings.Global.getInt(mResolver,
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
mMode = getMode();
mCommittedMode = getModeFromSetting();
}
private int getMode() {
private int getModeFromSetting() {
final int v = Settings.Global.getInt(mResolver,
Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
if (v == Settings.Global.ZEN_MODE_LIMITED) return MODE_LIMITED;