summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src/com')
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterView.java805
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/EventLogTags.logtags25
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java6
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java549
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AdbOverNetworkTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CompassTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LiveDisplayTile.java223
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java5
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java116
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/MediaExpandableNotificationRow.java231
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/MediaNotificationGuts.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java254
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/QueueViewRow.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java136
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java698
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java216
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java226
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java349
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java118
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerService.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java1
66 files changed, 3840 insertions, 1611 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index e606156..06c2957 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013-14 The Android Open Source Project
+ * Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,43 +17,47 @@
package com.android.systemui;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryStateRegistar;
-
import android.animation.ArgbEvaluator;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.content.res.ThemeConfig;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.graphics.Typeface;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.os.BatteryManager;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
import android.view.View;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryStateRegistar;
+
+import org.cyanogenmod.graphics.drawable.StopMotionVectorDrawable;
+
public class BatteryMeterView extends View implements DemoMode,
BatteryController.BatteryStateChangeCallback {
public static final String TAG = BatteryMeterView.class.getSimpleName();
public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
- private static final int FULL = 96;
-
- private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
-
private final int[] mColors;
protected boolean mShowPercent = true;
- private float mButtonHeightFraction;
- private float mSubpixelSmoothingLeft;
- private float mSubpixelSmoothingRight;
public enum BatteryMeterMode {
BATTERY_METER_GONE,
@@ -66,14 +71,9 @@ public class BatteryMeterView extends View implements DemoMode,
private int mWidth;
private String mWarningString;
private final int mCriticalLevel;
- private final int mFrameColor;
private boolean mAnimationsEnabled;
- private final Path mShapePath = new Path();
- private final Path mClipPath = new Path();
- private final Path mTextPath = new Path();
-
private BatteryStateRegistar mBatteryStateRegistar;
private BatteryController mBatteryController;
private boolean mPowerSaveEnabled;
@@ -94,6 +94,9 @@ public class BatteryMeterView extends View implements DemoMode,
private BatteryMeterDrawable mBatteryMeterDrawable;
private int mIconTint = Color.WHITE;
+ private int mCurrentBackgroundColor = 0;
+ private int mCurrentFillColor = 0;
+
protected class BatteryTracker extends BroadcastReceiver {
public static final int UNKNOWN_LEVEL = -1;
@@ -225,8 +228,6 @@ public class BatteryMeterView extends View implements DemoMode,
final Resources res = context.getResources();
TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
defStyle, 0);
- mFrameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
- res.getColor(R.color.batterymeter_frame_color));
TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
@@ -242,12 +243,6 @@ public class BatteryMeterView extends View implements DemoMode,
mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
mCriticalLevel = getContext().getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
- mButtonHeightFraction = context.getResources().getFraction(
- R.fraction.battery_button_height_fraction, 1, 1);
- mSubpixelSmoothingLeft = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_left, 1, 1);
- mSubpixelSmoothingRight = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_right, 1, 1);
mDarkModeBackgroundColor =
context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
@@ -260,17 +255,13 @@ public class BatteryMeterView extends View implements DemoMode,
}
protected BatteryMeterDrawable createBatteryMeterDrawable(BatteryMeterMode mode) {
- Resources res = mContext.getResources();
+ Resources res = getResources();
switch (mode) {
- case BATTERY_METER_CIRCLE:
- return new CircleBatteryMeterDrawable(res);
- case BATTERY_METER_ICON_LANDSCAPE:
- return new NormalBatteryMeterDrawable(res, true);
case BATTERY_METER_TEXT:
case BATTERY_METER_GONE:
return null;
default:
- return new NormalBatteryMeterDrawable(res, false);
+ return new AllInOneBatteryMeterDrawable(res, mode);
}
}
@@ -279,13 +270,8 @@ public class BatteryMeterView extends View implements DemoMode,
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- if (mMeterMode == BatteryMeterMode.BATTERY_METER_CIRCLE) {
- height += (CircleBatteryMeterDrawable.STROKE_WITH / 3);
- width = height;
- } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_TEXT) {
+ if (mMeterMode == BatteryMeterMode.BATTERY_METER_TEXT) {
onSizeChanged(width, height, 0, 0); // Force a size changed event
- } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) {
- width = (int)(height * 1.2f);
}
setMeasuredDimension(width, height);
@@ -378,11 +364,6 @@ public class BatteryMeterView extends View implements DemoMode,
mBatteryMeterDrawable.onDispose();
}
mBatteryMeterDrawable = createBatteryMeterDrawable(mode);
- if (mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_PORTRAIT ||
- mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) {
- ((NormalBatteryMeterDrawable)mBatteryMeterDrawable).loadBoltPoints(
- mContext.getResources());
- }
if (tracker.present) {
setVisibility(View.VISIBLE);
requestLayout();
@@ -394,7 +375,6 @@ public class BatteryMeterView extends View implements DemoMode,
}
public int getColorForLevel(int percent) {
-
// If we are in power save mode, always use the normal color.
if (mPowerSaveEnabled) {
return mColors[mColors.length-1];
@@ -418,9 +398,9 @@ public class BatteryMeterView extends View implements DemoMode,
public void setDarkIntensity(float darkIntensity) {
if (mBatteryMeterDrawable != null) {
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- mBatteryMeterDrawable.setDarkIntensity(backgroundColor, fillColor);
+ mCurrentBackgroundColor = getBackgroundColor(darkIntensity);
+ mCurrentFillColor = getFillColor(darkIntensity);
+ mBatteryMeterDrawable.setDarkIntensity(mCurrentBackgroundColor, mCurrentFillColor);
}
}
@@ -482,253 +462,83 @@ public class BatteryMeterView extends View implements DemoMode,
void setDarkIntensity(int backgroundColor, int fillColor);
}
- protected class NormalBatteryMeterDrawable implements BatteryMeterDrawable {
+ protected class AllInOneBatteryMeterDrawable implements BatteryMeterDrawable {
private static final boolean SINGLE_DIGIT_PERCENT = false;
private static final boolean SHOW_100_PERCENT = false;
private boolean mDisposed;
- protected final boolean mHorizontal;
+ private boolean mIsAnimating; // stores charge-animation status to remove callbacks
+
+ private float mTextX, mTextY; // precalculated position for drawText() to appear centered
- private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
- private float mTextHeight, mWarningTextHeight;
+ private boolean mInitialized;
- private int mChargeColor;
- private final float[] mBoltPoints;
- private final Path mBoltPath = new Path();
+ private Paint mTextAndBoltPaint;
+ private Paint mWarningTextPaint;
+ private Paint mClearPaint;
- private final RectF mFrame = new RectF();
- private final RectF mButtonFrame = new RectF();
- private final RectF mBoltFrame = new RectF();
+ private LayerDrawable mBatteryDrawable;
+ private Drawable mFrameDrawable;
+ private StopMotionVectorDrawable mLevelDrawable;
+ private Drawable mBoltDrawable;
- public NormalBatteryMeterDrawable(Resources res, boolean horizontal) {
+ private BatteryMeterMode mMode;
+ private int mTextGravity;
+
+ public AllInOneBatteryMeterDrawable(Resources res, BatteryMeterMode mode) {
super();
- mHorizontal = horizontal;
- mDisposed = false;
- mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFramePaint.setColor(mFrameColor);
- mFramePaint.setDither(true);
- mFramePaint.setStrokeWidth(0);
- mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ loadBatteryDrawables(res, mode);
- mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBatteryPaint.setDither(true);
- mBatteryPaint.setStrokeWidth(0);
- mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ mMode = mode;
+ mDisposed = false;
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ // load text gravity and blend mode
+ int[] attrs = new int[] {android.R.attr.gravity, R.attr.blendMode};
+ int resId = getBatteryDrawableStyleResourceForMode(mode);
+ PorterDuff.Mode xferMode = PorterDuff.Mode.XOR;
+ if (resId != 0) {
+ TypedArray a = getContext().obtainStyledAttributes(
+ getBatteryDrawableStyleResourceForMode(mode), attrs);
+ mTextGravity = a.getInt(0, Gravity.CENTER);
+ xferMode = PorterDuff.intToMode(a.getInt(1,
+ PorterDuff.modeToInt(PorterDuff.Mode.XOR)));
+ } else {
+ mTextGravity = Gravity.CENTER;
+ }
+ Log.d(TAG, "mTextGravity=" + mTextGravity);
+
+ mTextAndBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
- mTextPaint.setTypeface(font);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
+ mTextAndBoltPaint.setTypeface(font);
+ mTextAndBoltPaint.setTextAlign(getPaintAlignmentFromGravity(mTextGravity));
+ mTextAndBoltPaint.setXfermode(new PorterDuffXfermode(xferMode));
+ mTextAndBoltPaint.setColor(mCurrentFillColor != 0
+ ? mCurrentFillColor
+ : res.getColor(R.color.batterymeter_bolt_color));
mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mWarningTextPaint.setColor(mColors[1]);
font = Typeface.create("sans-serif", Typeface.BOLD);
mWarningTextPaint.setTypeface(font);
- mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+ mWarningTextPaint.setTextAlign(getPaintAlignmentFromGravity(mTextGravity));
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
- mBoltPoints = loadBoltPoints(res);
+ mClearPaint = new Paint();
+ mClearPaint.setColor(0);
}
@Override
public void onDraw(Canvas c, BatteryTracker tracker) {
if (mDisposed) return;
- final int level = tracker.level;
-
- if (level == BatteryTracker.UNKNOWN_LEVEL) return;
-
- float drawFrac = (float) level / 100f;
- final int pt = getPaddingTop() + (mHorizontal ? (int)(mHeight * 0.12f) : 0);
- final int pl = getPaddingLeft();
- final int pr = getPaddingRight();
- final int pb = getPaddingBottom() + (mHorizontal ? (int)(mHeight * 0.08f) : 0);
- final int height = mHeight - pt - pb;
- final int width = mWidth - pl - pr;
-
- final int buttonHeight = (int) ((mHorizontal ? width : height) * mButtonHeightFraction);
-
- mFrame.set(0, 0, width, height);
- mFrame.offset(pl, pt);
-
- if (mHorizontal) {
- mButtonFrame.set(
- /*cover frame border of intersecting area*/
- width - buttonHeight - mFrame.left,
- mFrame.top + Math.round(height * 0.25f),
- mFrame.right,
- mFrame.bottom - Math.round(height * 0.25f));
-
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.bottom -= mSubpixelSmoothingRight;
- mButtonFrame.right -= mSubpixelSmoothingRight;
- } else {
- // button-frame: area above the battery body
- mButtonFrame.set(
- mFrame.left + Math.round(width * 0.25f),
- mFrame.top,
- mFrame.right - Math.round(width * 0.25f),
- mFrame.top + buttonHeight);
-
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.left += mSubpixelSmoothingLeft;
- mButtonFrame.right -= mSubpixelSmoothingRight;
- }
-
- // frame: battery body area
-
- if (mHorizontal) {
- mFrame.right -= buttonHeight;
- } else {
- mFrame.top += buttonHeight;
- }
- mFrame.left += mSubpixelSmoothingLeft;
- mFrame.top += mSubpixelSmoothingLeft;
- mFrame.right -= mSubpixelSmoothingRight;
- mFrame.bottom -= mSubpixelSmoothingRight;
-
- // set the battery charging color
- mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level));
-
- if (level >= FULL) {
- drawFrac = 1f;
- } else if (level <= mCriticalLevel) {
- drawFrac = 0f;
- }
-
- final float levelTop;
-
- if (drawFrac == 1f) {
- if (mHorizontal) {
- levelTop = mButtonFrame.right;
- } else {
- levelTop = mButtonFrame.top;
- }
- } else {
- if (mHorizontal) {
- levelTop = (mFrame.right - (mFrame.width() * (1f - drawFrac)));
- } else {
- levelTop = (mFrame.top + (mFrame.height() * (1f - drawFrac)));
- }
- }
-
- // define the battery shape
- mShapePath.reset();
- mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
- if (mHorizontal) {
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.bottom);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.bottom);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
- } else {
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+ if (!mInitialized) {
+ init();
}
- if (tracker.plugged) {
- // define the bolt shape
- final float bl = mFrame.left + mFrame.width() / (mHorizontal ? 9f : 4.5f);
- final float bt = mFrame.top + mFrame.height() / (mHorizontal ? 4.5f : 6f);
- final float br = mFrame.right - mFrame.width() / (mHorizontal ? 6f : 7f);
- final float bb = mFrame.bottom - mFrame.height() / (mHorizontal ? 7f : 10f);
- if (mBoltFrame.left != bl || mBoltFrame.top != bt
- || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
- mBoltFrame.set(bl, bt, br, bb);
- mBoltPath.reset();
- mBoltPath.moveTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- for (int i = 2; i < mBoltPoints.length; i += 2) {
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
- }
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- }
-
- float boltPct = mHorizontal ?
- (mBoltFrame.left - levelTop) / (mBoltFrame.left - mBoltFrame.right) :
- (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mBoltPath, mBoltPaint);
- } else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
- }
- }
-
- // compute percentage text
- boolean pctOpaque = false;
- float pctX = 0, pctY = 0;
- String pctText = null;
- if (!tracker.plugged && level > mCriticalLevel && mShowPercent) {
- mTextPaint.setColor(getColorForLevel(level));
- final float full = mHorizontal ? 0.60f : 0.45f;
- final float nofull = mHorizontal ? 0.75f : 0.6f;
- final float single = mHorizontal ? 0.86f : 0.75f;
- mTextPaint.setTextSize(height *
- (SINGLE_DIGIT_PERCENT ? single
- : (tracker.level == 100 ? full : nofull)));
- mTextHeight = -mTextPaint.getFontMetrics().ascent;
- pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
- pctX = mWidth * 0.5f;
- pctY = (mHeight + mTextHeight) * 0.47f;
- if (mHorizontal) {
- pctOpaque = pctX > levelTop;
- } else {
- pctOpaque = levelTop > pctY;
- }
- if (!pctOpaque) {
- mTextPath.reset();
- mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
- // cut the percentage text out of the overall shape
- mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
- }
- }
-
- // draw the battery shape background
- c.drawPath(mShapePath, mFramePaint);
-
- // draw the battery shape, clipped to charging level
- if (mHorizontal) {
- mFrame.right = levelTop;
- } else {
- mFrame.top = levelTop;
- }
- mClipPath.reset();
- mClipPath.addRect(mFrame, Path.Direction.CCW);
- mShapePath.op(mClipPath, Path.Op.INTERSECT);
- c.drawPath(mShapePath, mBatteryPaint);
-
- if (!tracker.plugged) {
- if (level <= mCriticalLevel) {
- // draw the warning text
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (pctOpaque) {
- // draw the percentage text
- c.drawText(pctText, pctX, pctY, mTextPaint);
- }
+ drawBattery(c, tracker);
+ if (mAnimationsEnabled) {
+ // TODO: Allow custom animations to be used
}
}
@@ -740,282 +550,293 @@ public class BatteryMeterView extends View implements DemoMode,
@Override
public void setDarkIntensity(int backgroundColor, int fillColor) {
mIconTint = fillColor;
- mFramePaint.setColor(backgroundColor);
- mBoltPaint.setColor(fillColor);
- mChargeColor = fillColor;
+ // Make bolt fully opaque for increased visibility
+ mBoltDrawable.setTint(0xff000000 | fillColor);
+ mFrameDrawable.setTint(backgroundColor);
+ updateBoltDrawableLayer(mBatteryDrawable, mBoltDrawable);
invalidate();
}
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
- mHeight = h;
- mWidth = w;
- mWarningTextPaint.setTextSize(h * 0.75f);
- mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
- }
-
- private float[] loadBoltPoints(Resources res) {
- final int[] pts = res.getIntArray(getBoltPointsArrayResource());
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
- }
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
- }
- return ptsF;
+ init();
}
- protected int getBoltPointsArrayResource() {
- return mHorizontal
- ? R.array.batterymeter_inverted_bolt_points
- : R.array.batterymeter_bolt_points;
+ private boolean isThemeApplied() {
+ ThemeConfig themeConfig = ThemeConfig.getBootTheme(getContext().getContentResolver());
+ return themeConfig != null &&
+ !ThemeConfig.SYSTEM_DEFAULT.equals(themeConfig.getOverlayForStatusBar());
}
- }
- protected class CircleBatteryMeterDrawable implements BatteryMeterDrawable {
- private static final boolean SINGLE_DIGIT_PERCENT = false;
- private static final boolean SHOW_100_PERCENT = false;
-
- private static final int FULL = 96;
+ private void checkBatteryMeterDrawableValid(Resources res, BatteryMeterMode mode) {
+ final int resId = getBatteryDrawableResourceForMode(mode);
+ final Drawable batteryDrawable;
+ try {
+ batteryDrawable = res.getDrawable(resId);
+ } catch (Resources.NotFoundException e) {
+ throw new BatteryMeterDrawableException(res.getResourceName(resId) + " is an " +
+ "invalid drawable", e);
+ }
- public static final float STROKE_WITH = 6.5f;
+ // check that the drawable is a LayerDrawable
+ if (!(batteryDrawable instanceof LayerDrawable)) {
+ throw new BatteryMeterDrawableException("Expected a LayerDrawable but received a " +
+ batteryDrawable.getClass().getSimpleName());
+ }
- private boolean mDisposed;
+ final LayerDrawable layerDrawable = (LayerDrawable) batteryDrawable;
+ final Drawable frame = layerDrawable.findDrawableByLayerId(R.id.battery_frame);
+ final Drawable level = layerDrawable.findDrawableByLayerId(R.id.battery_fill);
+ final Drawable bolt = layerDrawable.findDrawableByLayerId(
+ R.id.battery_charge_indicator);
+ // now check that the required layers exist and are of the correct type
+ if (frame == null) {
+ throw new BatteryMeterDrawableException("Missing battery_frame drawble");
+ }
+ if (bolt == null) {
+ throw new BatteryMeterDrawableException(
+ "Missing battery_charge_indicator drawable");
+ }
+ if (level != null) {
+ // check that the level drawable is an AnimatedVectorDrawable
+ if (!(level instanceof AnimatedVectorDrawable)) {
+ throw new BatteryMeterDrawableException("Expected a AnimatedVectorDrawable " +
+ "but received a " + level.getClass().getSimpleName());
+ }
+ // make sure we can stop motion animate the level drawable
+ try {
+ StopMotionVectorDrawable smvd = new StopMotionVectorDrawable(level);
+ smvd.setCurrentFraction(0.5f);
+ } catch (Exception e) {
+ throw new BatteryMeterDrawableException("Unable to perform stop motion on " +
+ "battery_fill drawable", e);
+ }
+ } else {
+ throw new BatteryMeterDrawableException("Missing battery_fill drawable");
+ }
+ }
- private int mAnimOffset;
- private boolean mIsAnimating; // stores charge-animation status to reliably
- //remove callbacks
+ private void loadBatteryDrawables(Resources res, BatteryMeterMode mode) {
+ if (isThemeApplied()) {
+ try {
+ checkBatteryMeterDrawableValid(res, mode);
+ } catch (BatteryMeterDrawableException e) {
+ Log.w(TAG, "Invalid themed battery meter drawable, falling back to system", e);
+ final Context context = getContext();
+ PackageManager pm = getContext().getPackageManager();
+ try {
+ res = pm.getThemedResourcesForApplication(context.getPackageName(),
+ ThemeConfig.SYSTEM_DEFAULT);
+ } catch (PackageManager.NameNotFoundException nnfe) {
+ /* ignore, this should not happen */
+ }
+ }
+ }
- private int mCircleSize; // draw size of circle
- private RectF mRectLeft; // contains the precalculated rect used in drawArc(),
- // derived from mCircleSize
- private float mTextX, mTextY; // precalculated position for drawText() to appear centered
+ int drawableResId = getBatteryDrawableResourceForMode(mode);
+ mBatteryDrawable = (LayerDrawable) res.getDrawable(drawableResId);
+ mFrameDrawable = mBatteryDrawable.findDrawableByLayerId(R.id.battery_frame);
+ mFrameDrawable.setTint(mCurrentBackgroundColor != 0
+ ? mCurrentBackgroundColor
+ : res.getColor(R.color.batterymeter_frame_color));
+ // set the animated vector drawable we will be stop animating
+ Drawable levelDrawable = mBatteryDrawable.findDrawableByLayerId(R.id.battery_fill);
+ mLevelDrawable = new StopMotionVectorDrawable(levelDrawable);
+ mBoltDrawable = mBatteryDrawable.findDrawableByLayerId(R.id.battery_charge_indicator);
+ }
- private Paint mTextPaint;
- private Paint mFrontPaint;
- private Paint mBackPaint;
- private Paint mBoltPaint;
- private Paint mWarningTextPaint;
+ private void drawBattery(Canvas canvas, BatteryTracker tracker) {
+ boolean unknownStatus = tracker.status == BatteryManager.BATTERY_STATUS_UNKNOWN;
+ int level = tracker.level;
- private final RectF mBoltFrame = new RectF();
+ if (unknownStatus || tracker.status == BatteryManager.BATTERY_STATUS_FULL) {
+ level = 100;
+ }
- private int mChargeColor;
- private final float[] mBoltPoints;
- private final Path mBoltPath = new Path();
+ mTextAndBoltPaint.setColor(getColorForLevel(level));
- public CircleBatteryMeterDrawable(Resources res) {
- super();
- mDisposed = false;
+ // Make sure we don't draw the charge indicator if not plugged in
+ Drawable d = mBatteryDrawable.findDrawableByLayerId(R.id.battery_charge_indicator);
+ if (d instanceof BitmapDrawable) {
+ // In case we are using a BitmapDrawable, which we should be unless something bad
+ // happened, we need to change the paint rather than the alpha in case the blendMode
+ // has been set to clear. Clear always clears regardless of alpha level ;)
+ BitmapDrawable bd = (BitmapDrawable) d;
+ bd.getPaint().set(tracker.plugged ? mTextAndBoltPaint : mClearPaint);
+ } else {
+ d.setAlpha(tracker.plugged ? 255 : 0);
+ }
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
- mTextPaint.setTypeface(font);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mFrontPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFrontPaint.setStrokeCap(Paint.Cap.BUTT);
- mFrontPaint.setDither(true);
- mFrontPaint.setStrokeWidth(0);
- mFrontPaint.setStyle(Paint.Style.STROKE);
-
- mBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBackPaint.setColor(res.getColor(R.color.batterymeter_frame_color));
- mBackPaint.setStrokeCap(Paint.Cap.BUTT);
- mBackPaint.setDither(true);
- mBackPaint.setStrokeWidth(0);
- mBackPaint.setStyle(Paint.Style.STROKE);
+ // Now draw the level indicator
+ // set the level and tint color of the fill drawable
+ mLevelDrawable.setCurrentFraction(level / 100f);
+ mLevelDrawable.setTint(getColorForLevel(level));
+ mBatteryDrawable.draw(canvas);
- mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mWarningTextPaint.setColor(mColors[1]);
- font = Typeface.create("sans-serif", Typeface.BOLD);
- mWarningTextPaint.setTypeface(font);
- mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+ // if chosen by options, draw percentage text in the middle
+ // always skip percentage when 100, so layout doesnt break
+ if (unknownStatus) {
+ mTextAndBoltPaint.setColor(getContext().getColor(R.color.batterymeter_frame_color));
+ canvas.drawText("?", mTextX, mTextY, mTextAndBoltPaint);
- mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+ } else if (!tracker.plugged) {
+ drawPercentageText(canvas, tracker);
+ }
+ }
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
- mBoltPoints = loadBoltPoints(res);
+ private void drawPercentageText(Canvas canvas, BatteryTracker tracker) {
+ final int level = tracker.level;
+ if (level > mCriticalLevel
+ && (mShowPercent && !(level == 100 && !SHOW_100_PERCENT))) {
+ // draw the percentage text
+ String pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+ mTextAndBoltPaint.setColor(getColorForLevel(level));
+ canvas.drawText(pctText, mTextX, mTextY, mTextAndBoltPaint);
+ } else if (level <= mCriticalLevel) {
+ // draw the warning text
+ canvas.drawText(mWarningString, mTextX, mTextY, mWarningTextPaint);
+ }
}
- @Override
- public void onDraw(Canvas c, BatteryTracker tracker) {
- if (mDisposed) return;
+ /**
+ * initializes all size dependent variables
+ */
+ private void init() {
+ // not much we can do with zero width or height, we'll get another pass later
+ if (mWidth <= 0 || mHeight <=0) return;
+
+ final float widthDiv2 = mWidth / 2f;
+ // text size is width / 2 - 2dp for wiggle room
+ final float textSize = widthDiv2 - getResources().getDisplayMetrics().density * 2;
+ mTextAndBoltPaint.setTextSize(textSize);
+ mWarningTextPaint.setTextSize(textSize);
+
+ int pLeft = getPaddingLeft();
+ Rect iconBounds = new Rect(pLeft, 0, pLeft + mWidth, mHeight);
+ mBatteryDrawable.setBounds(iconBounds);
- if (mRectLeft == null) {
- initSizeBasedStuff();
+ // calculate text position
+ Rect bounds = new Rect();
+ mTextAndBoltPaint.getTextBounds("99", 0, "99".length(), bounds);
+ boolean isRtl = isLayoutRtl();
+
+ // compute mTextX based on text gravity
+ if ((mTextGravity & Gravity.START) == Gravity.START) {
+ mTextX = isRtl ? mWidth : 0;
+ } else if ((mTextGravity & Gravity.END) == Gravity.END) {
+ mTextX = isRtl ? 0 : mWidth;
+ } else if ((mTextGravity & Gravity.LEFT) == Gravity.LEFT) {
+ mTextX = 0;
+ }else if ((mTextGravity & Gravity.RIGHT) == Gravity.RIGHT) {
+ mTextX = mWidth;
+ } else {
+ mTextX = widthDiv2 + pLeft;
}
- drawCircle(c, tracker, mTextX, mRectLeft);
- if (mAnimationsEnabled) {
- updateChargeAnim(tracker);
+ // compute mTextY based on text gravity
+ if ((mTextGravity & Gravity.TOP) == Gravity.TOP) {
+ mTextY = bounds.height();
+ } else if ((mTextGravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
+ mTextY = mHeight;
+ } else {
+ mTextY = widthDiv2 + bounds.height() / 2.0f;
}
- }
- @Override
- public void onDispose() {
- mDisposed = true;
+ updateBoltDrawableLayer(mBatteryDrawable, mBoltDrawable);
+
+ mInitialized = true;
}
- @Override
- public void setDarkIntensity(int backgroundColor, int fillColor) {
- mIconTint = fillColor;
- mBoltPaint.setColor(fillColor);
- mChargeColor = fillColor;
- invalidate();
+ private int getBatteryDrawableResourceForMode(BatteryMeterMode mode) {
+ switch (mode) {
+ case BATTERY_METER_ICON_LANDSCAPE:
+ return R.drawable.ic_battery_landscape;
+ case BATTERY_METER_CIRCLE:
+ return R.drawable.ic_battery_circle;
+ case BATTERY_METER_ICON_PORTRAIT:
+ return R.drawable.ic_battery_portrait;
+ default:
+ return 0;
+ }
}
- @Override
- public void onSizeChanged(int w, int h, int oldw, int oldh) {
- initSizeBasedStuff();
+ private int getBatteryDrawableStyleResourceForMode(BatteryMeterMode mode) {
+ switch (mode) {
+ case BATTERY_METER_ICON_LANDSCAPE:
+ return R.style.BatteryMeterViewDrawable_Landscape;
+ case BATTERY_METER_CIRCLE:
+ return R.style.BatteryMeterViewDrawable_Circle;
+ case BATTERY_METER_ICON_PORTRAIT:
+ return R.style.BatteryMeterViewDrawable_Portrait;
+ default:
+ return R.style.BatteryMeterViewDrawable;
+ }
}
- private float[] loadBoltPoints(Resources res) {
- final int[] pts = res.getIntArray(getBoltPointsArrayResource());
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
+ private Paint.Align getPaintAlignmentFromGravity(int gravity) {
+ boolean isRtl = isLayoutRtl();
+ if ((gravity & Gravity.START) == Gravity.START) {
+ return isRtl ? Paint.Align.RIGHT : Paint.Align.LEFT;
}
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
+ if ((gravity & Gravity.END) == Gravity.END) {
+ return isRtl ? Paint.Align.LEFT : Paint.Align.RIGHT;
}
- return ptsF;
- }
+ if ((gravity & Gravity.LEFT) == Gravity.LEFT) return Paint.Align.LEFT;
+ if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) return Paint.Align.RIGHT;
- protected int getBoltPointsArrayResource() {
- return R.array.batterymeter_bolt_points;
+ // default to center
+ return Paint.Align.CENTER;
}
- private void drawCircle(Canvas canvas, BatteryTracker tracker,
- float textX, RectF drawRect) {
- boolean unknownStatus = tracker.status == BatteryManager.BATTERY_STATUS_UNKNOWN;
- int level = tracker.level;
- Paint paint;
-
- if (unknownStatus) {
- paint = mBackPaint;
- level = 100; // Draw all the circle;
+ // Creates a BitmapDrawable of the bolt so we can make use of the XOR xfer mode with vector
+ // based drawables
+ private void updateBoltDrawableLayer(LayerDrawable batteryDrawable, Drawable boltDrawable) {
+ BitmapDrawable newBoltDrawable;
+ if (boltDrawable instanceof BitmapDrawable) {
+ newBoltDrawable = (BitmapDrawable) boltDrawable.mutate();
} else {
- paint = mFrontPaint;
- paint.setColor(getColorForLevel(level));
- if (tracker.status == BatteryManager.BATTERY_STATUS_FULL) {
- level = 100;
+ Bitmap boltBitmap = createBoltBitmap(boltDrawable);
+ if (boltBitmap == null) {
+ // not much to do with a null bitmap so keep original bolt for now
+ return;
}
+ Rect bounds = boltDrawable.getBounds();
+ newBoltDrawable = new BitmapDrawable(getResources(), boltBitmap);
+ newBoltDrawable.setBounds(bounds);
}
-
- // draw thin gray ring first
- canvas.drawArc(drawRect, 270, 360, false, mBackPaint);
- if (level != 0) {
- // draw colored arc representing charge level
- canvas.drawArc(drawRect, 270 + mAnimOffset, 3.6f * level, false, paint);
- }
- // if chosen by options, draw percentage text in the middle
- // always skip percentage when 100, so layout doesnt break
- if (unknownStatus) {
- mTextPaint.setColor(paint.getColor());
- canvas.drawText("?", textX, mTextY, mTextPaint);
-
- } else if (tracker.plugged) {
- canvas.drawPath(mBoltPath, mBoltPaint);
- } else {
- if (level > mCriticalLevel
- && (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT))) {
- // draw the percentage text
- String pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
- mTextPaint.setColor(paint.getColor());
- canvas.drawText(pctText, textX, mTextY, mTextPaint);
- } else if (level <= mCriticalLevel) {
- // draw the warning text
- canvas.drawText(mWarningString, textX, mTextY, mWarningTextPaint);
+ newBoltDrawable.getPaint().set(mTextAndBoltPaint);
+ batteryDrawable.setDrawableByLayerId(R.id.battery_charge_indicator, newBoltDrawable);
+ }
+
+ private Bitmap createBoltBitmap(Drawable boltDrawable) {
+ // not much we can do with zero width or height, we'll get another pass later
+ if (mWidth <= 0 || mHeight <= 0) return null;
+
+ Bitmap bolt;
+ if (!(boltDrawable instanceof BitmapDrawable)) {
+ int pLeft = getPaddingLeft();
+ Rect iconBounds = new Rect(pLeft, 0, pLeft + mWidth, mHeight);
+ bolt = Bitmap.createBitmap(iconBounds.width(), iconBounds.height(),
+ Bitmap.Config.ARGB_8888);
+ if (bolt != null) {
+ Canvas c = new Canvas(bolt);
+ c.drawColor(-1, PorterDuff.Mode.CLEAR);
+ boltDrawable.draw(c);
}
- }
- }
-
- /**
- * updates the animation counter
- * cares for timed callbacks to continue animation cycles
- * uses mInvalidate for delayed invalidate() callbacks
- */
- private void updateChargeAnim(BatteryTracker tracker) {
- // Stop animation when battery is full or after the meter
- // rotated back to 0 after unplugging.
- if (!tracker.shouldIndicateCharging()
- || tracker.status == BatteryManager.BATTERY_STATUS_FULL
- || tracker.level == 0) {
- mIsAnimating = false;
} else {
- mIsAnimating = true;
- }
-
- if (mAnimOffset > 360) {
- mAnimOffset = 0;
- }
-
- boolean continueAnimation = mIsAnimating || mAnimOffset != 0;
-
- if (continueAnimation) {
- mAnimOffset += 3;
+ bolt = ((BitmapDrawable) boltDrawable).getBitmap();
}
- if (continueAnimation) {
- postInvalidateDelayed(50);
- }
+ return bolt;
}
- /**
- * initializes all size dependent variables
- * sets stroke width and text size of all involved paints
- * YES! i think the method name is appropriate
- */
- private void initSizeBasedStuff() {
- mCircleSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
- mTextPaint.setTextSize(mCircleSize / 2f);
- mWarningTextPaint.setTextSize(mCircleSize / 2f);
-
- float strokeWidth = mCircleSize / STROKE_WITH;
- mFrontPaint.setStrokeWidth(strokeWidth);
- mBackPaint.setStrokeWidth(strokeWidth);
-
- // calculate rectangle for drawArc calls
- int pLeft = getPaddingLeft();
- mRectLeft = new RectF(pLeft + strokeWidth / 2.0f, 0 + strokeWidth / 2.0f, mCircleSize
- - strokeWidth / 2.0f + pLeft, mCircleSize - strokeWidth / 2.0f);
+ private class BatteryMeterDrawableException extends RuntimeException {
+ public BatteryMeterDrawableException(String detailMessage) {
+ super(detailMessage);
+ }
- // calculate Y position for text
- Rect bounds = new Rect();
- mTextPaint.getTextBounds("99", 0, "99".length(), bounds);
- mTextX = mCircleSize / 2.0f + getPaddingLeft();
- // the +1dp at end of formula balances out rounding issues.works out on all resolutions
- mTextY = mCircleSize / 2.0f + (bounds.bottom - bounds.top) / 2.0f
- - strokeWidth / 2.0f + getResources().getDisplayMetrics().density;
-
- // draw the bolt
- final float bl = (int) (mRectLeft.left + mRectLeft.width() / 3.2f);
- final float bt = (int) (mRectLeft.top + mRectLeft.height() / 4f);
- final float br = (int) (mRectLeft.right - mRectLeft.width() / 5.2f);
- final float bb = (int) (mRectLeft.bottom - mRectLeft.height() / 8f);
- if (mBoltFrame.left != bl || mBoltFrame.top != bt
- || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
- mBoltFrame.set(bl, bt, br, bb);
- mBoltPath.reset();
- mBoltPath.moveTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- for (int i = 2; i < mBoltPoints.length; i += 2) {
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
- }
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ public BatteryMeterDrawableException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java
index b80e6d0..a29b16c 100755
--- a/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java
@@ -18,7 +18,6 @@ package com.android.systemui;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.os.BatteryManager;
import android.util.AttributeSet;
import android.view.View;
@@ -148,45 +147,4 @@ public class DockBatteryMeterView extends BatteryMeterView {
setVisibility(View.GONE);
}
}
-
- @Override
- protected BatteryMeterDrawable createBatteryMeterDrawable(BatteryMeterMode mode) {
- Resources res = mContext.getResources();
- switch (mode) {
- case BATTERY_METER_CIRCLE:
- return new DockCircleBatteryMeterDrawable(res);
- case BATTERY_METER_ICON_LANDSCAPE:
- return new DockNormalBatteryMeterDrawable(res, true);
- case BATTERY_METER_TEXT:
- case BATTERY_METER_GONE:
- return null;
- default:
- return new DockNormalBatteryMeterDrawable(res, false);
- }
- }
-
- protected class DockNormalBatteryMeterDrawable extends NormalBatteryMeterDrawable {
-
- public DockNormalBatteryMeterDrawable(Resources res, boolean horizontal) {
- super(res, horizontal);
- }
-
- @Override
- protected int getBoltPointsArrayResource() {
- return mHorizontal
- ? R.array.dockbatterymeter_inverted_bolt_points
- : R.array.dockbatterymeter_bolt_points;
- }
- }
-
- protected class DockCircleBatteryMeterDrawable extends CircleBatteryMeterDrawable {
- public DockCircleBatteryMeterDrawable(Resources res) {
- super(res);
- }
-
- @Override
- protected int getBoltPointsArrayResource() {
- return R.array.dockbatterymeter_bolt_points;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index a584cf6..a08d4b7 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -51,3 +51,28 @@ option java_package com.android.systemui;
# SearchPanelView.java
# ---------------------------
36050 sysui_searchpanel_touch (type|1),(x|1),(y|1)
+
+# ---------------------------
+# LiveLockScreenController.java
+# ---------------------------
+# sysui_lls_keyguard_showing
+## screenOn: 0:screen turned off
+## 1:screen turned on
+36060 sysui_lls_keyguard_showing (screenOn|1)
+# sysui_lls_keyguard_dismissed: Logged when user unlocks the device
+## onLls: 0:dismissed while showing notifications
+## 1:dismissed while user interacting with LLS
+36061 sysui_lls_keyguard_dismissed (onLls|1)
+# sysui_lls_notification_panel_shown: Logged when the notification panel is swiped in and out
+## shown: 0:panel is hidden
+## 1:panel is visible
+36062 sysui_lls_notification_panel_shown (shown|1)
+
+# ---------------------------
+# RecentsView.java
+# ---------------------------
+36070 sysui_recents_event (what|1)
+## what: 1: OPEN
+## 2: CLOSE
+## 3: CHOSE_TASK
+## 4: CLOSE_ALL_TASKS
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 1dca149..5911916 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -36,6 +36,7 @@ import android.view.ViewConfiguration;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.MediaExpandableNotificationRow;
import com.android.systemui.statusbar.policy.ScrollAdapter;
public class ExpandHelper implements Gefingerpoken {
@@ -96,7 +97,7 @@ public class ExpandHelper implements Gefingerpoken {
private float mCurrentHeight;
private int mSmallSize;
- private int mLargeSize;
+ private int mLargeSize, mInitialLargeSize;
private float mMaximumStretch;
private boolean mOnlyMovements;
@@ -161,6 +162,7 @@ public class ExpandHelper implements Gefingerpoken {
mSmallSize = small;
mMaximumStretch = mSmallSize * STRETCH_INTERVAL;
mLargeSize = large;
+ mInitialLargeSize = large;
mContext = context;
mCallback = callback;
mScaler = new ViewScaler();
@@ -511,7 +513,14 @@ public class ExpandHelper implements Gefingerpoken {
mCurrentHeight = mOldHeight;
if (mCallback.canChildBeExpanded(v)) {
if (DEBUG) Log.d(TAG, "working on an expandable child");
- mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
+ if (v instanceof MediaExpandableNotificationRow) {
+ final int maxHeight = ((MediaExpandableNotificationRow) v).getMaxContentHeight();
+ mLargeSize = maxHeight;
+ mNaturalHeight = maxHeight;
+ } else {
+ mLargeSize = mInitialLargeSize;
+ mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
+ }
} else {
if (DEBUG) Log.d(TAG, "working on a non-expandable child");
mNaturalHeight = mOldHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33f6564..c3e5043 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -45,9 +45,15 @@ public class SwipeHelper implements Gefingerpoken {
public static final int X = 0;
public static final int Y = 1;
+ public static final int SWIPE_ZONE_LEFT = 0x1;
+ public static final int SWIPE_ZONE_RIGHT = 0x2;
+ public static final int SWIPE_ZONE_TOP = 0x4;
+ public static final int SWIPE_ZONE_BOTTOM = 0x8;
private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
private final Interpolator mFastOutLinearInInterpolator;
+ private final int mTouchSlop;
+ private int mSwipeZone;
private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
@@ -69,6 +75,7 @@ public class SwipeHelper implements Gefingerpoken {
private VelocityTracker mVelocityTracker;
private float mInitialTouchPos;
+ private float mPerpendicularInitialTouchPos;
private boolean mDragging;
private View mCurrView;
private View mCurrAnimView;
@@ -84,6 +91,8 @@ public class SwipeHelper implements Gefingerpoken {
private int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
+ private float mSwipeProgressFadeEnd;
+
public SwipeHelper(int swipeDirection, Callback callback, Context context) {
mCallback = callback;
mHandler = new Handler();
@@ -91,12 +100,28 @@ public class SwipeHelper implements Gefingerpoken {
mVelocityTracker = VelocityTracker.obtain();
mDensityScale = context.getResources().getDisplayMetrics().density;
mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
android.R.interpolator.fast_out_linear_in);
mFalsingThreshold = context.getResources().getDimensionPixelSize(
R.dimen.swipe_helper_falsing_threshold);
+ if (swipeDirection == X) {
+ mSwipeZone = SWIPE_ZONE_LEFT | SWIPE_ZONE_RIGHT;
+ } else {
+ mSwipeZone = SWIPE_ZONE_TOP | SWIPE_ZONE_BOTTOM;
+ }
+ mSwipeProgressFadeEnd = SWIPE_PROGRESS_FADE_END;
+ }
+
+ public SwipeHelper(int swipeDirection, int swipeZone, Callback callback, Context context) {
+ this(swipeDirection, callback, context);
+ mSwipeZone = swipeZone;
+ }
+
+ public boolean isDragging() {
+ return mDragging;
}
public void setLongPressListener(LongPressListener listener) {
@@ -115,6 +140,10 @@ public class SwipeHelper implements Gefingerpoken {
return mSwipeDirection == X ? ev.getX() : ev.getY();
}
+ private float getPerpendicularPos(MotionEvent ev) {
+ return mSwipeDirection == X ? ev.getY() : ev.getX();
+ }
+
private float getTranslation(View v) {
return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
}
@@ -158,7 +187,7 @@ public class SwipeHelper implements Gefingerpoken {
private float getSwipeProgressForOffset(View view) {
float viewSize = getSize(view);
- final float fadeSize = SWIPE_PROGRESS_FADE_END * viewSize;
+ final float fadeSize = mSwipeProgressFadeEnd * viewSize;
float result = 1.0f;
float pos = getTranslation(view);
if (pos >= viewSize * SWIPE_PROGRESS_FADE_START) {
@@ -236,6 +265,7 @@ public class SwipeHelper implements Gefingerpoken {
mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
mVelocityTracker.addMovement(ev);
mInitialTouchPos = getPos(ev);
+ mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
if (mLongPressListener != null) {
if (mWatchLongPress == null) {
@@ -413,11 +443,30 @@ public class SwipeHelper implements Gefingerpoken {
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_MOVE:
if (mCurrView != null) {
+ float pos = getPos(ev);
+ float altPos = getPerpendicularPos(ev);
float delta = getPos(ev) - mInitialTouchPos;
float absDelta = Math.abs(delta);
if (absDelta >= getFalsingThreshold()) {
mTouchAboveFalsingThreshold = true;
}
+
+ boolean touchBeyondZoneLimit = true;
+ if (mSwipeDirection == X) {
+ if ((mSwipeZone & SWIPE_ZONE_RIGHT) == 0 && pos > mInitialTouchPos) {
+ touchBeyondZoneLimit = false;
+ } else if ((mSwipeZone & SWIPE_ZONE_LEFT) == 0 && pos < mInitialTouchPos) {
+ touchBeyondZoneLimit = false;
+ }
+ } else {
+ if ((mSwipeZone & SWIPE_ZONE_TOP) == 0 && altPos < mPerpendicularInitialTouchPos) {
+ touchBeyondZoneLimit = false;
+ } else if ((mSwipeZone & SWIPE_ZONE_BOTTOM) == 0 && pos > mInitialTouchPos) {
+ touchBeyondZoneLimit = false;
+ }
+ }
+ if (!touchBeyondZoneLimit) return false;
+
// don't let items that can't be dismissed be dragged more than
// maxScrollDistance
if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
@@ -470,6 +519,10 @@ public class SwipeHelper implements Gefingerpoken {
return true;
}
+ public void setSwipeProgressFadeEnd(float end) {
+ mSwipeProgressFadeEnd = end;
+ }
+
private int getFalsingThreshold() {
float factor = mCallback.getFalsingThresholdFactor();
return (int) (mFalsingThreshold * factor);
@@ -505,6 +558,49 @@ public class SwipeHelper implements Gefingerpoken {
float getFalsingThresholdFactor();
}
+ public static abstract class SimpleCallback implements Callback {
+ public abstract View getChildAtPosition(MotionEvent ev);
+ public abstract View getChildContentView(View v);
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return false;
+ }
+
+ @Override
+ public boolean isAntiFalsingNeeded() {
+ return false;
+ }
+
+ @Override
+ public void onBeginDrag(View v) {
+ }
+
+ @Override
+ public void onChildDismissed(View v) {
+ }
+
+ @Override
+ public void onDragCancelled(View v) {
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
+ @Override
+ public boolean updateSwipeProgress(View animView,
+ boolean dismissable,
+ float swipeProgress) {
+ return false;
+ }
+
+ @Override
+ public float getFalsingThresholdFactor() {
+ return 0;
+ }
+ }
+
/**
* Equivalent to View.OnLongClickListener with coordinates
*/
diff --git a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java
index d8cfa5e..3cd86fe 100644
--- a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java
@@ -1,5 +1,6 @@
package com.android.systemui.cm;
+import com.android.internal.app.AssistUtils;
import com.android.settingslib.cm.ShortcutPickHelper;
import com.android.systemui.R;
import com.android.systemui.cm.LockscreenShortcutsHelper.Shortcuts;
@@ -34,6 +35,7 @@ public class LockscreenShortcutsActivity extends Activity implements View.OnClic
private View mSelectedView;
private ColorMatrixColorFilter mFilter;
private ColorStateList mDefaultTintList;
+ private AssistUtils mAssistUtils;
@Override
public void shortcutPicked(String uri, String friendlyName, boolean isApplication) {
@@ -107,6 +109,7 @@ public class LockscreenShortcutsActivity extends Activity implements View.OnClic
mFilter = new ColorMatrixColorFilter(cm);
ImageView unlockButton = (ImageView) findViewById(R.id.middle_button);
mDefaultTintList = unlockButton.getImageTintList();
+ mAssistUtils = new AssistUtils(this);
createActionList();
initiateViews();
updateDrawables();
@@ -146,19 +149,40 @@ public class LockscreenShortcutsActivity extends Activity implements View.OnClic
if (mShortcutHelper.isTargetEmpty(shortcut)) {
drawable = getResources().getDrawable(R.drawable.ic_lockscreen_shortcuts_blank);
} else {
- drawable = mShortcutHelper.getDrawableForTarget(shortcut);
- if (drawable == null) {
- drawable = getResources().getDrawable(shortcut == Shortcuts.LEFT_SHORTCUT
- ? R.drawable.ic_phone_24dp : R.drawable.ic_camera_alt_24dp);
+ if (shortcut == Shortcuts.LEFT_SHORTCUT &&
+ !mShortcutHelper.isTargetCustom(shortcut)) {
+ drawable = getLeftAffordanceDrawable();
v.setImageTintList(mDefaultTintList);
} else {
- v.setColorFilter(mFilter);
+ drawable = mShortcutHelper.getDrawableForTarget(shortcut);
+ if (drawable == null) {
+ drawable = (shortcut == Shortcuts.LEFT_SHORTCUT) ?
+ getLeftAffordanceDrawable()
+ : getResources().getDrawable(R.drawable.ic_camera_alt_24dp);
+ v.setImageTintList(mDefaultTintList);
+ } else {
+ v.setColorFilter(mFilter);
+ }
}
}
v.setImageDrawable(drawable);
}
}
+ private Drawable getLeftAffordanceDrawable() {
+ Drawable drawable;
+ if (canLaunchVoiceAssist()) {
+ drawable = getResources().getDrawable(R.drawable.ic_mic_26dp);
+ } else {
+ drawable = getResources().getDrawable(R.drawable.ic_phone_24dp);
+ }
+ return drawable;
+ }
+
+ private boolean canLaunchVoiceAssist() {
+ return mAssistUtils.activeServiceSupportsLaunchFromKeyguard();
+ }
+
private void createActionList() {
mActions = new ActionHolder();
mActions.addAction(LockscreenShortcutsHelper.NONE, R.string.lockscreen_none_target);
@@ -211,13 +235,15 @@ public class LockscreenShortcutsActivity extends Activity implements View.OnClic
private void onTargetChange(String uri) {
if (uri == null) {
- final GlowBackground background = (GlowBackground) mSelectedView.getBackground();
- background.hideGlow();
+ if (mSelectedView != null) {
+ final GlowBackground background = (GlowBackground) mSelectedView.getBackground();
+ background.hideGlow();
+ }
return;
}
if (uri.equals(ACTION_APP)) {
- mPicker.pickShortcut(null, null, 0);
+ mPicker.pickShortcut(null, null, 0, false);
} else {
mSelectedView.setTag(uri);
saveCustomActions();
diff --git a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java
index 12b9810..b47b69f 100644
--- a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java
@@ -53,9 +53,15 @@ public class LockscreenShortcutsHelper {
if (listener != null) {
mListener = listener;
mHandler = new Handler(Looper.getMainLooper());
- mContext.getContentResolver().registerContentObserver(
- CMSettings.Secure.getUriFor(CMSettings.Secure.LOCKSCREEN_TARGETS), false, mObserver);
+ registerAndFetchTargets();
+ } else {
+ fetchTargets();
}
+ }
+
+ public void registerAndFetchTargets() {
+ mContext.getContentResolver().registerContentObserver(
+ CMSettings.Secure.getUriFor(CMSettings.Secure.LOCKSCREEN_TARGETS), false, mObserver);
fetchTargets();
}
@@ -76,7 +82,6 @@ public class LockscreenShortcutsHelper {
public void cleanup() {
mContext.getContentResolver().unregisterContentObserver(mObserver);
- mListener = null;
}
public static class TargetInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index d2c60ef..a6ca6a0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -90,6 +90,12 @@ public class KeyguardService extends Service {
mKeyguardViewMediator.setOccluded(isOccluded);
}
+ @Override
+ public void showKeyguard() {
+ checkPermission();
+ mKeyguardViewMediator.showKeyguard();
+ }
+
@Override // Binder interface
public void dismiss() {
checkPermission();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 06ce8cc..2833759 100755
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -53,6 +53,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.view.IWindowManager;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicy;
@@ -61,6 +62,7 @@ import android.view.animation.AnimationUtils;
import com.android.systemui.cm.UserContentObserver;
import com.android.systemui.qs.tiles.LockscreenToggleTile;
+import com.android.systemui.statusbar.StatusBarState;
import cyanogenmod.app.Profile;
import cyanogenmod.app.ProfileManager;
@@ -173,6 +175,7 @@ public class KeyguardViewMediator extends SystemUI {
private static final int NOTIFY_SCREEN_TURNED_ON = 22;
private static final int NOTIFY_SCREEN_TURNED_OFF = 23;
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 24;
+ private static final int NOTIFY_KEYGUARD_PANEL_FOCUS_CHANGED = 25;
/**
* The default amount of time we stay awake (used for all key input)
@@ -254,6 +257,8 @@ public class KeyguardViewMediator extends SystemUI {
// true if the keyguard is hidden by another window
private boolean mOccluded = false;
+ private boolean mKeyguardPanelFocused = false;
+
/**
* Helps remember whether the screen has turned on since the last time
* it turned off due to timeout. see {@link #onScreenTurnedOff(int)}
@@ -351,6 +356,8 @@ public class KeyguardViewMediator extends SystemUI {
private IKeyguardDrawnCallback mDrawnCallback;
private LockscreenEnabledSettingsObserver mSettingsObserver;
+ private PhoneStatusBar mStatusBar;
+
public static class LockscreenEnabledSettingsObserver extends UserContentObserver {
private static final String KEY_ENABLED = "lockscreen_enabled";
@@ -480,21 +487,20 @@ public class KeyguardViewMediator extends SystemUI {
// only force lock screen in case of missing sim if user hasn't
// gone through setup wizard
synchronized (this) {
- if (shouldWaitForProvisioning()) {
- if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
- + " we need to show the keyguard since the "
- + "device isn't provisioned yet.");
- doKeyguardLocked(null);
- } else {
- resetStateLocked();
- }
+ if (shouldWaitForProvisioning() && !mShowing) {
+ if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
+ + " we need to show the keyguard since the "
+ + "device isn't provisioned yet.");
+ doKeyguardLocked(null);
+ } else {
+ resetStateLocked();
}
}
break;
case PIN_REQUIRED:
case PUK_REQUIRED:
synchronized (this) {
+ mStatusBar.hideHeadsUp();
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG,
"INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
@@ -1291,6 +1297,36 @@ public class KeyguardViewMediator extends SystemUI {
mHandler.sendEmptyMessage(DISMISS);
}
+ public void showKeyguard() {
+ // This is to prevent left edge from interfering
+ // with affordances.
+ if (mStatusBar.isAffordanceSwipeInProgress()
+ || mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
+ return;
+ }
+
+ // Disable edge detector once we're back on lockscreen
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .setLiveLockscreenEdgeDetector(false);
+ } catch (RemoteException e){
+ Log.e(TAG, e.getMessage());
+ }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // Hide status bar window to avoid flicker,
+ // slideNotificationPanelIn will make it visible later.
+ mStatusBar.getStatusBarWindow().setVisibility(View.INVISIBLE);
+ // Get the keyguard into the correct state by calling mStatusBar.showKeyguard()
+ mStatusBar.showKeyguard();
+ // Now have the notification panel slid back into view
+ mStatusBar.slideNotificationPanelIn();
+ }
+ });
+ }
+
/**
* Send message to keyguard telling it to reset its state.
* @see #handleReset
@@ -1485,6 +1521,9 @@ public class KeyguardViewMediator extends SystemUI {
case ON_ACTIVITY_DRAWN:
handleOnActivityDrawn();
break;
+ case NOTIFY_KEYGUARD_PANEL_FOCUS_CHANGED:
+ notifyKeyguardPanelFocusChanged(msg.arg1 != 0);
+ break;
}
}
};
@@ -1865,6 +1904,7 @@ public class KeyguardViewMediator extends SystemUI {
FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
statusBarWindowManager, scrimController, fingerprintUnlockController);
+ mStatusBar = phoneStatusBar;
return mStatusBarKeyguardViewManager;
}
@@ -1935,6 +1975,31 @@ public class KeyguardViewMediator extends SystemUI {
}
}
+ public void setKeyguardPanelFocused(boolean focused) {
+ if (DEBUG) Log.d(TAG, "setSlideOffset " + focused);
+ mHandler.removeMessages(NOTIFY_KEYGUARD_PANEL_FOCUS_CHANGED);
+ Message msg = mHandler.obtainMessage(NOTIFY_KEYGUARD_PANEL_FOCUS_CHANGED,
+ focused ? 1 : 0, 0);
+ mHandler.sendMessage(msg);
+ }
+
+ public void notifyKeyguardPanelFocusChanged(boolean focused) {
+ if (focused != mKeyguardPanelFocused) {
+ mKeyguardPanelFocused = focused;
+ int size = mKeyguardStateCallbacks.size();
+ for (int i = size - 1; i >= 0; i--) {
+ try {
+ mKeyguardStateCallbacks.get(i).onKeyguardPanelFocusChanged(focused);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call onShowingStateChanged", e);
+ if (e instanceof DeadObjectException) {
+ mKeyguardStateCallbacks.remove(i);
+ }
+ }
+ }
+ }
+ }
+
public void addStateMonitorCallback(IKeyguardStateCallback callback) {
synchronized (this) {
mKeyguardStateCallbacks.add(callback);
@@ -1942,6 +2007,7 @@ public class KeyguardViewMediator extends SystemUI {
callback.onSimSecureStateChanged(mUpdateMonitor.isSimPinSecure());
callback.onShowingStateChanged(mShowing);
callback.onInputRestrictedStateChanged(mInputRestricted);
+ callback.onKeyguardPanelFocusChanged(mKeyguardPanelFocused);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onShowingStateChanged or onSimSecureStateChanged or onInputRestrictedStateChanged", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java
index 578a983..3e0ab8b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java
@@ -27,6 +27,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
@@ -42,7 +43,7 @@ import java.util.List;
/**
* Quick settings common detail list view with line items.
*/
-public class QSDetailItemsList extends LinearLayout {
+public class QSDetailItemsList extends FrameLayout {
private static final String TAG = "QSDetailItemsList";
private ListView mListView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
index 86fc49e..13f552c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
@@ -19,10 +19,8 @@ package com.android.systemui.qs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
-import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
@@ -32,12 +30,10 @@ import android.graphics.Color;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
-import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.UserHandle;
-import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.ArrayMap;
@@ -49,7 +45,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
-import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -58,12 +53,12 @@ import com.android.internal.logging.MetricsLogger;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.cm.UserContentObserver;
+import com.android.systemui.qs.tiles.CustomQSTile;
import com.android.systemui.qs.tiles.EditTile;
-import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSlider;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.QsTuner;
import com.viewpagerindicator.CirclePageIndicator;
@@ -80,6 +75,8 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+
public class QSDragPanel extends QSPanel implements View.OnDragListener, View.OnLongClickListener {
private static final String TAG = "QSDragPanel";
@@ -94,6 +91,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
protected final ArrayList<QSPage> mPages = new ArrayList<>();
+ private NotificationPanelView mPanelView;
protected QSViewPager mViewPager;
protected PagerAdapter mPagerAdapter;
QSPanelTopView mQsPanelTop;
@@ -102,6 +100,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
private TextView mDetailRemoveButton;
private DragTileRecord mDraggingRecord, mLastDragRecord;
+ private ViewGroup mDetailButtons;
private boolean mEditing;
private boolean mDragging;
private float mLastTouchLocationX, mLastTouchLocationY;
@@ -119,15 +118,13 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
List<TileRecord> mCurrentlyAnimating
= Collections.synchronizedList(new ArrayList<TileRecord>());
- private Point mDisplaySize;
- private int[] mTmpLoc;
-
private Runnable mResetPage = new Runnable() {
@Override
public void run() {
- if (!mListening) {
+ if (!mExpanded) {
// only reset when the user isn't interacting at all
mViewPager.setCurrentItem(0);
+ mPagerAdapter.notifyDataSetChanged();
}
}
};
@@ -145,6 +142,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
updateResources();
mDetail = LayoutInflater.from(mContext).inflate(R.layout.qs_detail, this, false);
+ mDetailButtons = (ViewGroup) mDetail.findViewById(R.id.buttons);
mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
mDetailRemoveButton = (TextView) mDetail.findViewById(android.R.id.button3);
mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
@@ -355,7 +353,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
@Override
public boolean hasOverlappingRendering() {
- return mClipper.isAnimating() || mEditing;
+ return mClipper.isAnimating() || mEditing || !mCurrentlyAnimating.isEmpty();
}
@Override
@@ -370,7 +368,14 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
protected void drawTile(TileRecord r, QSTile.State state) {
if (mEditing) {
- state.visible = true;
+ if ((r.tile instanceof CustomQSTile)
+ && (((CustomQSTile) r.tile).isUserRemoved()
+ || ((CustomQSTile) r.tile).getTile() == null)) {
+ // don't modify visibility state if removed, or not yet published
+ } else {
+ state.visible = true;
+ state.enabled = true;
+ }
}
final int visibility = state.visible ? VISIBLE : GONE;
setTileVisibility(r.tileView, visibility);
@@ -382,12 +387,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
public void setListening(boolean listening) {
if (mListening == listening) return;
mListening = listening;
- // reset the page when inactive for a while
- if (listening) {
- removeCallbacks(mResetPage);
- } else {
- postDelayed(mResetPage, PAGE_RESET_DELAY);
- }
for (TileRecord r : mRecords) {
r.tile.setListening(mListening);
}
@@ -465,7 +464,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
mLastRightShift = -1;
mQsPanelTop.onStopDrag();
- requestLayout();
}
protected View getDropTarget() {
@@ -501,14 +499,16 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
public void setTiles(final Collection<QSTile<?>> tilesCollection) {
- final List<QSTile<?>> tiles = new ArrayList<>(tilesCollection);
+ // we try to be as efficient as possible here because this can happen while the user
+ // is in edit mode, or maybe even while tiles are animating
+ // step 1: stop all animations
+ // step 2: remove tiles no longer to be used, cache ones that are still valid
+ // step 3: remove empty viewpager pages
+ // step 4: generate new tiles, re-add cached ones
+
if (DEBUG_TILES) {
- Log.i(TAG, "setTiles() called with " + "tiles = ["
- + tiles + "]");
+ Log.i(TAG, "setTiles() called with tiles = [" + tilesCollection + "]");
}
-
- int currentViewPagerPage = mViewPager.getCurrentItem();
-
if (mLastDragRecord != null && mRecords.indexOf(mLastDragRecord) == -1) {
// the last removed record might be stored in mLastDragRecord if we just shifted
// re-add it to the list so we'll clean it up below
@@ -516,25 +516,41 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
mLastDragRecord = null;
}
- Map<QSTile<?>, DragTileRecord> recordMap = new ArrayMap<>();
+ // step kinda-1
+ if (mDraggingRecord != null) {
+ // dragging record might be animating back, force it to finished position
+ mDraggingRecord.tileView.animate().cancel();
+ }
+
+ int currentViewPagerPage = mViewPager.getCurrentItem();
+ int removedPages = 0;
+
+ Map<QSTile<?>, DragTileRecord> cachedRecords = new ArrayMap<>();
ListIterator<TileRecord> iterator = mRecords.listIterator(mRecords.size());
int recordsRemoved = 0;
// cleanup current records
- while (iterator.hasPrevious()) {
+ while (iterator.hasPrevious()) { // mRecords
DragTileRecord dr = (DragTileRecord) iterator.previous();
- if (dr.page >= 0) {
- // clean up view
- mPages.get(dr.page).removeView(dr.tileView);
- }
+ // step 1
+ dr.tileView.animate().cancel();
- if (tiles.contains(dr.tile)) {
+ // step 2
+ if (tilesCollection.contains(dr.tile)) {
if (DEBUG_TILES) {
Log.i(TAG, "caching tile: " + dr.tile);
}
- recordMap.put(dr.tile, dr);
+ cachedRecords.put(dr.tile, dr);
} else {
+ if (dr.page >= 0) {
+ if (DEBUG_TILES) {
+ Log.w(TAG, "removed dr.tileView: " + dr.tileView + " from page: "
+ + dr.page + " (dest page: " + dr.destinationPage + ")");
+ }
+
+ removeTileView(dr.tileView);
+ }
if (DEBUG_TILES) {
Log.i(TAG, "removing tile: " + dr.tile);
}
@@ -543,74 +559,99 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
iterator.remove();
recordsRemoved++;
- if (dr.page >= getCurrentMaxPageCount() - 1) {
- final int childCount = mPages.get(dr.page).getChildCount();
-
- if (childCount == 0) {
- final int currentIndex = mViewPager.getCurrentItem();
- if (currentIndex > 0 && currentViewPagerPage == currentIndex) {
- // if we are about to remove the page we are currently on, move back
- currentViewPagerPage--;
- }
- final int pageIndex = dr.page + (mEditing ? 1 : 0);
- mPagerAdapter.startUpdate(mViewPager);
- mPagerAdapter.destroyItem(mViewPager, pageIndex, mPages.get(dr.page));
- mPagerAdapter.finishUpdate(mViewPager);
- mPagerAdapter.notifyDataSetChanged();
- }
- }
+ dr.page = -1;
+ dr.destinationPage = -1;
}
- dr.page = -1;
- dr.destinationPage = -1;
}
- // at this point recordMap should have all retained tiles, no new or old tiles
- int delta = tiles.size() - recordMap.size() - recordsRemoved;
+ // at this point cachedRecords should have all retained tiles, no new or old tiles
+ int delta = tilesCollection.size() - cachedRecords.size() - recordsRemoved;
if (DEBUG_TILES) {
Log.i(TAG, "record map delta: " + delta);
}
- mRecords.ensureCapacity(tiles.size());
- mPagerAdapter.notifyDataSetChanged();
+ // step 3
+ final Iterator<QSPage> pageIterator = mPages.iterator();
+ while (pageIterator.hasNext()) {
+ final QSPage page = pageIterator.next();
+ final int viewpagerIndex = page.getPageIndex() + (mEditing ? 1 : 0);
+ final int childCount = page.getChildCount();
- // even though we explicitly destroy old pages, without this call,
- // the viewpager doesn't seem to want to pick up the fact that we have less pages
- // and allows "empty" scrolls to the right where there is no page.
- mViewPager.setAdapter(mPagerAdapter);
+ if (DEBUG_TILES) {
+ Log.d(TAG, "page " + viewpagerIndex + " has " + childCount);
+ }
+ if (page.getPageIndex() >= getCurrentMaxPageCount() - 1) {
+ if (DEBUG_TILES) {
+ Log.d(TAG, "page : " + page + " has " + childCount + " children");
+ }
+ if (childCount == 0) {
+ removedPages++;
+
+ page.removeAllViews();
+ mPagerAdapter.startUpdate(mViewPager);
+ mPagerAdapter.destroyItem(mViewPager, viewpagerIndex, page);
+ mPagerAdapter.finishUpdate(mViewPager);
+ mPagerAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ if (removedPages > 0) {
+ // even though we explicitly destroy old pages, without this call,
+ // the viewpager doesn't seem to want to pick up the fact that we have less pages
+ // and allows "empty" scrolls to the right where there is no page.
+ if (DEBUG_TILES) {
+ Log.d(TAG, "re-setting adapter, page: " + currentViewPagerPage);
+ }
+ mViewPager.setAdapter(mPagerAdapter);
+ mViewPager.setCurrentItem(Math.min(currentViewPagerPage, mPagerAdapter.getCount()),
+ false);
+ mPagerAdapter.notifyDataSetChanged();
+ }
+
+ // step 4
+ mRecords.ensureCapacity(tilesCollection.size());
+ int runningCount = 0;
- // add new tiles
- for (int i = 0; i < tiles.size(); i++) {
- QSTile<?> tile = tiles.get(i);
- final int tileDestPage = getPagesForCount(i + 1) - 1;
+ final Iterator<QSTile<?>> newTileIterator = tilesCollection.iterator();
+ while (newTileIterator.hasNext()) {
+ QSTile<?> tile = newTileIterator.next();
+ if (tile instanceof CustomQSTile) {
+ if (((CustomQSTile) tile).isUserRemoved()
+ || ((CustomQSTile) tile).getTile() == null) {
+ // tile not published yet
+ continue;
+ }
+ }
+ final int tileDestPage = getPagesForCount(runningCount + 1) - 1;
if (DEBUG_TILES) {
- Log.d(TAG, "tile at : " + i + ": " + tile + " to dest page: " + tileDestPage);
+ Log.d(TAG, "tile at : " + runningCount + ": " + tile
+ + " to dest page: " + tileDestPage);
}
DragTileRecord record;
- if (!recordMap.containsKey(tile)) {
+ if (!cachedRecords.containsKey(tile)) {
if (DEBUG_TILES) {
- Log.d(TAG, "tile at: " + i + " not cached, adding it to records");
+ Log.d(TAG, "tile at: " + runningCount + " not cached, adding it to records");
}
record = makeRecord(tile);
record.destinationPage = tileDestPage;
- recordMap.put(tile, record);
- mRecords.add(i, record);
+ mRecords.add(runningCount, record);
mPagerAdapter.notifyDataSetChanged();
} else {
- record = recordMap.get(tile);
+ record = cachedRecords.get(tile);
if (DEBUG_TILES) {
- Log.d(TAG, "tile at : " + i + ": cached, restoring: " + record);
+ Log.d(TAG, "tile at : " + runningCount + ": cached, restoring: " + record);
}
- int indexOf = mRecords.indexOf(record);
- if (indexOf != i) {
- if (DEBUG_TILES) {
- Log.w(TAG, "moving index of " + record + " from "
- + indexOf + " to " + i);
- }
- Collections.swap(mRecords, indexOf, i);
- }
+ mPages.get(record.page).removeView(record.tileView);
+
+ record.page = -1;
record.destinationPage = tileDestPage;
+
+ mRecords.remove(record);
+ mRecords.add(runningCount, record);
+ mPagerAdapter.notifyDataSetChanged();
}
if (record.page == -1) {
// add the view
@@ -620,11 +661,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
Log.d(TAG, "added view " + record);
}
}
+ runningCount++;
}
- // restore the visible page
- mViewPager.setCurrentItem(currentViewPagerPage, false);
-
if (isShowingDetail()) {
mDetail.bringToFront();
}
@@ -718,10 +757,18 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return r;
}
+ private void removeTileView(QSTileView v) {
+ for (QSPage page : mPages) {
+ page.removeView(v);
+ page.removeTransientView(v);
+ }
+
+ }
+
private void removeDraggingRecord() {
// what spec is this tile?
String spec = mHost.getSpec(mDraggingRecord.tile);
- if (DEBUG_DRAG) {
+ if (DEBUG_TILES) {
Log.w(TAG, "removing tile: " + mDraggingRecord + " with spec: " + spec);
}
onStopDrag();
@@ -736,13 +783,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mTmpLoc = null;
- mDisplaySize = null;
- }
-
- @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -756,37 +796,18 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
if (mFooter.hasFooter()) {
h += mFooter.getView().getMeasuredHeight();
}
+ mGridHeight = h;
+
mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+
if (mDetail.getMeasuredHeight() < h) {
mDetail.measure(exactly(width), exactly(h));
}
-
- // Check if the detail view would be overflowing below the physical height of the device
- // and cutting the content off. If it is, reduce the detail height to fit.
- if (isShowingDetail()) {
- if (mDisplaySize == null) {
- mDisplaySize = new Point();
- getDisplay().getSize(mDisplaySize);
- }
- if (mTmpLoc == null) {
- mTmpLoc = new int[2];
- mDetail.getLocationOnScreen(mTmpLoc);
- }
-
- final int containerTop = mTmpLoc[1];
- final int detailBottom = containerTop + mDetail.getMeasuredHeight();
- if (detailBottom >= mDisplaySize.y) {
- // panel is hanging below the screen
- final int detailMinHeight = mDisplaySize.y - containerTop;
- mDetail.measure(exactly(width), exactly(detailMinHeight));
- }
- setMeasuredDimension(width, mDetail.getMeasuredHeight());
- mGridHeight = mDetail.getMeasuredHeight();
- } else {
- setMeasuredDimension(width, h);
- mGridHeight = h;
+ if (isShowingDetail() && !isClosingDetail() && mExpanded) {
+ h = mDetail.getMeasuredHeight();
}
+ setMeasuredDimension(width, h);
for (TileRecord record : mRecords) {
setupRecord(record);
}
@@ -816,11 +837,13 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
r.tile.setDetailListening(show);
int x = (int) ((DragTileRecord) r).destination.x + r.tileView.getWidth() / 2;
- int y = mViewPager.getTop() + (int) ((DragTileRecord) r).destination.y + r.tileView.getHeight() / 2;
+ int y = mViewPager.getTop()
+ + (int) ((DragTileRecord) r).destination.y + r.tileView.getHeight() / 2;
handleShowDetailImpl(r, show, x, y);
} else {
super.handleShowDetailTile(r, show);
}
+ mPageIndicator.setVisibility(!show ? View.VISIBLE : View.INVISIBLE);
}
@Override
@@ -833,9 +856,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
// view pager laid out from top of brightness view to bottom to page through settings
mViewPager.layout(0, 0, w, viewPagerBottom);
- // layout page indicator inside viewpager inset
- mPageIndicator.layout(0, b - mPageIndicatorHeight, w, b);
-
mDetail.layout(0, 0, w, mDetail.getMeasuredHeight());
if (mFooter.hasFooter()) {
@@ -846,7 +866,10 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
if (!isShowingDetail() && !isClosingDetail()) {
mQsPanelTop.bringToFront();
+
}
+ // layout page indicator inside viewpager inset
+ mPageIndicator.layout(0, b - mPageIndicatorHeight, w, b);
}
protected int getRowTop(int row) {
@@ -1014,7 +1037,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
if (originatingTileEvent && !event.getResult()) {
// view pager probably ate the event
- restoreDraggingTilePosition(v);
+ restoreDraggingTilePosition(v, null);
}
break;
@@ -1032,15 +1055,38 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
Log.d(TAG, "dropping on delete target!!");
}
if (mDraggingRecord.tile instanceof EditTile) {
+ final QSTileView editTileView = mDraggingRecord.tileView;
+
mQsPanelTop.toast(R.string.quick_settings_cannot_delete_edit_tile);
- restoreDraggingTilePosition(v);
+ restoreDraggingTilePosition(v, new Runnable() {
+ @Override
+ public void run() {
+ // move edit tile to the back
+ final TileRecord editTile = getRecord(editTileView);
+ if (mRecords.remove(editTile)) {
+ // we depend on mHost.setTiles() placing it on the end
+ persistRecords();
+ }
+ }
+ });
break;
+ } else if (mDraggingRecord.tile instanceof CustomQSTile) {
+ ((CustomQSTile) mDraggingRecord.tile).setUserRemoved(true);
+ final String spec = mHost.getSpec(mDraggingRecord.tile);
+ restoreDraggingTilePosition(v, new Runnable() {
+ @Override
+ public void run() {
+ // it might get added back later by the app, but that's ok,
+ // we just want to reset its position after it has been removed.
+ mHost.remove(spec);
+ }
+ });
} else {
mRestored = true;
removeDraggingRecord();
}
} else {
- restoreDraggingTilePosition(v);
+ restoreDraggingTilePosition(v, null);
}
break;
@@ -1171,7 +1217,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return false;
}
- private void restoreDraggingTilePosition(View v) {
+ private void restoreDraggingTilePosition(View v, final Runnable onAnimationFinishedRunnable) {
if (mRestored) {
return;
}
@@ -1251,6 +1297,20 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
@Override
+ public void onAnimationCancel(Animator animation) {
+ mViewPager.requestDisallowInterceptTouchEvent(false);
+ removeTransientView(mDraggingRecord.tileView);
+ mCurrentlyAnimating.remove(mDraggingRecord);
+ mRestoring = false;
+ mPagerAdapter.notifyDataSetChanged();
+ onStopDrag();
+
+ if (onAnimationFinishedRunnable != null) {
+ postOnAnimation(onAnimationFinishedRunnable);
+ }
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
mViewPager.requestDisallowInterceptTouchEvent(false);
@@ -1265,8 +1325,8 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
Log.i(TAG, "drag record was attached");
}
}
- mDraggingRecord.page = mDraggingRecord.destinationPage;
targetP.addView(mDraggingRecord.tileView);
+ mDraggingRecord.page = mDraggingRecord.destinationPage;
mDraggingRecord.tileView.setX(mDraggingRecord.destination.x);
// reset this to be in the coords of the page, not viewpager anymore
@@ -1281,6 +1341,12 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
mPagerAdapter.notifyDataSetChanged();
}
onStopDrag();
+
+ if (onAnimationFinishedRunnable != null) {
+ postOnAnimation(onAnimationFinishedRunnable);
+ } else {
+ requestLayout();
+ }
}
});
}
@@ -1497,10 +1563,16 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
.y(ti.destination.y)
.setListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationCancel(Animator animation) {
+ tilePageSource.removeTransientView(ti.tileView);
+ mCurrentlyAnimating.remove(ti);
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
tilePageSource.removeTransientView(ti.tileView);
- ti.page = tilePageTarget.getPageIndex();
tilePageTarget.addView(ti.tileView);
+ ti.page = tilePageTarget.getPageIndex();
ti.tileView.setX(ti.destination.x);
ti.tileView.setY(ti.destination.y);
@@ -1516,6 +1588,11 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
.y(ti.destination.y)
.setListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationCancel(Animator animation) {
+ mCurrentlyAnimating.remove(ti);
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
mCurrentlyAnimating.remove(ti);
final boolean dual = getPage(ti.destinationPage).dualRecord(ti);
@@ -1551,10 +1628,16 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
.y(last.destination.y)
.setListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationCancel(Animator animation) {
+ tilePageSource.removeTransientView(last.tileView);
+ mCurrentlyAnimating.remove(last);
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
tilePageSource.removeTransientView(last.tileView);
- last.page = tilePageTarget.getPageIndex();
tilePageTarget.addView(last.tileView);
+ last.page = tilePageTarget.getPageIndex();
last.tileView.setX(last.destination.x);
last.tileView.setY(last.destination.y);
@@ -1573,6 +1656,11 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
.y(last.destination.y)
.setListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationCancel(Animator animation) {
+ mCurrentlyAnimating.remove(last);
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
if (DEBUG_DRAG) {
Log.i(TAG, "shift finished: " + last);
@@ -1654,10 +1742,16 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
@Override
+ public void onAnimationCancel(Animator animation) {
+ page.removeTransientView(ti.tileView);
+ mCurrentlyAnimating.remove(ti);
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
page.removeTransientView(ti.tileView);
- ti.page = page.getPageIndex();
page.addView(ti.tileView);
+ ti.page = page.getPageIndex();
mCurrentlyAnimating.remove(ti);
requestLayout();
@@ -1710,17 +1804,27 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
});
}
+ mPanelView.setDetailRequestedScrollLock(mExpanded && show
+ && getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE);
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
FontSizeUtils.updateFontSize(mDetailRemoveButton, R.dimen.qs_detail_button_text_size);
+ mPanelView.setDetailRequestedScrollLock(mExpanded && isShowingDetail()
+ && getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE);
}
@Override
public void setExpanded(boolean expanded) {
super.setExpanded(expanded);
+ // reset the page when inactive for a while
+ if (expanded) {
+ removeCallbacks(mResetPage);
+ } else {
+ postDelayed(mResetPage, PAGE_RESET_DELAY);
+ }
if (!expanded) {
if (mEditing) {
mHost.setEditing(false);
@@ -1747,10 +1851,11 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
for (TileRecord r : mRecords) {
r.tile.clearState();
}
+ updateDetailText();
+ mQsPanelTop.updateResources();
if (mListening) {
refreshAllTiles();
}
- updateDetailText();
}
}
@@ -1764,6 +1869,10 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
}
+ public void setPanelView(NotificationPanelView panelView) {
+ this.mPanelView = panelView;
+ }
+
public static class TilesListAdapter extends BaseExpandableListAdapter
implements QSTile.DetailAdapter {
@@ -1790,7 +1899,8 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
final Iterator<String> i = tiles.iterator();
while (i.hasNext()) {
final String spec = i.next();
- if (QSUtils.isStaticQsTile(spec) || QSUtils.isDynamicQsTile(spec)) {
+ if (QSUtils.isStaticQsTile(spec)
+ || QSUtils.isDynamicQsTile(extractTileTagFromSpec(spec))) {
List<String> packageList = mPackageTileMap.get(PACKAGE_ANDROID);
packageList.add(spec);
} else {
@@ -1803,13 +1913,122 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
}
+ final Map<String, ?> stringMap = CustomQSTile.getCustomQSTilePrefs(mContext).getAll();
+ for (Map.Entry<String, ?> entry : stringMap.entrySet()) {
+ if (entry.getValue() instanceof Boolean) {
+ if ((Boolean)entry.getValue()) {
+ final String key = entry.getKey();
+ if (QSUtils.isDynamicQsTile(extractTileTagFromSpec(key))) {
+ mPackageTileMap.get(PACKAGE_ANDROID).add(key);
+ } else {
+ final String customTilePackage = getCustomTilePackage(key);
+ List<String> packageList = mPackageTileMap.get(customTilePackage);
+ if (packageList == null) {
+ mPackageTileMap.put(customTilePackage,
+ packageList = new ArrayList<>());
+ }
+ packageList.add(key);
+
+ }
+ }
+ }
+ };
+
final List<String> systemTiles = mPackageTileMap.get(PACKAGE_ANDROID);
Collections.sort(systemTiles);
}
private String getCustomTilePackage(String spec) {
- StatusBarPanelCustomTile sbc = mHost.getCustomTileData().get(spec).sbc;
- return sbc.getPackage();
+ if (mHost.getCustomTileData().get(spec) != null) {
+ StatusBarPanelCustomTile sbc = mHost.getCustomTileData().get(spec).sbc;
+ return sbc.getPackage();
+ } else {
+ return extractPackageFromCustomTileSpec(spec);
+ }
+ }
+
+ private static String extractPackageFromCustomTileSpec(String spec) {
+ if (spec != null && !spec.isEmpty()) {
+ final String[] split = spec.split("\\|");
+ if (split != null && split.length > 2) {
+ return split[1];
+ }
+ return spec;
+ }
+ return null;
+ }
+
+ private static String extractTileTagFromSpec(String spec) {
+ if (spec != null && !spec.isEmpty()) {
+ final String[] split = spec.split("\\|");
+ if (split != null && split.length == 5) {
+ /** for {@link cyanogenmod.app.StatusBarPanelCustomTile#key() **/
+ return split[3];
+ } else if (split != null && split.length == 3) {
+ /** for {@link cyanogenmod.app.StatusBarPanelCustomTile#persistableKey()} **/
+ return split[2];
+ }
+ return spec;
+ }
+ return null;
+ }
+
+ private Drawable getQSTileIcon(String spec) {
+ if (QSUtils.isDynamicQsTile(extractTileTagFromSpec(spec))) {
+ return QSTile.ResourceIcon.get(QSUtils.getDynamicQSTileResIconId(mContext,
+ UserHandle.myUserId(), extractTileTagFromSpec(spec))).getDrawable(mContext);
+ } else if (QSUtils.isStaticQsTile(spec)) {
+ final int res = QSTileHost.getIconResource(spec);
+ if (res != 0) {
+ return QSTile.ResourceIcon.get(res).getDrawable(mContext);
+ } else {
+ return mContext.getPackageManager().getDefaultActivityIcon();
+ }
+ } else {
+ QSTile<?> tile = mHost.getTile(spec);
+ if (tile != null) {
+ QSTile.State state = tile.getState();
+ if (state != null && state.icon != null) {
+ return state.icon.getDrawable(mContext);
+ }
+ }
+ return getPackageDrawable(getCustomTilePackage(spec));
+ }
+ }
+
+ private String getPackageLabel(String packageName) {
+ try {
+ return mContext.getPackageManager().getApplicationLabel(
+ mContext.getPackageManager().getApplicationInfo(packageName, 0)).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private Drawable getPackageDrawable(String packageName) {
+ try {
+ return mContext.getPackageManager().getApplicationIcon(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private String getQSTileLabel(String spec) {
+ if (QSUtils.isStaticQsTile(spec)) {
+ int resource = QSTileHost.getLabelResource(spec);
+ if (resource != 0) {
+ return mContext.getText(resource).toString();
+ } else {
+ return spec;
+ }
+ } else if (QSUtils.isDynamicQsTile(extractTileTagFromSpec(spec))) {
+ return QSUtils.getDynamicQSTileLabel(mContext,
+ UserHandle.myUserId(), extractTileTagFromSpec(spec));
+ } else {
+ return getPackageLabel(getCustomTilePackage(spec));
+ }
}
@Override
@@ -1872,6 +2091,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
// special icon
systemOrAppIcon.setImageResource(R.drawable.ic_qs_tile_category_system);
} else {
+ group = getPackageLabel(group);
systemOrAppIcon.setImageResource(R.drawable.ic_qs_tile_category_other);
}
title.setText(group);
@@ -1910,57 +2130,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return child;
}
- private String getQSTileLabel(String spec) {
- if (QSUtils.isStaticQsTile(spec)) {
- int resource = QSTileHost.getLabelResource(spec);
- return mContext.getText(resource).toString();
- } else if (QSUtils.isDynamicQsTile(spec)) {
- return QSUtils.getDynamicQSTileLabel(mContext,
- UserHandle.myUserId(), spec);
- } else {
- return getPackageLabel(getCustomTilePackage(spec));
- }
- }
-
- private Drawable getQSTileIcon(String spec) {
- if (QSUtils.isDynamicQsTile(spec)) {
- return QSTile.ResourceIcon.get(
- QSUtils.getDynamicQSTileResIconId(mContext, UserHandle.myUserId(), spec))
- .getDrawable(mContext);
- } else if (QSUtils.isStaticQsTile(spec)) {
- return QSTile.ResourceIcon.get(QSTileHost.getIconResource(spec))
- .getDrawable(mContext);
- } else {
- QSTile<?> tile = mHost.getTile(spec);
- if (tile != null) {
- QSTile.State state = tile.getState();
- if (state != null && state.icon != null) {
- return state.icon.getDrawable(mContext);
- }
- }
- return getPackageDrawable(getCustomTilePackage(spec));
- }
- }
-
- private String getPackageLabel(String packageName) {
- try {
- return mContext.getPackageManager().getApplicationLabel(
- mContext.getPackageManager().getApplicationInfo(packageName, 0)).toString();
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private Drawable getPackageDrawable(String packageName) {
- try {
- return mContext.getPackageManager().getApplicationIcon(packageName);
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
-
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
@@ -2001,7 +2170,21 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
String spec = getChild(groupPosition, childPosition);
- mPanel.add(spec);
+
+ final QSTile<?> tile = mHost.getTile(spec);
+ if (tile != null && tile instanceof CustomQSTile) {
+ // already present
+ ((CustomQSTile) tile).setUserRemoved(false);
+ mPanel.refreshAllTiles();
+ } else {
+ // reset its state just in case it's not published
+ CustomQSTile.getCustomQSTilePrefs(mContext)
+ .edit()
+ .remove(spec)
+ .apply();
+ mPanel.add(spec);
+ // TODO notify user the app isn't publishing the tile, but it now can be!
+ }
mPanel.closeDetail();
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 60dc787..77ede93 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -72,7 +72,7 @@ public class QSPanel extends ViewGroup {
protected int mDualTileUnderlap;
protected int mBrightnessPaddingTop;
protected int mGridHeight;
- private boolean mExpanded;
+ protected boolean mExpanded;
protected boolean mListening;
private boolean mClosingDetail;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java
index 5f57be1..b00483c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java
@@ -53,6 +53,7 @@ public class QSPanelTopView extends FrameLayout {
protected View mBrightnessView;
protected TextView mToastView;
protected View mAddTarget;
+ protected TextView mEditInstructionText;
private boolean mEditing = false;
private boolean mDisplayingInstructions = false;
@@ -112,6 +113,14 @@ public class QSPanelTopView extends FrameLayout {
mBrightnessView = findViewById(R.id.brightness_container);
mToastView = (TextView) findViewById(R.id.qs_toast);
mAddTarget = findViewById(R.id.add_target);
+ mEditInstructionText = (TextView) findViewById(R.id.edit_text_instruction);
+ updateResources();
+ }
+
+ public void updateResources() {
+ if (mEditInstructionText != null) {
+ mEditInstructionText.setText(R.string.qs_tile_edit_header_instruction);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 2d62724..01a170f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -34,6 +34,7 @@ import android.view.ViewGroup;
import android.widget.RemoteViews;
import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -344,6 +345,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
CastController getCastController();
FlashlightController getFlashlightController();
KeyguardMonitor getKeyguardMonitor();
+ BatteryController getBatteryController();
boolean isEditing();
void setEditing(boolean editing);
void resetTiles();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AdbOverNetworkTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AdbOverNetworkTile.java
index 283d617..b970a4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AdbOverNetworkTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AdbOverNetworkTile.java
@@ -91,7 +91,7 @@ public class AdbOverNetworkTile extends QSTile<QSTile.BooleanState> {
}
private boolean isAdbEnabled() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
+ return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ADB_ENABLED, 0) > 0;
}
@@ -120,7 +120,7 @@ public class AdbOverNetworkTile extends QSTile<QSTile.BooleanState> {
CMSettings.Secure.getUriFor(CMSettings.Secure.ADB_PORT),
false, mObserver);
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Global.ADB_ENABLED),
+ Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
false, mObserver);
} else {
mContext.getContentResolver().unregisterContentObserver(mObserver);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 37d8d73..1a60fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -25,6 +25,8 @@ import android.provider.Settings;
import com.android.systemui.qs.QSTile;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryStateRegistar;
import cyanogenmod.power.PerformanceManager;
@@ -36,13 +38,15 @@ public class BatterySaverTile extends QSTile<QSTile.BooleanState> {
private static final Intent BATTERY_SETTINGS = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
private final PowerManager mPm;
- private final PerformanceManager mPerformanceManager;
+ private final boolean mHasPowerProfiles;
+
private boolean mListening;
+ private boolean mPluggedIn;
public BatterySaverTile(Host host) {
super(host);
mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mPerformanceManager = PerformanceManager.getInstance(mContext);
+ mHasPowerProfiles = PerformanceManager.getInstance(mContext).getNumberOfProfiles() > 0;
}
@Override
@@ -53,7 +57,7 @@ public class BatterySaverTile extends QSTile<QSTile.BooleanState> {
@Override
public void handleClick() {
mPm.setPowerSaveMode(!mState.value);
- refreshState();
+ refreshState(!mState.value);
}
@Override
@@ -63,8 +67,8 @@ public class BatterySaverTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- state.value = mPm.isPowerSaveMode();
- state.visible = mPerformanceManager.getNumberOfProfiles() == 0;
+ state.value = arg instanceof Boolean ? (boolean) arg : mPm.isPowerSaveMode();
+ state.visible = !mHasPowerProfiles;
state.label = mContext.getString(R.string.quick_settings_battery_saver_label);
if (state.value) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver_on);
@@ -75,6 +79,11 @@ public class BatterySaverTile extends QSTile<QSTile.BooleanState> {
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_battery_saver_off);
}
+
+ state.enabled = !mPluggedIn;
+ if (mPluggedIn) {
+ state.label = mContext.getString(R.string.quick_settings_battery_saver_label_charging);
+ }
}
@Override
@@ -93,11 +102,24 @@ public class BatterySaverTile extends QSTile<QSTile.BooleanState> {
return CMMetricsLogger.TILE_BATTERY_SAVER;
}
- private ContentObserver mObserver = new ContentObserver(mHandler) {
+ private BatteryStateRegistar.BatteryStateChangeCallback mBatteryState
+ = new BatteryStateRegistar.BatteryStateChangeCallback() {
+ @Override
+ public void onBatteryLevelChanged(boolean present, int level, boolean pluggedIn,
+ boolean charging) {
+ mPluggedIn = pluggedIn || charging;
+ refreshState();
+ }
+
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onPowerSaveChanged() {
refreshState();
}
+
+ @Override
+ public void onBatteryStyleChanged(int style, int percentMode) {
+ // ignore
+ }
};
@Override
@@ -106,11 +128,9 @@ public class BatterySaverTile extends QSTile<QSTile.BooleanState> {
mListening = listening;
if (listening) {
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE),
- false, mObserver);
+ getHost().getBatteryController().addStateChangedCallback(mBatteryState);
} else {
- mContext.getContentResolver().unregisterContentObserver(mObserver);
+ getHost().getBatteryController().removeStateChangedCallback(mBatteryState);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index a798e4e..cdedc26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -225,6 +225,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
listView.setOnItemClickListener(this);
listView.setAdapter(mAdapter =
new QSDetailItemsList.QSDetailListAdapter(context, mBluetoothItems));
+ mAdapter.setCallback(this);
mItemsList.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
R.string.quick_settings_bluetooth_detail_empty_text);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 04cc5dc..f49d97e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -39,7 +39,6 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
private final AnimationIcon mDisable
= new AnimationIcon(R.drawable.ic_invert_colors_disable_animation);
private final SecureSetting mSetting;
- private final UsageTracker mUsageTracker;
private boolean mListening;
@@ -50,29 +49,11 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
- if (value != 0 || observedChange) {
- mUsageTracker.trackUsage();
- }
if (mListening) {
handleRefreshState(value);
}
}
};
- mUsageTracker = new UsageTracker(host.getContext(),
- Prefs.Key.COLOR_INVERSION_TILE_LAST_USED, ColorInversionTile.class,
- R.integer.days_to_show_color_inversion_tile);
- if (mSetting.getValue() != 0 && !mUsageTracker.isRecentlyUsed()) {
- mUsageTracker.trackUsage();
- }
- mUsageTracker.setListening(true);
- mSetting.setListening(true);
- }
-
- @Override
- protected void handleDestroy() {
- super.handleDestroy();
- mUsageTracker.setListening(false);
- mSetting.setListening(false);
}
@Override
@@ -82,7 +63,11 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
@Override
public void setListening(boolean listening) {
+ if (mListening == listening) {
+ return;
+ }
mListening = listening;
+ mSetting.setListening(mListening);
}
@Override
@@ -101,25 +86,14 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleLongClick() {
- if (mState.value) {
- mHost.startActivityDismissingKeyguard(ACCESSIBILITY_SETTINGS);
- } else {
- final String title = mContext.getString(
- R.string.quick_settings_reset_confirmation_title, mState.label);
- mUsageTracker.showResetConfirmation(title, new Runnable() {
- @Override
- public void run() {
- refreshState();
- }
- });
- }
+ mHost.startActivityDismissingKeyguard(ACCESSIBILITY_SETTINGS);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
final boolean enabled = value != 0;
- state.visible = enabled || mUsageTracker.isRecentlyUsed();
+ state.visible = true;
state.value = enabled;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
state.icon = enabled ? mEnable : mDisable;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CompassTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CompassTile.java
index f19e466..85790d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CompassTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CompassTile.java
@@ -32,6 +32,7 @@ public class CompassTile extends QSTile<QSTile.BooleanState> implements SensorEv
private final static float ALPHA = 0.97f;
private boolean mActive = false;
+ private boolean mListening = false;
private SensorManager mSensorManager;
private Sensor mAccelerationSensor;
@@ -95,7 +96,7 @@ public class CompassTile extends QSTile<QSTile.BooleanState> implements SensorEv
Float degrees = arg == null ? 0 :(float) arg;
state.visible = true;
- state.value = mActive;
+ state.value = mActive && mListening;
if (state.value) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_compass_on);
@@ -126,10 +127,10 @@ public class CompassTile extends QSTile<QSTile.BooleanState> implements SensorEv
@Override
public void setListening(boolean listening) {
- if (!listening) {
- setListeningSensors(false);
- mActive = false;
- }
+ // setListening might get called multiple times with the same value, we check for it
+ // in setListeningSensors
+ mListening = listening;
+ setListeningSensors(mListening && mActive);
}
private String formatValueWithCardinalDirection(float degree) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
index d09ca92..40c7184 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.ThemeConfig;
import android.net.Uri;
@@ -31,15 +32,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RemoteViews;
import android.widget.TextView;
-import com.android.internal.logging.MetricsLogger;
-
import com.android.systemui.qs.QSDetailItemsGrid;
import com.android.systemui.qs.QSDetailItemsList;
import cyanogenmod.app.CustomTile;
@@ -53,6 +51,8 @@ import java.util.Arrays;
public class CustomQSTile extends QSTile<QSTile.State> {
+ private static final String HIDDEN_TILES_PREF_NAME = "user_hidden_qs_tiles";
+
private CustomTile.ExpandedStyle mExpandedStyle;
private PendingIntent mOnClick;
private PendingIntent mOnLongClick;
@@ -61,10 +61,51 @@ public class CustomQSTile extends QSTile<QSTile.State> {
private StatusBarPanelCustomTile mTile;
private CustomQSDetailAdapter mDetailAdapter;
private boolean mCollapsePanel;
+ private boolean mUserRemoved;
+ private String mPersistedPlaceHolderKey;
+
+ public CustomQSTile(Host host, String persistedSpec) {
+ super(host);
+ mTile = null;
+ mPersistedPlaceHolderKey = persistedSpec;
+ }
public CustomQSTile(Host host, StatusBarPanelCustomTile tile) {
super(host);
mTile = tile;
+ mUserRemoved = getIsUserRemovedPersisted();
+ }
+
+ private String getPersistableKey() {
+ if (mPersistedPlaceHolderKey != null) {
+ return mPersistedPlaceHolderKey;
+ } else {
+ return getTile().persistableKey();
+ }
+ }
+
+ private boolean getIsUserRemovedPersisted() {
+ return getCustomQSTilePrefs(mContext).getBoolean(getPersistableKey(), false);
+ }
+
+ public boolean isUserRemoved() {
+ return mUserRemoved;
+ }
+
+ public void setUserRemoved(boolean removed) {
+ if (mUserRemoved != removed) {
+ if (removed) {
+ getCustomQSTilePrefs(mContext).edit().putBoolean(getPersistableKey(), true).apply();
+ } else {
+ getCustomQSTilePrefs(mContext).edit().remove(getPersistableKey()).apply();
+ }
+ mUserRemoved = removed;
+ refreshState();
+ }
+ }
+
+ public static SharedPreferences getCustomQSTilePrefs(Context context) {
+ return context.getSharedPreferences(HIDDEN_TILES_PREF_NAME, Context.MODE_PRIVATE);
}
@Override
@@ -138,11 +179,18 @@ public class CustomQSTile extends QSTile<QSTile.State> {
protected void handleUpdateState(State state, Object arg) {
if (arg instanceof StatusBarPanelCustomTile) {
mTile = (StatusBarPanelCustomTile) arg;
+ mPersistedPlaceHolderKey = null;
+ mUserRemoved = getIsUserRemovedPersisted();
+ }
+ if (mTile == null) {
+ state.visible = false;
+ // nothing to show, it's a place holder for now
+ return;
}
final CustomTile customTile = mTile.getCustomTile();
state.contentDescription = customTile.contentDescription;
state.label = customTile.label;
- state.visible = true;
+ state.visible = !mUserRemoved;
final int iconId = customTile.icon;
if (iconId != 0 && (customTile.remoteIcon == null)) {
final String iconPackage = mTile.getResPkg();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 25a7fb7..6080358 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -48,7 +48,6 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
new AnimationIcon(R.drawable.ic_hotspot_disable_animation);
private final HotspotController mController;
private final Callback mCallback = new Callback();
- private final UsageTracker mUsageTracker;
private final ConnectivityManager mConnectivityManager;
private boolean mListening;
private int mNumConnectedClients = 0;
@@ -56,18 +55,10 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
public HotspotTile(Host host) {
super(host);
mController = host.getHotspotController();
- mUsageTracker = newUsageTracker(host.getContext());
- mUsageTracker.setListening(true);
mConnectivityManager = host.getContext().getSystemService(ConnectivityManager.class);
}
@Override
- protected void handleDestroy() {
- super.handleDestroy();
- mUsageTracker.setListening(false);
- }
-
- @Override
protected BooleanState newTileState() {
return new BooleanState();
}
@@ -108,23 +99,12 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleLongClick() {
- if (mState.value) {
- mHost.startActivityDismissingKeyguard(TETHER_SETTINGS);
- } else {
- final String title = mContext.getString(
- R.string.quick_settings_reset_confirmation_title, mState.label);
- mUsageTracker.showResetConfirmation(title, new Runnable() {
- @Override
- public void run() {
- refreshState();
- }
- });
- }
+ mHost.startActivityDismissingKeyguard(TETHER_SETTINGS);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- state.visible = mController.isHotspotSupported() && mUsageTracker.isRecentlyUsed();
+ state.visible = mController.isHotspotSupported();
if (arg instanceof Boolean) {
state.value = (boolean) arg;
@@ -155,11 +135,6 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
}
}
- private static UsageTracker newUsageTracker(Context context) {
- return new UsageTracker(context, Prefs.Key.HOTSPOT_TILE_LAST_USED, HotspotTile.class,
- R.integer.days_to_show_hotspot_tile);
- }
-
private BroadcastReceiver mTetherConnectStateChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -175,20 +150,4 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
refreshState(enabled);
}
};
-
- /**
- * This will catch broadcasts for changes in hotspot state so we can show
- * the hotspot tile for a number of days after use.
- */
- public static class APChangedReceiver extends BroadcastReceiver {
- private UsageTracker mUsageTracker;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mUsageTracker == null) {
- mUsageTracker = newUsageTracker(context);
- }
- mUsageTracker.trackUsage();
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LiveDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LiveDisplayTile.java
deleted file mode 100644
index f59c876..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LiveDisplayTile.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2015 The CyanogenMod 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.qs.tiles;
-
-import android.content.Intent;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
-
-import com.android.internal.util.ArrayUtils;
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-
-import cyanogenmod.hardware.CMHardwareManager;
-import cyanogenmod.providers.CMSettings;
-import org.cyanogenmod.internal.logging.CMMetricsLogger;
-
-/** Quick settings tile: LiveDisplay mode switcher **/
-public class LiveDisplayTile extends QSTile<LiveDisplayTile.LiveDisplayState> {
-
- private static final Intent LIVEDISPLAY_SETTINGS =
- new Intent("android.settings.LIVEDISPLAY_SETTINGS");
-
- private final LiveDisplayObserver mObserver;
- private String[] mEntries;
- private String[] mDescriptionEntries;
- private String[] mAnnouncementEntries;
- private String[] mValues;
- private final int[] mEntryIconRes;
-
- private boolean mListening;
-
- private static final int MODE_OUTDOOR = 3;
- private static final int MODE_DAY = 4;
-
- private static final int OFF_TEMPERATURE = 6500;
-
- private int mDayTemperature;
-
- private final boolean mOutdoorModeAvailable;
- private final int mDefaultDayTemperature;
-
- public LiveDisplayTile(Host host) {
- super(host);
-
- Resources res = mContext.getResources();
- TypedArray typedArray = res.obtainTypedArray(R.array.live_display_drawables);
- mEntryIconRes = new int[typedArray.length()];
- for (int i = 0; i < mEntryIconRes.length; i++) {
- mEntryIconRes[i] = typedArray.getResourceId(i, 0);
- }
- typedArray.recycle();
-
- updateEntries();
-
- mOutdoorModeAvailable =
- CMHardwareManager.getInstance(mContext)
- .isSupported(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT);
-
- mDefaultDayTemperature = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_dayColorTemperature);
- loadDayTemperature();
-
- mObserver = new LiveDisplayObserver(mHandler);
- mObserver.startObserving();
- }
-
- private void updateEntries() {
- Resources res = mContext.getResources();
- mEntries = res.getStringArray(com.android.internal.R.array.live_display_entries);
- mDescriptionEntries = res.getStringArray(R.array.live_display_description);
- mAnnouncementEntries = res.getStringArray(R.array.live_display_announcement);
- mValues = res.getStringArray(com.android.internal.R.array.live_display_values);
- }
-
- @Override
- protected LiveDisplayState newTileState() {
- return new LiveDisplayState();
- }
-
- @Override
- public void setListening(boolean listening) {
- if (mListening == listening)
- return;
- mListening = listening;
- if (listening) {
- mObserver.startObserving();
- } else {
- mObserver.endObserving();
- }
- }
-
- @Override
- protected void handleClick() {
- changeToNextMode();
- }
-
- @Override
- protected void handleLongClick() {
- mHost.startActivityDismissingKeyguard(LIVEDISPLAY_SETTINGS);
- }
-
- @Override
- protected void handleUpdateState(LiveDisplayState state, Object arg) {
- updateEntries();
- state.visible = true;
- state.mode = arg == null ? getCurrentModeIndex() : (Integer) arg;
- state.label = mEntries[state.mode];
- state.icon = ResourceIcon.get(mEntryIconRes[state.mode]);
- state.contentDescription = mDescriptionEntries[state.mode];
- }
-
- @Override
- public int getMetricsCategory() {
- return CMMetricsLogger.TILE_LIVE_DISPLAY;
- }
-
- @Override
- protected String composeChangeAnnouncement() {
- return mAnnouncementEntries[getCurrentModeIndex()];
- }
-
- private int getCurrentModeIndex() {
- return ArrayUtils.indexOf(mValues,
- String.valueOf(CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_TEMPERATURE_MODE,
- 0, UserHandle.USER_CURRENT)));
- }
-
- private void changeToNextMode() {
- int next = getCurrentModeIndex() + 1;
-
- if (next >= mValues.length) {
- next = 0;
- }
-
- while (true) {
- // Skip outdoor mode if it's unsupported, and skip the day setting
- // if it's the same as the off setting
- if ((!mOutdoorModeAvailable &&
- Integer.valueOf(mValues[next]) == MODE_OUTDOOR) ||
- (mDayTemperature == OFF_TEMPERATURE &&
- Integer.valueOf(mValues[next]) == MODE_DAY)) {
- next++;
- if (next >= mValues.length) {
- next = 0;
- }
- } else {
- break;
- }
- }
-
- CMSettings.System.putIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_TEMPERATURE_MODE,
- Integer.valueOf(mValues[next]), UserHandle.USER_CURRENT);
- }
-
- private void loadDayTemperature() {
- mDayTemperature = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_TEMPERATURE_DAY,
- mDefaultDayTemperature,
- UserHandle.USER_CURRENT);
- }
-
- private class LiveDisplayObserver extends ContentObserver {
- public LiveDisplayObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- loadDayTemperature();
- refreshState(getCurrentModeIndex());
- }
-
- public void startObserving() {
- mContext.getContentResolver().registerContentObserver(
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_MODE),
- false, this, UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_DAY),
- false, this, UserHandle.USER_ALL);
- }
-
- public void endObserving() {
- mContext.getContentResolver().unregisterContentObserver(this);
- }
- }
-
- public static class LiveDisplayState extends QSTile.State {
- public int mode;
-
- @Override
- public boolean copyTo(State other) {
- final LiveDisplayState o = (LiveDisplayState) other;
- final boolean changed = mode != o.mode;
- return super.copyTo(other) || changed;
- }
-
- @Override
- protected StringBuilder toStringBuilder() {
- final StringBuilder rt = super.toStringBuilder();
- rt.insert(rt.length() - 1, ",mode=" + mode);
- return rt;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 1bfbb8f..a5ffd23 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -22,12 +22,14 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
+import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import org.cyanogenmod.internal.logging.CMMetricsLogger;
+import org.cyanogenmod.internal.util.QSUtils;
public class NfcTile extends QSTile<QSTile.BooleanState> {
- private NfcAdapter mNfcAdapter;
+
private boolean mListening;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -36,10 +38,11 @@ public class NfcTile extends QSTile<QSTile.BooleanState> {
refreshState();
}
};
+ private final boolean mSupportsNfc;
public NfcTile(Host host) {
super(host);
- mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
+ mSupportsNfc = QSUtils.deviceSupportsNfc(mContext);
}
@Override
@@ -49,7 +52,9 @@ public class NfcTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
- toggleState();
+ boolean newState = !getState().value;
+ setState(newState);
+ refreshState();
}
@Override
@@ -57,23 +62,45 @@ public class NfcTile extends QSTile<QSTile.BooleanState> {
mHost.startActivityDismissingKeyguard(new Intent("android.settings.NFC_SETTINGS"));
}
- protected void toggleState() {
- int state = getNfcState();
- switch (state) {
- case NfcAdapter.STATE_TURNING_ON:
- case NfcAdapter.STATE_ON:
- mNfcAdapter.disable();
- break;
- case NfcAdapter.STATE_TURNING_OFF:
- case NfcAdapter.STATE_OFF:
- mNfcAdapter.enable();
- break;
+ private void setState(boolean on) {
+ try {
+ NfcAdapter nfcAdapter = NfcAdapter.getNfcAdapter(mContext);
+ if (nfcAdapter == null) {
+ Log.e(TAG, "tried to set NFC state, but no NFC adapter was found");
+ return;
+ }
+ if (on) {
+ nfcAdapter.enable();
+ } else {
+ nfcAdapter.disable();
+ }
+ } catch (UnsupportedOperationException e) {
+ // ignore
+ }
+ }
+
+ private int getNfcAdapterState() {
+ try {
+ NfcAdapter nfcAdapter = NfcAdapter.getNfcAdapter(mContext);
+ if (nfcAdapter == null) {
+ Log.e(TAG, "tried to get NFC state, but no NFC adapter was found");
+ return NfcAdapter.STATE_OFF;
+ }
+ return nfcAdapter.getAdapterState();
+ } catch (UnsupportedOperationException e) {
+ // ignore
+ return NfcAdapter.STATE_OFF;
}
}
- private boolean isEnabled() {
- int state = getNfcState();
- switch (state) {
+ /**
+ * Helper method to encapsulate intermediate states (turning off/on) to help determine whether
+ * the adapter will be on or off.
+ * @param nfcState The current NFC adapter state.
+ * @return boolean representing what state the adapter is/will be in
+ */
+ private static boolean isEnabled(int nfcState) {
+ switch (nfcState) {
case NfcAdapter.STATE_TURNING_ON:
case NfcAdapter.STATE_ON:
return true;
@@ -84,17 +111,28 @@ public class NfcTile extends QSTile<QSTile.BooleanState> {
}
}
- private int getNfcState() {
- return mNfcAdapter.getAdapterState();
+ /**
+ * Helper method to determine intermediate states
+ * @param nfcState The current NFC adapter state.
+ * @return boolean representing if the adapter is in an intermediate state
+ */
+ private static boolean isEnablingDisabling(int nfcState) {
+ switch (nfcState) {
+ case NfcAdapter.STATE_TURNING_OFF:
+ case NfcAdapter.STATE_TURNING_ON:
+ return true;
+ default:
+ return false;
+ }
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- if (mNfcAdapter == null) {
- mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
- }
- state.visible = mNfcAdapter != null;
- state.value = mNfcAdapter != null && isEnabled();
+ state.visible = mSupportsNfc;
+ final int nfcState = getNfcAdapterState();
+ state.value = mSupportsNfc && isEnabled(nfcState);
+ state.enabled = mSupportsNfc && !isEnablingDisabling(nfcState);
+
state.icon = ResourceIcon.get(state.value ?
R.drawable.ic_qs_nfc_on : R.drawable.ic_qs_nfc_off);
state.label = mContext.getString(R.string.quick_settings_nfc_label);
@@ -110,12 +148,9 @@ public class NfcTile extends QSTile<QSTile.BooleanState> {
if (mListening == listening) return;
mListening = listening;
if (listening) {
- if (mNfcAdapter == null) {
- mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
- refreshState();
- }
mContext.registerReceiver(mReceiver,
new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED));
+ refreshState();
} else {
mContext.unregisterReceiver(mReceiver);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java
index e6e6bb4..4863683 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java
@@ -48,6 +48,7 @@ public class PerfProfileTile extends QSTile<PerfProfileTile.ProfileState> {
private final String[] mDescriptionEntries;
private final String[] mAnnouncementEntries;
private final int[] mPerfProfileValues;
+ private final int mNumPerfProfiles;
private final Icon mIcon;
private final PowerManager mPm;
@@ -61,16 +62,36 @@ public class PerfProfileTile extends QSTile<PerfProfileTile.ProfileState> {
mObserver = new PerformanceProfileObserver(mHandler);
mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mPerformanceManager = PerformanceManager.getInstance(mContext);
+ mNumPerfProfiles = mPerformanceManager.getNumberOfProfiles();
- Resources res = mContext.getResources();
-
- mPerfProfileValues = res.getIntArray(org.cyanogenmod.platform.internal.R.array.perf_profile_values);
-
- mEntries = res.getStringArray(org.cyanogenmod.platform.internal.R.array.perf_profile_entries);
- mDescriptionEntries = res.getStringArray(R.array.perf_profile_description);
- mAnnouncementEntries = res.getStringArray(R.array.perf_profile_announcement);
+ mPerfProfileValues = new int[mNumPerfProfiles];
+ mEntries = new String[mNumPerfProfiles];
+ mDescriptionEntries = new String[mNumPerfProfiles];
+ mAnnouncementEntries = new String[mNumPerfProfiles];
mIcon = ResourceIcon.get(R.drawable.ic_qs_perf_profile);
+
+ // Filter out unsupported profiles
+ Resources res = mContext.getResources();
+ final int[] perfProfileValues = res.getIntArray(
+ org.cyanogenmod.platform.internal.R.array.perf_profile_values);
+ final String[] entries = res.getStringArray(
+ org.cyanogenmod.platform.internal.R.array.perf_profile_entries);
+ final String[] descriptionEntries = res.getStringArray(
+ R.array.perf_profile_description);
+ final String[] announcementEntries = res.getStringArray(
+ R.array.perf_profile_announcement);
+ int i = 0;
+
+ for (int j = 0; j < perfProfileValues.length; j++) {
+ if (perfProfileValues[j] < mNumPerfProfiles) {
+ mPerfProfileValues[i] = perfProfileValues[j];
+ mEntries[i] = entries[j];
+ mDescriptionEntries[i] = descriptionEntries[j];
+ mAnnouncementEntries[i] = announcementEntries[j];
+ i++;
+ }
+ }
}
@Override
@@ -135,7 +156,7 @@ public class PerfProfileTile extends QSTile<PerfProfileTile.ProfileState> {
public void startObserving() {
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(CMSettings.Secure.PERFORMANCE_PROFILE),
+ CMSettings.Secure.getUriFor(CMSettings.Secure.PERFORMANCE_PROFILE),
false, this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index f4fe677..9e08599 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -85,6 +85,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// Runnable to be executed after we paused ourselves
Runnable mAfterPauseRunnable;
+ private ReferenceCountedTrigger mExitTrigger;
+
/**
* A common Runnable to finish Recents either by calling finish() (with a custom animation) or
* launching Home with some ActivityOptions. Generally we always launch home when we exit
@@ -95,6 +97,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
class FinishRecentsRunnable implements Runnable {
Intent mLaunchIntent;
ActivityOptions mLaunchOpts;
+ boolean mAbort = false;
/**
* Creates a finish runnable that starts the specified intent, using the given
@@ -105,8 +108,15 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mLaunchOpts = opts;
}
+ public void setAbort(boolean run) {
+ this.mAbort = run;
+ }
+
@Override
public void run() {
+ if (mAbort) {
+ return;
+ }
// Finish Recents
if (mLaunchIntent != null) {
try {
@@ -317,13 +327,26 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
return false;
}
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (!hasFocus && mExitTrigger != null && mExitTrigger.getCount() > 0) {
+ // we are animating recents out and the window has lost focus during the
+ // animation. we need to stop everything we're doing now and get out
+ // without any animations (since we were already animating)
+ mFinishLaunchHomeRunnable.setAbort(true);
+ finish();
+ overridePendingTransition(0, 0);
+ }
+ }
+
/** Dismisses Recents directly to Home. */
void dismissRecentsToHomeRaw(boolean animated) {
if (animated) {
- ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+ mExitTrigger = new ReferenceCountedTrigger(this,
null, mFinishLaunchHomeRunnable, null);
mRecentsView.startExitToHomeAnimation(
- new ViewAnimation.TaskViewExitContext(exitTrigger));
+ new ViewAnimation.TaskViewExitContext(mExitTrigger));
} else {
mFinishLaunchHomeRunnable.run();
}
@@ -458,6 +481,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
protected void onStop() {
super.onStop();
+
+ mExitTrigger = null;
+
MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 64622620..2f11c56 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -31,6 +31,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.EventLog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowInsets;
@@ -48,6 +49,8 @@ import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.EventLogTags;
+
import java.util.ArrayList;
import java.util.List;
@@ -267,6 +270,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
stackView.startEnterRecentsAnimation(ctx);
}
ctx.postAnimationTrigger.decrement();
+
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_EVENT, 1 /* opened */);
}
/** Requests all task stacks to start their exit-recents animation */
@@ -620,6 +625,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
launchRunnable.run();
}
}
+
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_EVENT, 3 /* chose task */);
}
@Override
@@ -659,6 +666,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// Keep track of all-deletions
MetricsLogger.count(getContext(), "overview_task_all_dismissed", 1);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_EVENT, 4 /* closed all */);
}
/** Final callback after Recents is finally hidden. */
@@ -670,6 +678,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
TaskStackView stackView = stackViews.get(i);
stackView.onRecentsHidden();
}
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_EVENT, 2 /* closed */);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 43b9a3e..454222c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1018,8 +1018,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
t.setClipViewInStack(false);
t.startLaunchTaskAnimation(r, true, true, lockToTask);
} else {
- boolean occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(t.getTask(),
- launchTargetTask);
+ boolean occludesLaunchTarget = launchTargetTask != null &&
+ launchTargetTask.group != null &&
+ launchTargetTask.group.isTaskAboveTask(t.getTask(), launchTargetTask);
t.startLaunchTaskAnimation(null, false, occludesLaunchTarget, lockToTask);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7b608bb..e958ee1 100755
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -45,6 +45,7 @@ import android.database.ContentObserver;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.media.session.MediaController;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -117,6 +118,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import cyanogenmod.providers.CMSettings;
+
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
@@ -154,6 +157,8 @@ public abstract class BaseStatusBar extends SystemUI implements
private static final String BANNER_ACTION_SETUP =
"com.android.systemui.statusbar.banner_action_setup";
+ protected static final int SYSTEM_UI_VISIBILITY_MASK = 0xffffffff;
+
private static final Uri SPAM_MESSAGE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SpamMessageProvider.AUTHORITY)
@@ -221,6 +226,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected WindowManager mWindowManager;
protected IWindowManager mWindowManagerService;
+ private NotificationManager mNoMan;
+
protected abstract void refreshLayout(int layoutDirection);
protected Display mDisplay;
@@ -263,8 +270,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- final boolean provisioned = 0 != Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
+ final boolean provisioned = 0 != CMSettings.Secure.getInt(
+ mContext.getContentResolver(), CMSettings.Secure.CM_SETUP_WIZARD_COMPLETED, 0);
if (provisioned != mDeviceProvisioned) {
mDeviceProvisioned = provisioned;
updateNotifications();
@@ -427,9 +434,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
} else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
- NotificationManager noMan = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.cancel(R.id.notification_hidden);
+ mNoMan.cancel(R.id.notification_hidden);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -558,6 +563,9 @@ public abstract class BaseStatusBar extends SystemUI implements
public void start() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
+
+ mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+
mDisplay = mWindowManager.getDefaultDisplay();
mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
@@ -574,8 +582,8 @@ public abstract class BaseStatusBar extends SystemUI implements
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
- mSettingsObserver);
+ CMSettings.Secure.getUriFor(CMSettings.Secure.CM_SETUP_WIZARD_COMPLETED), false,
+ mSettingsObserver, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
mSettingsObserver);
@@ -624,7 +632,7 @@ public abstract class BaseStatusBar extends SystemUI implements
mSettingsObserver.onChange(false); // set up
disable(switches[0], switches[6], false /* animate */);
- setSystemUiVisibility(switches[1], 0xffffffff);
+ setSystemUiVisibility(switches[1], SYSTEM_UI_VISIBILITY_MASK);
topAppWindowChanged(switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
@@ -723,9 +731,7 @@ public abstract class BaseStatusBar extends SystemUI implements
mContext.getString(R.string.hidden_notifications_setup),
setupIntent);
- NotificationManager noMan =
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.notify(R.id.notification_hidden, note.build());
+ mNoMan.notify(R.id.notification_hidden, note.build());
}
}
@@ -769,6 +775,10 @@ public abstract class BaseStatusBar extends SystemUI implements
return null;
}
+ protected MediaController getCurrentMediaController() {
+ return null;
+ }
+
@Override
public NotificationGroupManager getGroupManager() {
return mGroupManager;
@@ -947,7 +957,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
});
- filterButton.setVisibility(View.VISIBLE);
+ Notification notification = sbn.getNotification();
+ filterButton.setVisibility(SpamFilter.hasFilterableContent(notification)
+ ? View.VISIBLE : View.GONE);
filterButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
AsyncTask.execute(new Runnable() {
@@ -1014,6 +1026,10 @@ public abstract class BaseStatusBar extends SystemUI implements
}
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ if (v instanceof MediaExpandableNotificationRow
+ && !((MediaExpandableNotificationRow) v).inflateGuts()) {
+ return false;
+ }
bindGuts(row);
// Assume we are a status_bar_notification_row
@@ -1280,6 +1296,20 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected boolean inflateViews(Entry entry, ViewGroup parent) {
+ final StatusBarNotification sbn = entry.notification;
+ String themePackageName = mCurrentTheme != null
+ ? mCurrentTheme.getOverlayPkgNameForApp(sbn.getPackageName()) : null;
+ boolean inflated = inflateViews(entry, parent, true);
+ if (!inflated && themePackageName != null
+ && !ThemeConfig.SYSTEM_DEFAULT.equals(themePackageName)) {
+ Log.w(TAG, "Couldn't expand themed RemoteViews, trying unthemed for: " + sbn);
+ inflated = inflateViews(entry, mStackScroller, false);
+ }
+
+ return inflated;
+ }
+
+ protected boolean inflateViews(Entry entry, ViewGroup parent, boolean isThemeable) {
PackageManager pmUser = getPackageManagerForUser(
entry.notification.getUser().getIdentifier());
@@ -1320,8 +1350,19 @@ public abstract class BaseStatusBar extends SystemUI implements
// create the row view
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
- parent, false);
+
+ // cannot use isMediaNotification()
+ if (sbn.getNotification().category != null
+ && sbn.getNotification().category.equals(Notification.CATEGORY_TRANSPORT)) {
+ row = (MediaExpandableNotificationRow) inflater.inflate(
+ R.layout.status_bar_notification_row_media, parent, false);
+ ((MediaExpandableNotificationRow)row).setMediaController(
+ getCurrentMediaController());
+ } else {
+ row = (ExpandableNotificationRow) inflater.inflate(
+ R.layout.status_bar_notification_row,
+ parent, false);
+ }
row.setExpansionLogger(this, entry.notification.getKey());
row.setGroupManager(mGroupManager);
}
@@ -1345,10 +1386,12 @@ public abstract class BaseStatusBar extends SystemUI implements
View contentViewLocal = null;
View bigContentViewLocal = null;
View headsUpContentViewLocal = null;
- String themePackageName = mCurrentTheme != null
- ? mCurrentTheme.getOverlayPkgNameForApp(sbn.getPackageName()) : null;
- String statusBarThemePackageName = mCurrentTheme != null
- ? mCurrentTheme.getOverlayForStatusBar() : null;
+ String themePackageName = (isThemeable && mCurrentTheme != null)
+ ? mCurrentTheme.getOverlayPkgNameForApp(sbn.getPackageName())
+ : ThemeConfig.SYSTEM_DEFAULT;
+ String statusBarThemePackageName = (isThemeable && mCurrentTheme != null)
+ ? mCurrentTheme.getOverlayForStatusBar()
+ : ThemeConfig.SYSTEM_DEFAULT;
try {
contentViewLocal = contentView.apply(
@@ -1439,8 +1482,10 @@ public abstract class BaseStatusBar extends SystemUI implements
}
if (publicViewLocal == null) {
+ final Context layoutContext = isThemeable ? mContext
+ : maybeGetThemedContext(mContext, ThemeConfig.SYSTEM_DEFAULT);
// Add a basic notification template
- publicViewLocal = LayoutInflater.from(mContext).inflate(
+ publicViewLocal = LayoutInflater.from(layoutContext).inflate(
R.layout.notification_public_default,
contentContainerPublic, false);
publicViewLocal.setIsRootNamespace(true);
@@ -1875,7 +1920,18 @@ public abstract class BaseStatusBar extends SystemUI implements
}
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
- return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
+ if (!mShowLockscreenNotifications || mNotificationData.isAmbient(sbn.getKey())) {
+ return false;
+ }
+ final int showOnKeyguard = mNoMan.getShowNotificationForPackageOnKeyguard(
+ sbn.getPackageName(), sbn.getUid());
+ boolean isKeyguardAllowedForApp =
+ (showOnKeyguard & Notification.SHOW_ALL_NOTI_ON_KEYGUARD) != 0;
+ if (isKeyguardAllowedForApp && sbn.isOngoing()) {
+ isKeyguardAllowedForApp =
+ (showOnKeyguard & Notification.SHOW_NO_ONGOING_NOTI_ON_KEYGUARD) == 0;
+ }
+ return isKeyguardAllowedForApp;
}
protected void setZenMode(int mode) {
@@ -2286,4 +2342,24 @@ public abstract class BaseStatusBar extends SystemUI implements
mAssistManager.startAssist(args);
}
}
+
+ /**
+ * Returns a context with the given theme applied or the original context if we fail to get a
+ * themed context.
+ */
+ private Context maybeGetThemedContext(Context context, String themePkg) {
+ Context themedContext;
+ try {
+ ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
+ context.getPackageName(), 0);
+ themedContext = context.createApplicationContext(ai, themePkg,
+ 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ themedContext = null;
+ }
+ if (themedContext == null) {
+ themedContext = context;
+ }
+ return themedContext;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
index 4be7292..42974ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
@@ -29,7 +29,7 @@ public class CustomTileData {
public final StatusBarPanelCustomTile sbc;
public Entry(StatusBarPanelCustomTile sbc) {
- this.key = sbc.getKey();
+ this.key = sbc.persistableKey();
this.sbc = sbc;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index c964ca7..be51e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -64,7 +64,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mShowingPublic;
private boolean mSensitive;
private boolean mShowingPublicInitialized;
- private boolean mHideSensitiveForIntrinsicHeight;
+ protected boolean mHideSensitiveForIntrinsicHeight;
/**
* Is this notification expanded by the system. The expansion state can be overridden by the
@@ -77,10 +77,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
private boolean mExpansionDisabled;
- private NotificationContentView mPublicLayout;
- private NotificationContentView mPrivateLayout;
- private int mMaxExpandHeight;
- private int mHeadsUpHeight;
+ protected NotificationContentView mPublicLayout;
+ protected NotificationContentView mPrivateLayout;
+ protected int mMaxExpandHeight;
+ protected int mHeadsUpHeight;
private View mVetoButton;
private boolean mClearable;
private ExpansionLogger mLogger;
@@ -101,7 +101,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private ValueAnimator mChildExpandAnimator;
private float mChildrenExpandProgress;
private float mExpandButtonStart;
- private ViewStub mGutsStub;
+ protected ViewStub mGutsStub;
private boolean mHasExpandAction;
private boolean mIsSystemChildExpanded;
private boolean mIsPinned;
@@ -443,10 +443,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mVetoButton = findViewById(R.id.veto);
}
- public void inflateGuts() {
+ public boolean inflateGuts() {
if (mGuts == null) {
mGutsStub.inflate();
}
+ return false;
}
private void updateChildrenVisibility(boolean animated) {
@@ -645,7 +646,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
} else if (mChildrenExpanded) {
maxContentHeight = mChildrenContainer.getIntrinsicHeight();
} else {
- maxContentHeight = getMaxExpandHeight();
+ maxContentHeight = mMaxExpandHeight;
}
return maxContentHeight + getBottomDecorHeight();
}
@@ -669,7 +670,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*
* @return whether the view state is currently expanded.
*/
- private boolean isExpanded() {
+ protected boolean isExpanded() {
return !mExpansionDisabled
&& (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
|| isUserExpanded());
@@ -703,7 +704,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return super.isChildInvisible(child) || isInvisibleChildContainer;
}
- private void updateMaxHeights() {
+ protected void updateMaxHeights() {
int intrinsicBefore = getIntrinsicHeight();
View expandedChild = mPrivateLayout.getExpandedChild();
if (expandedChild == null) {
@@ -902,10 +903,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
- public int getMaxExpandHeight() {
- return mMaxExpandHeight;
- }
-
@Override
public boolean isContentExpandable() {
NotificationContentView showingLayout = getShowingLayout();
@@ -961,7 +958,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mMaxExpandHeight != 0;
}
- private NotificationContentView getShowingLayout() {
+ protected NotificationContentView getShowingLayout() {
return mShowingPublic ? mPublicLayout : mPrivateLayout;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 71baf57..76858ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -42,7 +42,7 @@ public abstract class ExpandableView extends FrameLayout {
private boolean mDark;
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
private int mClipTopOptimization;
- private static Rect mClipRect = new Rect();
+ private Rect mClipRect = new Rect();
private boolean mWillBeGone;
private int mMinClipTopAmount = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 26b9c8e..1f7e687 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -187,7 +187,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette
if (mPreviewView != null) {
mPreviewView.setVisibility(mLaunchingAffordance
? oldPreviewView.getVisibility() : INVISIBLE);
- mPreviewView.setVisibility(INVISIBLE);
+ mPreviewView.setVisibility(GONE);
addOverlay();
}
}
@@ -283,7 +283,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette
});
animatorToRadius.start();
setImageAlpha(0, true);
- if (mPreviewView != null) {
+ if (mPreviewView != null && mPreviewView.getVisibility() == View.VISIBLE) {
mPreviewView.setVisibility(View.VISIBLE);
mPreviewClipper = ViewAnimationUtils.createCircularReveal(
mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
@@ -386,7 +386,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette
invalidate();
if (nowHidden) {
if (mPreviewView != null) {
- mPreviewView.setVisibility(View.INVISIBLE);
+ mPreviewView.setVisibility(View.GONE);
}
}
} else if (!mCircleWillBeHidden) {
@@ -425,7 +425,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette
mPreviewClipper.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mPreviewView.setVisibility(View.INVISIBLE);
+ mPreviewView.setVisibility(View.GONE);
}
});
mPreviewClipper.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 318ef5e..e4a0196 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.fingerprint.FingerprintManager;
@@ -74,16 +75,20 @@ public class KeyguardIndicationController {
private int mChargingSpeed;
private int mChargingCurrent;
private String mMessageToShowOnScreenOn;
+ private IndicationDirection mIndicationDirection;
+ private boolean mScreenOnHintsEnabled;
public KeyguardIndicationController(Context context, KeyguardIndicationTextView textView,
LockIcon lockIcon) {
mContext = context;
mTextView = textView;
mLockIcon = lockIcon;
+ mIndicationDirection = IndicationDirection.NONE;
Resources res = context.getResources();
mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
+ mScreenOnHintsEnabled = res.getBoolean(R.bool.config_showScreenOnLockScreenHints);
mBatteryInfo = IBatteryStats.Stub.asInterface(
@@ -121,6 +126,20 @@ public class KeyguardIndicationController {
/**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/
+ public void showTransientIndication(int transientIndication, IndicationDirection direction) {
+ showTransientIndication(mContext.getResources().getString(transientIndication), direction);
+ }
+
+ /**
+ * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+ */
+ public void showTransientIndication(String transientIndication, IndicationDirection direction) {
+ showTransientIndication(transientIndication, Color.WHITE, direction);
+ }
+
+ /**
+ * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+ */
public void showTransientIndication(int transientIndication) {
showTransientIndication(mContext.getResources().getString(transientIndication));
}
@@ -129,15 +148,24 @@ public class KeyguardIndicationController {
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/
public void showTransientIndication(String transientIndication) {
- showTransientIndication(transientIndication, Color.WHITE);
+ showTransientIndication(transientIndication, Color.WHITE, IndicationDirection.NONE);
}
/**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/
public void showTransientIndication(String transientIndication, int textColor) {
+ showTransientIndication(transientIndication, textColor, IndicationDirection.NONE);
+ }
+
+ /**
+ * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+ */
+ public void showTransientIndication(String transientIndication, int textColor,
+ IndicationDirection direction) {
mTransientIndication = transientIndication;
mTransientTextColor = textColor;
+ mIndicationDirection = direction;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
updateIndication();
}
@@ -160,8 +188,31 @@ public class KeyguardIndicationController {
private void updateIndication() {
if (mVisible) {
+ final int color = computeColor();
mTextView.switchIndication(computeIndication());
- mTextView.setTextColor(computeColor());
+ mTextView.setTextColor(color);
+ int top = 0, left = 0, right = 0;
+ // pad the bottom using ic_empty_space to keep text vertically aligned if needed
+ int bottom = mScreenOnHintsEnabled ? R.drawable.ic_empty_space : 0;
+ switch (mIndicationDirection) {
+ case UP:
+ top = R.drawable.ic_keyboard_arrow_up;
+ break;
+ case DOWN:
+ bottom = R.drawable.ic_keyboard_arrow_down;
+ break;
+ case LEFT:
+ left = R.drawable.ic_keyboard_arrow_left;
+ break;
+ case RIGHT:
+ right = R.drawable.ic_keyboard_arrow_right;
+ break;
+ case NONE:
+ default:
+ break;
+ }
+ mTextView.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
+ mTextView.setCompoundDrawableTintList(ColorStateList.valueOf(color));
}
}
@@ -176,6 +227,7 @@ public class KeyguardIndicationController {
if (!TextUtils.isEmpty(mTransientIndication)) {
return mTransientIndication;
}
+ mIndicationDirection = IndicationDirection.NONE;
if (mPowerPluggedIn) {
String indication = computePowerIndication();
if (DEBUG_CHARGING_CURRENT) {
@@ -326,4 +378,12 @@ public class KeyguardIndicationController {
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
}
+
+ public enum IndicationDirection {
+ NONE,
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaExpandableNotificationRow.java
new file mode 100644
index 0000000..c25f146
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaExpandableNotificationRow.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod 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;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.media.session.MediaController;
+import android.os.Build;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
+
+import cyanogenmod.providers.CMSettings;
+
+public class MediaExpandableNotificationRow extends ExpandableNotificationRow {
+
+ private static final String TAG = MediaExpandableNotificationRow.class.getSimpleName();
+ public static final boolean DEBUG = false;
+
+ public static final int MAX_QUEUE_ENTRIES = 3;
+
+ private QueueView mQueue;
+
+ private int mMaxQueueHeight;
+ private int mRowHeight;
+ private int mShadowHeight;
+ private int mDisplayedRows;
+
+ private SettingsObserver mSettingsObserver;
+ private boolean mQueueEnabled;
+
+ public MediaExpandableNotificationRow(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mSettingsObserver = new SettingsObserver(new Handler());
+ mQueueEnabled = isQueueEnabled(context);
+
+ Resources res = mContext.getResources();
+
+ // 3 * queue_row_height + shadow height
+ mRowHeight = res.getDimensionPixelSize(R.dimen.queue_row_height);
+ mShadowHeight = res.getDimensionPixelSize(R.dimen.queue_top_shadow);
+ }
+
+ public boolean inflateGuts() {
+ if (getGuts() == null) {
+ mGutsStub.inflate();
+ }
+ if (!mQueueEnabled) {
+ return true;
+ }
+ return !mQueue.isUserSelectingRow();
+ }
+
+ @Override
+ protected void updateMaxHeights() {
+ // update queue height based on number of rows
+ int rows = mQueue != null ? mQueue.getCurrentQueueRowCount() : 0;
+ if (rows != mDisplayedRows) {
+ mMaxQueueHeight = rows * mRowHeight;
+ if (mMaxQueueHeight > 0) {
+ mMaxQueueHeight += mShadowHeight;
+ }
+ mDisplayedRows = rows;
+ }
+
+ int intrinsicBefore = getIntrinsicHeight();
+ View expandedChild = mPrivateLayout.getExpandedChild();
+ if (expandedChild == null) {
+ expandedChild = mPrivateLayout.getContractedChild();
+ }
+ mMaxExpandHeight = expandedChild.getHeight() + mMaxQueueHeight;
+
+ View headsUpChild = mPrivateLayout.getHeadsUpChild();
+ if (headsUpChild == null) {
+ headsUpChild = mPrivateLayout.getContractedChild();
+ }
+ mHeadsUpHeight = headsUpChild.getHeight();
+ if (intrinsicBefore != getIntrinsicHeight()) {
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ invalidateOutline();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ if (getGuts() != null && getGuts().isShown()) {
+ return getGuts().getActualHeight();
+ }
+ if (!mQueueEnabled) {
+ return super.getIntrinsicHeight();
+ }
+ if (mHideSensitiveForIntrinsicHeight) {
+ return getMinHeight();
+ }
+ if (isUserLocked()) {
+ return getActualHeight();
+ }
+ boolean inExpansionState = isExpanded();
+ if (!inExpansionState) {
+ // not expanded, so we return the collapsed size
+ return getMinHeight();
+ }
+ return getMaxContentHeight();
+ }
+
+ @Override
+ public int getMaxContentHeight() {
+ /**
+ * calls into NotificationContentView.getMaxHeight()
+ */
+ return getShowingLayout().getMaxHeight() + mMaxQueueHeight;
+ }
+
+ @Override
+ public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
+ super.setHeightRange(rowMinHeight, rowMaxHeight);
+ mMaxViewHeight = Math.max(rowMaxHeight, getMaxContentHeight());
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mQueue = (QueueView) findViewById(R.id.queue_view);
+ mQueue.setQueueEnabled(mQueueEnabled);
+ mQueue.setVisibility(mQueueEnabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void setMediaController(MediaController mediaController) {
+ if (DEBUG) Log.d(TAG, "setMediaController() called with "
+ + "mediaController = [" + mediaController + "]");
+ if (mQueue.setController(mediaController) && mQueueEnabled) {
+ notifyHeightChanged(true);
+ }
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+ if (filterMotionEvent(ev)) {
+ return super.dispatchGenericMotionEvent(ev);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (filterMotionEvent(ev)) {
+ return super.dispatchTouchEvent(ev);
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean filterMotionEvent(MotionEvent event) {
+ if (!mQueueEnabled) {
+ return super.filterMotionEvent(event);
+ }
+ if (isExpanded() && mQueue.isUserSelectingRow()
+ && event.getActionMasked() != MotionEvent.ACTION_DOWN
+ && event.getActionMasked() != MotionEvent.ACTION_UP
+ && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
+ // this is for hotspot propogation?
+ return false;
+ }
+ return super.filterMotionEvent(event);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mSettingsObserver.observe();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mSettingsObserver.unobserve();
+ }
+
+ private class SettingsObserver extends UserContentObserver {
+
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+ mContext.getContentResolver().registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.NOTIFICATION_PLAY_QUEUE),
+ true, this);
+ }
+
+ @Override
+ protected void unobserve() {
+ super.unobserve();
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ protected void update() {
+ mQueueEnabled = isQueueEnabled(mContext);
+ mQueue.setQueueEnabled(mQueueEnabled);
+ mQueue.setVisibility(mQueueEnabled ? View.VISIBLE : View.GONE);
+ requestLayout();
+ }
+ }
+
+ public static boolean isQueueEnabled(Context context) {
+ return CMSettings.System.getInt(context.getContentResolver(),
+ CMSettings.System.NOTIFICATION_PLAY_QUEUE, 1) == 1;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaNotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaNotificationGuts.java
new file mode 100644
index 0000000..14ce8e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaNotificationGuts.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod 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;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+import android.widget.TextView;
+import com.android.systemui.R;
+import cyanogenmod.providers.CMSettings;
+
+/**
+ * The guts of a media notification revealed when performing a long press.
+ */
+public class MediaNotificationGuts extends NotificationGuts {
+
+ private static final String TAG = MediaNotificationGuts.class.getSimpleName();
+
+ private ViewGroup mQueueGroup;
+ private TextView mText;
+ private Switch mSwitch;
+
+ public MediaNotificationGuts(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ setWillNotDraw(true);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // do nothing!
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mQueueGroup = (ViewGroup) findViewById(R.id.queue_group);
+ mSwitch = (Switch) findViewById(R.id.queue_switch);
+ mSwitch.setChecked(MediaExpandableNotificationRow.isQueueEnabled(getContext()));
+ mText = (TextView) findViewById(R.id.switch_label);
+ mText.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mSwitch.toggle();
+ }
+ });
+ mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ buttonView.setChecked(isChecked);
+ CMSettings.System.putInt(getContext().getContentResolver(),
+ CMSettings.System.NOTIFICATION_PLAY_QUEUE,
+ isChecked ? 1 : 0);
+ }
+ });
+ }
+
+
+ @Override
+ public void setActualHeight(int actualHeight) {
+ super.setActualHeight(actualHeight);
+ }
+
+ @Override
+ public int getActualHeight() {
+ return getHeight();
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+
+ // Prevents this view from creating a layer when alpha is animating.
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 46e0bf8..23912c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -28,9 +28,9 @@ import com.android.systemui.R;
*/
public class NotificationGuts extends FrameLayout {
- private Drawable mBackground;
- private int mClipTopAmount;
- private int mActualHeight;
+ protected Drawable mBackground;
+ protected int mClipTopAmount;
+ protected int mActualHeight;
public NotificationGuts(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java b/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java
new file mode 100644
index 0000000..1da2e5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.MediaDescription;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QueueView extends LinearLayout implements
+ QueueViewRow.UserRowInteractionListener, AdapterView.OnItemClickListener,
+ AdapterView.OnItemLongClickListener {
+
+ private static final String TAG = QueueView.class.getSimpleName();
+ private static final boolean DEBUG = MediaExpandableNotificationRow.DEBUG;
+
+ private MediaController mController;
+
+ private List<MediaSession.QueueItem> mQueue = new ArrayList<>(getMaxQueueRowCount());
+
+ private QueueItemAdapter mAdapter;
+ private ListView mList;
+ private boolean mQueueEnabled;
+
+ long mLastUserInteraction = -1;
+
+ private MediaController.Callback mCallback = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(@NonNull PlaybackState state) {
+ super.onPlaybackStateChanged(state);
+
+ if (getParent() != null && updateQueue(mController.getQueue())) {
+ getParent().requestLayout();
+ }
+ }
+
+ @Override
+ public void onSessionDestroyed() {
+ if (DEBUG) Log.d(TAG, "onSessionDestroyed() called with " + "");
+ super.onSessionDestroyed();
+ setController(null);
+ }
+ };
+
+ public QueueView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAdapter = new QueueItemAdapter(context);
+ setClipToOutline(false);
+ setClipToPadding(false);
+ }
+
+ public void setQueueEnabled(boolean enabled) {
+ mQueueEnabled = enabled;
+ mAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mList = (ListView) findViewById(R.id.queue_list);
+ mList.setItemsCanFocus(true);
+ mList.setDrawSelectorOnTop(true);
+ mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ mList.setAdapter(mAdapter);
+ mList.setOnItemLongClickListener(this);
+ mList.setOnItemClickListener(this);
+ mList.setVerticalScrollBarEnabled(false);
+ }
+
+ private class QueueItemAdapter extends ArrayAdapter<MediaSession.QueueItem> {
+
+ public QueueItemAdapter(Context context) {
+ super(context, R.layout.queue_adapter_row, mQueue);
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (position > getCount() - 1) {
+ return -1;
+ }
+ return getItem(position).getQueueId();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final MediaSession.QueueItem queueItem = getItem(position);
+
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.queue_adapter_row, parent, false);
+ }
+
+ QueueViewRow row = (QueueViewRow) convertView;
+ row.setHotSpotChangeListener(QueueView.this);
+
+ row.setQueueItem(queueItem);
+
+ return convertView;
+ }
+
+ @Override
+ public int getCount() {
+ if (!mQueueEnabled) {
+ return 0;
+ }
+ return super.getCount();
+ }
+ }
+
+ public boolean isUserSelectingRow() {
+ final long delta = System.currentTimeMillis() - mLastUserInteraction;
+ if (DEBUG) Log.i(TAG, "isUserSelectingRow() delta=" + delta);
+
+ if (mLastUserInteraction > 0 && delta < 500) {
+ if (DEBUG) Log.w(TAG, "user selecting row bc of hotspot change.");
+ return true;
+ }
+
+ return false;
+ }
+
+ public int getMaxQueueRowCount() {
+ return MediaExpandableNotificationRow.MAX_QUEUE_ENTRIES;
+ }
+
+ public int getCurrentQueueRowCount() {
+ if (mAdapter == null) {
+ return 0;
+ }
+ return mAdapter.getCount();
+ }
+
+ @Override
+ public void onHotSpotChanged(float x, float y) {
+ mLastUserInteraction = System.currentTimeMillis();
+ }
+
+ @Override
+ public void onDrawableStateChanged() {
+ mLastUserInteraction = System.currentTimeMillis();
+ }
+
+ /**
+ * @param queue
+ * @return whether the queue size has changed
+ */
+ public boolean updateQueue(List<MediaSession.QueueItem> queue) {
+ int queueSizeBefore = mAdapter.getCount();
+
+ mQueue.clear();
+
+ if (queue != null) {
+ // add everything *after* the currently playing item
+ boolean foundNowPlaying = false;
+
+ final PlaybackState playbackState = mController.getPlaybackState();
+
+ long activeQueueId = -1;
+ if (playbackState != null) {
+ activeQueueId = playbackState.getActiveQueueItemId();
+ }
+
+ for (int i = 0; i < queue.size() && mQueue.size() < getMaxQueueRowCount(); i++) {
+ final MediaSession.QueueItem item = queue.get(i);
+ if (!foundNowPlaying
+ && activeQueueId != -1
+ && activeQueueId == item.getQueueId()) {
+ foundNowPlaying = true;
+ continue;
+ }
+ if (foundNowPlaying) {
+ mQueue.add(item);
+ }
+ }
+
+ // add everything
+ if (!foundNowPlaying) {
+ for(int i = 0; i < getMaxQueueRowCount() && i < queue.size(); i++) {
+ mQueue.add(queue.get(i));
+ }
+ }
+ }
+ mAdapter.notifyDataSetChanged();
+
+ return mAdapter.getCount() != queueSizeBefore;
+ }
+
+ public boolean setController(MediaController controller) {
+ if (mController != null) {
+ mController.unregisterCallback(mCallback);
+ }
+ mController = controller;
+ if (mController != null) {
+ mController.registerCallback(mCallback);
+ }
+
+ return updateQueue(mController != null
+ ? mController.getQueue() : null);
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ final MediaSession.QueueItem itemAtPosition = (MediaSession.QueueItem)
+ parent.getItemAtPosition(position);
+ if (itemAtPosition != null && mController != null) {
+ mController.getTransportControls().skipToQueueItem(itemAtPosition.getQueueId());
+ }
+ mAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ return true;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QueueViewRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/QueueViewRow.java
new file mode 100644
index 0000000..dab89ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/QueueViewRow.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod 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;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.media.MediaDescription;
+import android.media.session.MediaSession;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import com.android.systemui.R;
+
+public class QueueViewRow extends RelativeLayout {
+
+ private static final String TAG = QueueViewRow.class.getSimpleName();
+
+ private UserRowInteractionListener mHotSpotChangeListener;
+
+ private ImageView mArt;
+ private TextView mTitle;
+ private TextView mSummary;
+
+ public QueueViewRow(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mArt = (ImageView) findViewById(R.id.art);
+ mTitle = (TextView) findViewById(R.id.title);
+ mSummary = (TextView) findViewById(R.id.summary);
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mHotSpotChangeListener != null) {
+ mHotSpotChangeListener.onDrawableStateChanged();
+ }
+ }
+
+ @Override
+ public void dispatchDrawableHotspotChanged(float x, float y) {
+ super.dispatchDrawableHotspotChanged(x, y);
+ if (mHotSpotChangeListener != null) {
+ mHotSpotChangeListener.onHotSpotChanged(x, y);
+ }
+ }
+
+ public void setHotSpotChangeListener(UserRowInteractionListener listener) {
+ mHotSpotChangeListener = listener;
+ }
+
+ public TextView getTitle() {
+ return mTitle;
+ }
+
+ public TextView getSummary() {
+ return mSummary;
+ }
+
+ public void setQueueItem(MediaSession.QueueItem queueItem) {
+ setTag(queueItem);
+
+ MediaDescription metadata = queueItem.getDescription();
+
+ final Bitmap bitmap = metadata.getIconBitmap();
+ mArt.setImageBitmap(bitmap);
+ mArt.setVisibility(bitmap != null ? View.VISIBLE : View.GONE);
+
+ mTitle.setText(metadata.getTitle());
+ mSummary.setText(metadata.getSubtitle());
+ }
+
+ /* package */ interface UserRowInteractionListener {
+ public void onHotSpotChanged(float x, float y);
+ public void onDrawableStateChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java
index 40e4330..538140c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java
@@ -32,11 +32,9 @@ import android.util.Log;
import android.view.View;
import com.android.systemui.cm.UserContentObserver;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
import cyanogenmod.providers.CMSettings;
-public class VisualizerView extends View implements Palette.PaletteAsyncListener,
- KeyguardMonitor.Callback {
+public class VisualizerView extends View implements Palette.PaletteAsyncListener {
private static final String TAG = VisualizerView.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -48,6 +46,7 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
private ValueAnimator[] mValueAnimators;
private float[] mFFTPoints;
+ private int mStatusBarState;
private boolean mVisualizerEnabled = false;
private boolean mVisible = false;
private boolean mPlaying = false;
@@ -59,7 +58,6 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
private int mColor;
private Bitmap mCurrentBitmap;
- private KeyguardMonitor mKeyguardMonitor;
private SettingsObserver mObserver;
private Visualizer.OnDataCaptureListener mVisualizerListener =
@@ -114,6 +112,13 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
}
};
+ private final Runnable mAsyncUnlinkVisualizer = new Runnable() {
+ @Override
+ public void run() {
+ AsyncTask.execute(mUnlinkVisualizer);
+ }
+ };
+
private final Runnable mUnlinkVisualizer = new Runnable() {
@Override
public void run() {
@@ -164,23 +169,19 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
this(context, null, 0);
}
- @Override
- public void onKeyguardChanged() {
- updateViewVisibility();
- }
-
private void updateViewVisibility() {
- setVisibility(mKeyguardMonitor != null && mKeyguardMonitor.isShowing()
- && mVisualizerEnabled ? View.VISIBLE : View.GONE);
- checkStateChanged();
+ final int curVis = getVisibility();
+ final int newVis = mStatusBarState != StatusBarState.SHADE
+ && mVisualizerEnabled ? View.VISIBLE : View.GONE;
+ if (curVis != newVis) {
+ setVisibility(newVis);
+ checkStateChanged();
+ }
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mKeyguardMonitor != null) {
- mKeyguardMonitor.addCallback(this);
- }
mObserver = new SettingsObserver(new Handler());
mObserver.observe();
mObserver.update();
@@ -189,23 +190,12 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mKeyguardMonitor != null) {
- mKeyguardMonitor.removeCallback(this);
- }
mObserver.unobserve();
mObserver = null;
mCurrentBitmap = null;
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- final int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
- setMeasuredDimension(size, size);
- }
-
- @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -223,7 +213,7 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
@Override
public boolean hasOverlappingRendering() {
- return mVisualizerEnabled && mDisplaying;
+ return false;
}
@Override
@@ -235,16 +225,6 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
}
}
- public void setKeyguardMonitor(KeyguardMonitor kgm) {
- mKeyguardMonitor = kgm;
- if (isAttachedToWindow()) {
- // otherwise we might never register ourselves
- mKeyguardMonitor.removeCallback(this);
- mKeyguardMonitor.addCallback(this);
- updateViewVisibility();
- }
- }
-
public void setVisible(boolean visible) {
if (mVisible != visible) {
if (DEBUG) {
@@ -295,6 +275,13 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
}
}
+ public void setStatusBarState(int statusBarState) {
+ if (mStatusBarState != statusBarState) {
+ mStatusBarState = statusBarState;
+ updateViewVisibility();
+ }
+ }
+
public void setBitmap(Bitmap bitmap) {
if (mCurrentBitmap == bitmap) {
return;
@@ -365,13 +352,12 @@ public class VisualizerView extends View implements Palette.PaletteAsyncListener
if (mVisible) {
animate()
.alpha(0f)
- .withEndAction(mUnlinkVisualizer)
+ .withEndAction(mAsyncUnlinkVisualizer)
.setDuration(600);
} else {
- AsyncTask.execute(mUnlinkVisualizer);
animate().
alpha(0f)
- .withEndAction(null)
+ .withEndAction(mAsyncUnlinkVisualizer)
.setDuration(0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 60ebfdf..e1a345f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -49,7 +49,7 @@ public class KeyguardAffordanceHelper {
private VelocityTracker mVelocityTracker;
private boolean mSwipingInProgress;
private float mInitialTouchX;
- private float mInitialTouchY;
+ private float mInitialTouchYRaw;
private float mTranslation;
private float mTranslationOnDown;
private int mTouchSlop;
@@ -128,7 +128,7 @@ public class KeyguardAffordanceHelper {
if (mMotionCancelled && action != MotionEvent.ACTION_DOWN) {
return false;
}
- final float y = event.getY();
+ final float y = event.getRawY();
final float x = event.getX();
boolean isUp = false;
@@ -146,7 +146,7 @@ public class KeyguardAffordanceHelper {
}
startSwiping(targetView);
mInitialTouchX = x;
- mInitialTouchY = y;
+ mInitialTouchYRaw = y;
mTranslationOnDown = mTranslation;
initVelocityTracker();
trackMovement(event);
@@ -159,7 +159,7 @@ public class KeyguardAffordanceHelper {
case MotionEvent.ACTION_MOVE:
trackMovement(event);
float xDist = x - mInitialTouchX;
- float yDist = y - mInitialTouchY;
+ float yDist = y - mInitialTouchYRaw;
float distance = (float) Math.hypot(xDist, yDist);
if (!mTouchSlopExeeded && distance > mTouchSlop) {
mTouchSlopExeeded = true;
@@ -211,8 +211,9 @@ public class KeyguardAffordanceHelper {
}
private boolean isOnIcon(View icon, float x, float y) {
+ int[] location = icon.getLocationOnScreen();
float iconX = icon.getX() + icon.getWidth() / 2.0f;
- float iconY = icon.getY() + icon.getHeight() / 2.0f;
+ float iconY = location[1] + icon.getHeight() / 2.0f;
double distance = Math.hypot(x - iconX, y - iconY);
return distance <= mTouchTargetSize / 2;
}
@@ -241,6 +242,13 @@ public class KeyguardAffordanceHelper {
return false;
}
+ public boolean isOnLockIcon(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getRawY();
+
+ return isOnIcon(mCenterIcon, x, y);
+ }
+
public void startHintAnimation(boolean right,
Runnable onFinishedListener) {
cancelAnimation();
@@ -488,7 +496,7 @@ public class KeyguardAffordanceHelper {
float aX = mVelocityTracker.getXVelocity();
float aY = mVelocityTracker.getYVelocity();
float bX = lastX - mInitialTouchX;
- float bY = lastY - mInitialTouchY;
+ float bY = lastY - mInitialTouchYRaw;
float bLen = (float) Math.hypot(bX, bY);
// Project the velocity onto the distance vector: a * b / |b|
float projectedVelocity = (aX * bX + aY * bY) / bLen;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d95a46a..b244e26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -29,14 +29,10 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.hardware.fingerprint.FingerprintManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
+import android.graphics.PixelFormat;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.fingerprint.FingerprintManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
@@ -50,8 +46,11 @@ import android.telecom.TelecomManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -73,6 +72,8 @@ import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.PreviewInflater;
+import java.util.Objects;
+
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -89,6 +90,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
+ public static final String CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE = "screen_gesture";
public static final String EXTRA_CAMERA_LAUNCH_SOURCE
= "com.android.systemui.camera_launch_source";
@@ -126,6 +128,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
private Messenger mPrewarmMessenger;
+ private final WindowManager mWindowManager;
+ private boolean mBottomAreaAttached;
+ private final WindowManager.LayoutParams mWindowLayoutParams;
+ private OnInterceptTouchEventListener mInterceptTouchListener;
+ private BroadcastReceiver mDevicePolicyReceiver;
+ private Intent mLastCameraIntent;
+
private final ServiceConnection mPrewarmConnection = new ServiceConnection() {
@Override
@@ -139,6 +148,48 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
};
+ @Override
+ public void setVisibility(int visibility) {
+ if (visibility == View.VISIBLE) {
+ if (!mBottomAreaAttached) {
+ addKeyguardBottomArea(false);
+ }
+ } else if (mBottomAreaAttached) {
+ removeKeyguardBottomArea();
+ }
+ super.setVisibility(visibility);
+ }
+
+ public void expand(boolean expand) {
+ addKeyguardBottomArea(expand);
+ }
+
+ private void addKeyguardBottomArea(boolean fullyExpand) {
+ mWindowLayoutParams.height = fullyExpand ? WindowManager.LayoutParams.MATCH_PARENT :
+ WindowManager.LayoutParams.WRAP_CONTENT;
+ if (!mBottomAreaAttached) {
+ try {
+ mWindowManager.addView(this, mWindowLayoutParams);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mBottomAreaAttached = true;
+ } else {
+ mWindowManager.updateViewLayout(this, mWindowLayoutParams);
+ }
+ }
+
+ private void removeKeyguardBottomArea() {
+ if (mBottomAreaAttached) {
+ try {
+ mWindowManager.removeView(this);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mBottomAreaAttached = false;
+ }
+ }
+
private AssistManager mAssistManager;
public KeyguardBottomAreaView(Context context) {
@@ -161,6 +212,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
mGrayScaleFilter = new ColorMatrixColorFilter(cm);
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+ mWindowLayoutParams = new WindowManager.LayoutParams();
+ mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+ mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ mWindowLayoutParams.privateFlags =
+ WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ mWindowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ mWindowLayoutParams.format = PixelFormat.TRANSPARENT;
+ mWindowLayoutParams.setTitle("KeyguardBottomArea");
+ mWindowLayoutParams.gravity = Gravity.BOTTOM;
}
private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@@ -417,6 +482,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private void watchForCameraPolicyChanges() {
final IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ mDevicePolicyReceiver = new DevicePolicyBroadcastReceiver();
getContext().registerReceiverAsUser(mDevicePolicyReceiver,
UserHandle.ALL, filter, null, null);
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
@@ -504,7 +570,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public void launchCamera(String source) {
final Intent intent;
- if (!mShortcutHelper.isTargetCustom(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT)) {
+ if (source.equals(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) ||
+ source.equals(CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE) ||
+ !mShortcutHelper.isTargetCustom(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT)) {
intent = getCameraIntent();
} else {
intent = mShortcutHelper.getIntent(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT);
@@ -656,10 +724,19 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
if (isTargetCustom(Shortcuts.RIGHT_SHORTCUT)) {
mPreviewContainer.removeView(mCameraPreview);
} else {
- mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
+ Intent cameraIntent = getCameraIntent();
+ if (!Objects.equals(cameraIntent, mLastCameraIntent)) {
+ if (mCameraPreview != null) {
+ mPreviewContainer.removeView(mCameraPreview);
+ }
+ mCameraPreview = mPreviewInflater.inflatePreview(cameraIntent);
+ if (mCameraPreview != null) {
+ mPreviewContainer.addView(mCameraPreview);
+ }
+ }
+ mLastCameraIntent = cameraIntent;
if (mCameraPreview != null) {
- mPreviewContainer.addView(mCameraPreview);
- mCameraPreview.setVisibility(View.INVISIBLE);
+ mCameraPreview.setVisibility(View.GONE);
}
}
}
@@ -681,7 +758,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
if (mLeftPreview != null) {
mPreviewContainer.addView(mLeftPreview);
- mLeftPreview.setVisibility(View.INVISIBLE);
+ mLeftPreview.setVisibility(View.GONE);
}
}
@@ -714,7 +791,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
.setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
}
- private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
+ public void cleanup() {
+ removeKeyguardBottomArea();
+ }
+
+ private final class DevicePolicyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
post(new Runnable() {
@@ -835,11 +916,42 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mAccessibilityController != null) {
+ mAccessibilityController.addStateChangedCallback(this);
+ }
+ mShortcutHelper.registerAndFetchTargets();
+ updateCustomShortcuts();
+ mUnlockMethodCache.addListener(this);
+ watchForCameraPolicyChanges();
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAccessibilityController.removeStateChangedCallback(this);
- mContext.unregisterReceiver(mDevicePolicyReceiver);
+ if (mDevicePolicyReceiver != null) {
+ mContext.unregisterReceiver(mDevicePolicyReceiver);
+ mDevicePolicyReceiver = null;
+ }
mShortcutHelper.cleanup();
mUnlockMethodCache.removeListener(this);
}
+
+ public interface OnInterceptTouchEventListener {
+ boolean onInterceptTouchEvent(MotionEvent e);
+ }
+
+ public void setOnInterceptTouchListener(OnInterceptTouchEventListener listener) {
+ mInterceptTouchListener = listener;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mInterceptTouchListener != null) {
+ return mInterceptTouchListener.onInterceptTouchEvent(ev);
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 65e2096..d992b17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -56,6 +56,7 @@ public class KeyguardBouncer {
private ViewGroup mRoot;
private boolean mShowingSoon;
private int mBouncerPromptReason;
+ private PhoneStatusBar mPhoneStatusBar;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -66,13 +67,14 @@ public class KeyguardBouncer {
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
- ViewGroup container) {
+ ViewGroup container, PhoneStatusBar phoneStatusBar) {
mContext = context;
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
mContainer = container;
mWindowManager = windowManager;
mCmLockPatternUtils = new CmLockPatternUtils(mContext);
+ mPhoneStatusBar = phoneStatusBar;
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
}
@@ -86,7 +88,15 @@ public class KeyguardBouncer {
if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
return;
}
-
+ // ensure external keyguard view does not have focus
+ mPhoneStatusBar.unfocusKeyguardExternalView();
+ mPhoneStatusBar.getScrimController().forceHideScrims(false);
+ // Don't hide bottom area if we are in the middle of a affordance
+ // launch transition, since once the animation is finished, NPV
+ // will take care of setting it invisible.
+ if (!mPhoneStatusBar.mNotificationPanel.isLaunchTransitionRunning()) {
+ mPhoneStatusBar.mKeyguardBottomArea.setVisibility(View.GONE);
+ }
// Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
// Keyguard. If we need to authenticate, show the bouncer.
if (!mKeyguardView.dismiss()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 8e58d14..cf39655 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -61,7 +61,8 @@ public class LockIcon extends KeyguardAffordanceView {
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
- if (isShown()) {
+ if (isShown() &&
+ KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive()) {
mTrustDrawable.start();
} else {
mTrustDrawable.stop();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java
index e767ca5..2028132 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java
@@ -63,6 +63,7 @@ public class NavBarInsetLayout extends FrameLayout {
public NavBarInsetLayout(Context context, AttributeSet attrs) {
super(context, attrs);
+ setMotionEventSplittingEnabled(false);
mTransparentSrcPaint.setColor(0);
mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index aaa7019..e4e02a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -18,37 +18,41 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.os.PowerManager;
+import android.os.RemoteException;
+import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.MathUtils;
+import android.view.Display;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -62,6 +66,7 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.QSDragPanel;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -73,22 +78,22 @@ import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
+import com.android.systemui.statusbar.policy.LiveLockScreenController;
+import com.android.systemui.statusbar.policy.WeatherController;
+import com.android.systemui.statusbar.policy.WeatherControllerImpl;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
-import cyanogenmod.externalviews.KeyguardExternalView;
import cyanogenmod.providers.CMSettings;
+import cyanogenmod.weather.util.WeatherUtils;
import java.util.List;
-import java.util.Objects;
-
-import org.cyanogenmod.internal.util.CmLockPatternUtils;
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
- HeadsUpManager.OnHeadsUpChangedListener {
+ HeadsUpManager.OnHeadsUpChangedListener, WeatherController.Callback {
private static final boolean DEBUG = false;
@@ -106,13 +111,19 @@ public class NotificationPanelView extends PanelView implements
private static final Rect mDummyDirtyRect = new Rect(0, 0, 1, 1);
- public static final long DOZE_ANIMATION_DURATION = 700;
+ private static final long SLIDE_PANEL_IN_ANIMATION_DURATION = 300;
+ private static final String KEY_USER_EXPANDED_NOTIFICATIONS_IN_KEYGUARD =
+ "user_expanded_notifications_in_keyguard";
+ private static final String KEY_USER_INTERACTED_WITH_LLS =
+ "user_interacted_with_lls";
+ private static final String KEY_USER_UNLOCKED =
+ "user_unlocked";
+ private static final String KEY_USER_RETURNED_FROM_LLS =
+ "user_returned_from_lls";
+
+ public static final long DOZE_ANIMATION_DURATION = 700;
- // Layout params for external keyguard view
- private static final FrameLayout.LayoutParams EXTERNAL_KEYGUARD_VIEW_PARAMS =
- new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
private KeyguardAffordanceHelper mAfforanceHelper;
private StatusBarHeaderView mHeader;
@@ -229,11 +240,6 @@ public class NotificationPanelView extends PanelView implements
private boolean mLaunchingAffordance;
private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
- private ComponentName mThirdPartyKeyguardViewComponent;
- private KeyguardExternalView mKeyguardExternalView;
- private CmLockPatternUtils mLockPatternUtils;
- private boolean mLiveLockScreenEnabled;
-
private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
@Override
public void run() {
@@ -254,6 +260,107 @@ public class NotificationPanelView extends PanelView implements
private int mStatusBarHeaderHeight;
private GestureDetector mDoubleTapGesture;
+ // Used to identify whether showUnlock() can dismiss the keyguard
+ // or not.
+ // TODO - add a new state to make it easier to identify keyguard vs
+ // LiveLockscreen
+ public boolean mCanDismissKeyguard;
+
+ // Used to track which direction the user is currently
+ // interacting with and ensure they don't alternate back
+ // and forth. Reset every MOTION_UP/MOTION_CANCEL
+ private SwipeLockedDirection mLockedDirection;
+
+ private SwipeHelper mSwipeHelper;
+ private final int mMinimumFlingVelocity;
+ private final int mScreenHeight;
+ private LiveLockScreenController mLiveLockscreenController;
+ private final GestureDetector mGestureDetector;
+ private ViewLinker mViewLinker;
+ private final UnlockMethodCache mUnlockMethodCache;
+ private boolean mDetailScrollLock;
+
+ private boolean mKeyguardWeatherEnabled;
+ private TextView mKeyguardWeatherInfo;
+ private WeatherControllerImpl mWeatherController;
+
+ // Keep track of common user interactions on the lock screen
+ private boolean mUserUnlocked;
+ private boolean mUserExpandedNotifications;
+ private boolean mUserInteractedWithLiveLockScreen;
+ private boolean mUserReturnedFromLiveLockScreen;
+
+ private boolean mScreenOnHintsEnabled;
+
+ private enum SwipeLockedDirection {
+ UNKNOWN,
+ HORIZONTAL,
+ VERTICAL
+ }
+
+ // Handles swiping to the LiveLockscreen from keyguard
+ SwipeHelper.SimpleCallback mSwipeCallback = new SwipeHelper.SimpleCallback() {
+ @Override
+ public View getChildAtPosition(MotionEvent ev) {
+ return mViewLinker.getParent();
+ }
+
+ @Override
+ public View getChildContentView(View v) {
+ return mViewLinker.getParent();
+ }
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return true;
+ }
+
+ @Override
+ public void onChildDismissed(View v) {
+ mCanDismissKeyguard = false;
+ mStatusBar.focusKeyguardExternalView();
+ mLiveLockscreenController.onLiveLockScreenFocusChanged(true /* hasFocus */);
+ if (!mUserInteractedWithLiveLockScreen) {
+ mUserInteractedWithLiveLockScreen = true;
+ saveUserInteractedWithLls(true);
+ }
+ if (!mUserReturnedFromLiveLockScreen) {
+ startShowNotificationsHintAnimation();
+ }
+ resetAlphaTranslation();
+ // Enables the left edge gesture to allow user
+ // to return to keyguard
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .setLiveLockscreenEdgeDetector(true);
+ } catch (RemoteException e){
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
+ // Let live lockscreen know of swipe progress to allow
+ // them to translate content in.
+ mLiveLockscreenController.getLiveLockScreenView()
+ .onLockscreenSlideOffsetChanged(swipeProgress);
+
+ // Fade out scrim background
+ float alpha = ScrimController.SCRIM_BEHIND_ALPHA_KEYGUARD - (1f - swipeProgress);
+ alpha = Math.max(0, alpha);
+ mStatusBar.getScrimController().setScrimBehindColor(alpha);
+ return false;
+ }
+
+ private void resetAlphaTranslation() {
+ mNotificationStackScroller.setTranslationX(0);
+ mNotificationStackScroller.setAlpha(1f);
+
+ mKeyguardStatusView.setTranslationX(0);
+ mKeyguardStatusView.setAlpha(1f);
+ }
+ };
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(!DEBUG);
@@ -268,12 +375,78 @@ public class NotificationPanelView extends PanelView implements
return true;
}
});
+
+ Resources res = getContext().getResources();
+ final int gradientStart = res.getColor(R.color.live_lockscreen_gradient_start);
+ final int gradientEnd = res.getColor(R.color.live_lockscreen_gradient_end);
+ mGestureDetector = new GestureDetector(getContext(),
+ new GestureDetector.SimpleOnGestureListener() {
+ private float mDown;
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ // Ensure we only capture swipes in the up direction
+ if (velocityY > 0 || Math.abs(velocityY) <= mMinimumFlingVelocity) {
+ return false;
+ }
+ mCanDismissKeyguard = true;
+ mStatusBar.showBouncer();
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ float delta = mDown - e2.getRawY();
+ delta = Math.max(0, delta);
+ float screenHeightHalf = (float) mScreenHeight / 2f;
+ int color = (Integer) ArgbEvaluator.getInstance()
+ .evaluate(delta / screenHeightHalf, gradientStart, gradientEnd);
+ mKeyguardBottomArea.setBackgroundColor(color);
+ return super.onScroll(e1, e2, distanceX, distanceY);
+ }
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ mDown = e.getRawY();
+ mKeyguardBottomArea.expand(true);
+ return true;
+ }
+ });
+
+ mSwipeHelper = new SwipeHelper(SwipeHelper.X,
+ SwipeHelper.SWIPE_ZONE_LEFT, mSwipeCallback, mContext);
+ mSwipeHelper.setSwipeProgressFadeEnd(1.0f);
+ mMinimumFlingVelocity = ViewConfiguration.get(getContext())
+ .getScaledMinimumFlingVelocity();
+
+ WindowManager windowManager = (WindowManager) mContext
+ .getSystemService(Context.WINDOW_SERVICE);
+ Display display = windowManager.getDefaultDisplay();
+ Point point = new Point();
+ display.getSize(point);
+ mScreenHeight = point.y;
+ mUnlockMethodCache = UnlockMethodCache.getInstance(context);
+
+ mScreenOnHintsEnabled = res.getBoolean(R.bool.config_showScreenOnLockScreenHints);
+ mUserUnlocked = getUserUnlocked();
+ mUserExpandedNotifications = getUserExpandedNotificationsInKeyguard();
+ mUserInteractedWithLiveLockScreen = getUserInteractedWithLls();
+ mUserReturnedFromLiveLockScreen = getUserReturnedFromLls();
}
public void setStatusBar(PhoneStatusBar bar) {
mStatusBar = bar;
}
+ public void setLiveController(LiveLockScreenController liveController) {
+ mLiveLockscreenController = liveController;
+ }
+
+ public void setWeatherController(WeatherControllerImpl weatherController) {
+ mWeatherController = weatherController;
+ mWeatherController.addCallback(this);
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -283,6 +456,7 @@ public class NotificationPanelView extends PanelView implements
mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
mQsPanel = (QSDragPanel) findViewById(R.id.quick_settings_panel);
+ mQsPanel.setPanelView(this);
mClockView = (TextView) findViewById(R.id.clock_view);
mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
mScrollView.setFocusable(false);
@@ -301,7 +475,64 @@ public class NotificationPanelView extends PanelView implements
android.R.interpolator.fast_out_linear_in);
mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.linear_out_slow_in);
- mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
+
+ mViewLinker = new ViewLinker<NotificationStackScrollLayout>(mNotificationStackScroller,
+ new ViewLinker.LinkInfo(mKeyguardStatusBar, ViewLinker.LINK_ALPHA),
+ new ViewLinker.LinkInfo(mKeyguardStatusView, ViewLinker.LINK_ALPHA
+ | ViewLinker.LINK_TRANSLATION));
+
+ mKeyguardBottomArea = (KeyguardBottomAreaView) View.inflate(getContext(),
+ R.layout.keyguard_bottom_area, null);
+ /** Keyguard bottom area lives in a separate window, and as such,
+ * we must redirect its touch events through the proper flow
+ */
+ mKeyguardBottomArea.setOnInterceptTouchListener(new KeyguardBottomAreaView.OnInterceptTouchEventListener() {
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent e) {
+ boolean intercept = false;
+ if (mLiveLockscreenController.getLiveLockScreenHasFocus()) {
+ // Handles swipe up to fade/dismiss when showing
+ // live lock screen
+ intercept = mAfforanceHelper.onInterceptTouchEvent(e);
+ if (!intercept) {
+ intercept = mGestureDetector.onTouchEvent(e);
+ }
+ } else {
+ intercept = NotificationPanelView.this.onInterceptTouchEvent(e);
+ }
+ return intercept;
+ }
+ });
+ mKeyguardBottomArea.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent e) {
+ int action = e.getAction();
+
+ boolean isCancelOrUp = action == MotionEvent.ACTION_UP ||
+ action == MotionEvent.ACTION_CANCEL;
+ if (isCancelOrUp) {
+ mKeyguardBottomArea.setBackground(null);
+ }
+
+ boolean intercept = false;
+ if (mLiveLockscreenController.getLiveLockScreenHasFocus()) {
+ intercept = mAfforanceHelper.onTouchEvent(e);
+ // If the touch did not originate on the affordance helper,
+ // we must collapse the panel here since we can't rely on
+ // the swipe callbacks from being invoked.
+ if (isCancelOrUp && !isAffordanceSwipeInProgress()) {
+ mKeyguardBottomArea.expand(false);
+ }
+ if (!intercept) {
+ intercept = mGestureDetector.onTouchEvent(e);
+ }
+ } else {
+ intercept = NotificationPanelView.this.onTouchEvent(e);
+ }
+ return intercept;
+ }
+ });
+
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
mLastOrientation = getResources().getConfiguration().orientation;
@@ -319,19 +550,17 @@ public class NotificationPanelView extends PanelView implements
}
});
- mLockPatternUtils = new CmLockPatternUtils(getContext());
- if (mLockPatternUtils.isThirdPartyKeyguardEnabled() && mLiveLockScreenEnabled) {
- mThirdPartyKeyguardViewComponent = mLockPatternUtils.getThirdPartyKeyguardComponent();
- }
+ mKeyguardWeatherInfo = (TextView) mKeyguardStatusView.findViewById(R.id.weather_info);
+ }
+
+ public boolean isAffordanceSwipeInProgress() {
+ return mAfforanceHelper.isSwipingInProgress();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mSettingsObserver.observe();
- mContext.registerReceiver(mExternalKeyguardViewChangedReceiver,
- new IntentFilter(CmLockPatternUtils.ACTION_THIRD_PARTY_KEYGUARD_COMPONENT_CHANGED));
-
mScrollView.setListener(this);
}
@@ -339,7 +568,7 @@ public class NotificationPanelView extends PanelView implements
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mSettingsObserver.unobserve();
- mContext.unregisterReceiver(mExternalKeyguardViewChangedReceiver);
+ mWeatherController.removeCallback(this);
}
@Override
@@ -619,6 +848,10 @@ public class NotificationPanelView extends PanelView implements
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ // Reset locked direction
+ mLockedDirection = SwipeLockedDirection.UNKNOWN;
+ mCanDismissKeyguard = true;
+
if (mBlockTouches) {
return false;
}
@@ -640,7 +873,15 @@ public class NotificationPanelView extends PanelView implements
if (!isFullyCollapsed() && onQsIntercept(event)) {
return true;
}
- return super.onInterceptTouchEvent(event);
+
+ if (isKeyguardInteractiveAndShowing() || mStatusBar.isKeyguardShowingMedia() ||
+ (mUnlockMethodCache.isTrustManaged() && mAfforanceHelper.isOnLockIcon(event))) {
+ return super.onInterceptTouchEvent(event);
+ }
+
+ // We want both, we really do
+ return mSwipeHelper.onInterceptTouchEvent(event)
+ & super.onInterceptTouchEvent(event);
}
private boolean onQsIntercept(MotionEvent event) {
@@ -795,6 +1036,12 @@ public class NotificationPanelView extends PanelView implements
if (mBlockTouches) {
return false;
}
+
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mKeyguardBottomArea.setBackground(null);
+ }
+
if (mDoubleTapToSleepEnabled
&& mStatusBarState == StatusBarState.KEYGUARD
&& event.getY() < mStatusBarHeaderHeight) {
@@ -808,7 +1055,8 @@ public class NotificationPanelView extends PanelView implements
}
if ((!mIsExpanding || mHintAnimationRunning)
&& !mQsExpanded
- && mStatusBar.getBarState() != StatusBarState.SHADE) {
+ && (mStatusBar.getBarState() != StatusBarState.SHADE
+ || mLiveLockscreenController.getLiveLockScreenHasFocus())) {
mAfforanceHelper.onTouchEvent(event);
}
if (mOnlyAffordanceInThisMotion) {
@@ -822,10 +1070,39 @@ public class NotificationPanelView extends PanelView implements
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
updateVerticalPanelPosition(event.getX());
}
- super.onTouchEvent(event);
+
+ if (isKeyguardInteractiveAndShowing() || mStatusBar.isKeyguardShowingMedia() ||
+ (mUnlockMethodCache.isTrustManaged() && mAfforanceHelper.isOnLockIcon(event))) {
+ super.onTouchEvent(event);
+ return true;
+ }
+
+ if ((!mIsExpanding || mHintAnimationRunning)
+ && !mQsExpanded
+ && mLockedDirection != SwipeLockedDirection.VERTICAL
+ && mStatusBar.getBarState() != StatusBarState.SHADE) {
+ mSwipeHelper.onTouchEvent(event);
+ if (mSwipeHelper.isDragging()) {
+ mLockedDirection = SwipeLockedDirection.HORIZONTAL;
+ }
+ if (mLockedDirection == SwipeLockedDirection.HORIZONTAL) {
+ requestDisallowInterceptTouchEvent(true);
+ return true;
+ }
+ }
+
+ if (super.onTouchEvent(event)) {
+ mLockedDirection = SwipeLockedDirection.VERTICAL;
+ }
return true;
}
+ private boolean isKeyguardInteractiveAndShowing() {
+ return mLiveLockscreenController.getLiveLockScreenHasFocus() ||
+ mStatusBar.getBarState() != StatusBarState.KEYGUARD ||
+ !mLiveLockscreenController.isLiveLockScreenInteractive();
+ }
+
private boolean handleQsTouch(MotionEvent event) {
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
@@ -857,7 +1134,8 @@ public class NotificationPanelView extends PanelView implements
mTwoFingerQsExpandPossible = true;
}
if (mTwoFingerQsExpandPossible && isOpenQsEvent(event)
- && event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
+ && event.getY(event.getActionIndex()) < mStatusBarMinHeight
+ && mExpandedHeight <= mQsPeekHeight) {
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1);
mQsExpandImmediate = true;
requestPanelHeightUpdate();
@@ -915,7 +1193,7 @@ public class NotificationPanelView extends PanelView implements
private void handleQsDown(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN
- && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
+ && shouldQuickSettingsIntercept(event.getX(), event.getRawY(), -1)) {
mQsTracking = true;
onQsExpansionStarted();
mInitialHeightOnTouch = mQsExpansionHeight;
@@ -997,8 +1275,13 @@ public class NotificationPanelView extends PanelView implements
mTrackingPointer = -1;
trackMovement(event);
float fraction = getQsExpansionFraction();
- if ((fraction != 0f || y >= mInitialTouchY)
- && (fraction != 1f || y <= mInitialTouchY)) {
+ final boolean fling = (fraction != 0f || y >= mInitialTouchY)
+ && (fraction != 1f || y <= mInitialTouchY);
+ final boolean flingExpand = Math.abs(getCurrentVelocity())
+ > mFlingAnimationUtils.getMinVelocityPxPerSecond();
+ final boolean detailFling = mDetailScrollLock && mQsExpanded
+ && flingExpand;
+ if ((fling && !mDetailScrollLock) || detailFling) {
flingQsWithCurrentVelocity(y,
event.getActionMasked() == MotionEvent.ACTION_CANCEL);
} else {
@@ -1099,9 +1382,17 @@ public class NotificationPanelView extends PanelView implements
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
+ if (oldState != statusBarState && statusBarState == StatusBarState.KEYGUARD) {
+ mCanDismissKeyguard = true;
+ }
- if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
- && statusBarState == StatusBarState.SHADE_LOCKED)) {
+ boolean keyguardToShadeLocked = oldState == StatusBarState.KEYGUARD
+ && statusBarState == StatusBarState.SHADE_LOCKED;
+ if (goingToFullShade || keyguardToShadeLocked) {
+ if (keyguardToShadeLocked && !mUserExpandedNotifications) {
+ mUserExpandedNotifications = true;
+ saveUserExpandedNotificationsInKeyguard(true);
+ }
animateKeyguardStatusBarOut();
animateHeaderSlidingIn();
} else if (oldState == StatusBarState.SHADE_LOCKED
@@ -1116,26 +1407,14 @@ public class NotificationPanelView extends PanelView implements
mAfforanceHelper.updatePreviews();
}
}
+ if (oldState != StatusBarState.SHADE && statusBarState == StatusBarState.SHADE &&
+ !mUserUnlocked) {
+ mUserUnlocked = true;
+ saveUserUnlocked(true);
+ }
if (statusBarState == StatusBarState.KEYGUARD ||
statusBarState == StatusBarState.SHADE_LOCKED) {
updateDozingVisibilities(false /* animate */);
- if (mThirdPartyKeyguardViewComponent != null) {
- if (mKeyguardExternalView == null) {
- mKeyguardExternalView =
- getExternalKeyguardView(mThirdPartyKeyguardViewComponent);
- if (mKeyguardExternalView != null) {
- mKeyguardExternalView.registerKeyguardExternalViewCallback(
- mExternalKeyguardViewCallbacks);
- }
- }
- if (mKeyguardExternalView != null && !mKeyguardExternalView.isAttachedToWindow()) {
- addView(mKeyguardExternalView, 0, EXTERNAL_KEYGUARD_VIEW_PARAMS);
- }
- }
- } else {
- if (mKeyguardExternalView != null && mKeyguardExternalView.isAttachedToWindow()) {
- removeView(mKeyguardExternalView);
- }
}
resetVerticalPanelPosition();
updateQsState();
@@ -1213,82 +1492,6 @@ public class NotificationPanelView extends PanelView implements
}
};
- private KeyguardExternalView.KeyguardExternalViewCallbacks mExternalKeyguardViewCallbacks =
- new KeyguardExternalView.KeyguardExternalViewCallbacks() {
- @Override
- public boolean requestDismiss() {
- if (hasExternalKeyguardView()) {
- post(new Runnable() {
- @Override
- public void run() {
- mStatusBar.showKeyguard();
- mStatusBar.showBouncer();
- }
- });
- return true;
- }
- return false;
- }
-
- @Override
- public boolean requestDismissAndStartActivity(final Intent intent) {
- if (hasExternalKeyguardView()) {
- if (hasExternalKeyguardView()) {
- post(new Runnable() {
- @Override
- public void run() {
- mStatusBar.showKeyguard();
- mStatusBar.startActivityDismissingKeyguard(intent, false, true, true,
- null);
- }
- });
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void collapseNotificationPanel() {
- if (mStatusBar.getBarState() == StatusBarState.KEYGUARD && hasExternalKeyguardView() &&
- mKeyguardExternalView.isInteractive()) {
- post(new Runnable() {
- @Override
- public void run() {
- mStatusBar.focusKeyguardExternalView();
- }
- });
- }
- }
-
- @Override
- public void providerDied() {
- mKeyguardExternalView.unregisterKeyguardExternalViewCallback(
- mExternalKeyguardViewCallbacks);
- mKeyguardExternalView = null;
- }
- };
-
- private BroadcastReceiver mExternalKeyguardViewChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String pkgName = getSendingPackage(intent);
- if (pkgName != null) {
- PackageManager pm = context.getPackageManager();
- if (pm.checkPermission(android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
- pkgName) != PackageManager.PERMISSION_GRANTED) {
- // we should not be here if the sending app does not have the proper permission,
- // so do nothing and return.
- return;
- }
- } else {
- // null package name? something is not right so just return and skip doing anything
- return;
- }
- updateExternalKeyguardView();
- }
- };
-
private void animateHeaderSlidingIn() {
// If the QS is already expanded we don't need to slide in the header as it's already
// visible.
@@ -1487,8 +1690,7 @@ public class NotificationPanelView extends PanelView implements
if (mKeyguardShowing) {
updateHeaderKeyguard();
}
- if (mStatusBarState == StatusBarState.SHADE_LOCKED
- || mStatusBarState == StatusBarState.KEYGUARD) {
+ if (mStatusBarState == StatusBarState.KEYGUARD) {
updateKeyguardBottomAreaAlpha();
}
if (mStatusBarState == StatusBarState.SHADE && mQsExpanded
@@ -1669,7 +1871,8 @@ public class NotificationPanelView extends PanelView implements
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
- return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
+ return onHeader || mDetailScrollLock
+ || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
} else {
return onHeader;
}
@@ -1759,7 +1962,7 @@ public class NotificationPanelView extends PanelView implements
*/
private int getTempQsMaxExpansion() {
int qsTempMaxExpansion = mQsMaxExpansionHeight;
- if (mScrollYOverride != -1) {
+ if (mScrollYOverride != -1 && !mDetailScrollLock) {
qsTempMaxExpansion -= mScrollYOverride;
}
return qsTempMaxExpansion;
@@ -1926,12 +2129,14 @@ public class NotificationPanelView extends PanelView implements
}
private void updateHeaderKeyguardAlpha() {
+ if (mSwipeHelper.isDragging()) {
+ return;
+ }
float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
* mKeyguardStatusBarAnimateAlpha);
mKeyguardStatusBar.setVisibility(mKeyguardStatusBar.getAlpha() != 0f
&& !mDozing ? VISIBLE : INVISIBLE);
- mStatusBar.getVisualizer().setAlpha(mKeyguardStatusBar.getAlpha());
}
private void updateHeaderKeyguard() {
@@ -1941,6 +2146,9 @@ public class NotificationPanelView extends PanelView implements
private void updateKeyguardBottomAreaAlpha() {
float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
+ if (mLiveLockscreenController.getLiveLockScreenHasFocus()) {
+ alpha = 1f;
+ }
mKeyguardBottomArea.setAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
@@ -2164,10 +2372,12 @@ public class NotificationPanelView extends PanelView implements
mLaunchAnimationEndRunnable.run();
mLaunchAnimationEndRunnable = null;
}
+ mKeyguardBottomArea.setVisibility(View.GONE);
}
@Override
protected void startUnlockHintAnimation() {
+ mKeyguardBottomArea.expand(true);
super.startUnlockHintAnimation();
startHighlightIconAnimation(getCenterIcon());
}
@@ -2202,11 +2412,13 @@ public class NotificationPanelView extends PanelView implements
requestDisallowInterceptTouchEvent(true);
mOnlyAffordanceInThisMotion = true;
mQsTracking = false;
+ mKeyguardBottomArea.expand(true);
}
@Override
public void onSwipingAborted() {
mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
+ mKeyguardBottomArea.expand(false);
}
@Override
@@ -2215,6 +2427,8 @@ public class NotificationPanelView extends PanelView implements
return;
}
mHintAnimationRunning = true;
+ mKeyguardBottomArea.expand(true);
+ mKeyguardBottomArea.getIndicationView().animate().cancel();
mAfforanceHelper.startHintAnimation(rightIcon, new Runnable() {
@Override
public void run() {
@@ -2395,11 +2609,6 @@ public class NotificationPanelView extends PanelView implements
// Hide "No notifications" in QS.
mNotificationStackScroller.updateEmptyShadeView(mShadeEmpty && !mQsExpanded);
- if (mStatusBarState == StatusBarState.KEYGUARD
- && (!mQsExpanded || mQsExpandImmediate || mIsExpanding
- && mQsExpandedWhenExpandingStarted)) {
- positionClockAndNotifications();
- }
}
public void setQsScrimEnabled(boolean qsScrimEnabled) {
@@ -2423,6 +2632,11 @@ public class NotificationPanelView extends PanelView implements
public void onScreenTurningOn() {
mKeyguardStatusView.refreshTime();
+ if (shouldShowScreenOnHints()) {
+ startScreenOnHintAnimation(mLiveLockscreenController.isLiveLockScreenInteractive() &&
+ !mUserInteractedWithLiveLockScreen,
+ !mUserUnlocked, !mUserExpandedNotifications);
+ }
}
@Override
@@ -2584,6 +2798,10 @@ public class NotificationPanelView extends PanelView implements
return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
}
+ public KeyguardBottomAreaView getKeyguardBottomArea() {
+ return mKeyguardBottomArea;
+ }
+
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
@@ -2596,7 +2814,7 @@ public class NotificationPanelView extends PanelView implements
resolver.registerContentObserver(CMSettings.System.getUriFor(
CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false, this);
resolver.registerContentObserver(CMSettings.Secure.getUriFor(
- CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED), false, this);
+ CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED), false, this);
update();
}
@@ -2622,11 +2840,12 @@ public class NotificationPanelView extends PanelView implements
mDoubleTapToSleepEnabled = CMSettings.System.getInt(
resolver, CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE, 1) == 1;
- boolean liveLockScreenEnabled = CMSettings.Secure.getInt(
- resolver, CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED, 0) == 1;
- if (liveLockScreenEnabled != mLiveLockScreenEnabled) {
- mLiveLockScreenEnabled = liveLockScreenEnabled;
- updateExternalKeyguardView();
+ boolean wasKeyguardWeatherEnabled = mKeyguardWeatherEnabled;
+ mKeyguardWeatherEnabled = CMSettings.Secure.getInt(
+ resolver, CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED, 0) == 1;
+ if (mWeatherController != null
+ && wasKeyguardWeatherEnabled != mKeyguardWeatherEnabled) {
+ onWeatherChanged(mWeatherController.getWeatherInfo());
}
}
}
@@ -2641,6 +2860,8 @@ public class NotificationPanelView extends PanelView implements
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
} else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
+ } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE;
} else {
// Default.
@@ -2650,7 +2871,8 @@ public class NotificationPanelView extends PanelView implements
// If we are launching it when we are occluded already we don't want it to animate,
// nor setting these flags, since the occluded state doesn't change anymore, hence it's
// never reset.
- if (!isFullyCollapsed()) {
+ if (!isFullyCollapsed() && mLastCameraLaunchSource ==
+ KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE) {
mLaunchingAffordance = true;
setLaunchingAffordance(true);
} else {
@@ -2699,48 +2921,158 @@ public class NotificationPanelView extends PanelView implements
return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
}
- public boolean hasExternalKeyguardView() {
- return mKeyguardExternalView != null && mKeyguardExternalView.isAttachedToWindow();
+ public void setDetailRequestedScrollLock(boolean detailScrollFlag) {
+ if (mDetailScrollLock != detailScrollFlag) {
+ if (mStatusBarState != StatusBarState.SHADE) {
+ mDetailScrollLock = false;
+ } else {
+ mDetailScrollLock = detailScrollFlag;
+ }
+ if (!detailScrollFlag && getQsExpansionFraction() > 0.3f) {
+ flingSettings(getCurrentVelocity(), true, new Runnable() {
+ @Override
+ public void run() {
+ mStackScrollerOverscrolling = false;
+ mQsExpansionFromOverscroll = false;
+ updateQsState();
+ updateHeader();
+ updateMaxHeadsUpTranslation();
+ updatePanelExpanded();
+ requestLayout();
+ }
+ }, false);
+ } else {
+ requestLayout();
+ }
+ }
}
- public boolean isExternalKeyguardViewInteractive() {
- return mKeyguardExternalView != null && mKeyguardExternalView.isInteractive();
+ @Override
+ public void onWeatherChanged(WeatherController.WeatherInfo info) {
+ if (!mKeyguardWeatherEnabled || Double.isNaN(info.temp) || info.condition == null) {
+ mKeyguardWeatherInfo.setVisibility(GONE);
+ } else {
+ mKeyguardWeatherInfo.setText(mContext.getString(
+ R.string.keyguard_status_view_weather_format,
+ WeatherUtils.formatTemperature(info.temp, info.tempUnit),
+ info.condition));
+ mKeyguardWeatherInfo.setVisibility(VISIBLE);
+ }
}
- public KeyguardExternalView getExternalKeyguardView() {
- return mKeyguardExternalView;
- }
+ private class SlideInAnimationListener implements ValueAnimator.AnimatorUpdateListener,
+ ValueAnimator.AnimatorListener {
+ @Override
+ public void onAnimationStart(Animator animator) {}
- private KeyguardExternalView getExternalKeyguardView(ComponentName componentName) {
- try {
- return new KeyguardExternalView(getContext(), null, componentName);
- } catch (Exception e) {
- // just return null below and move on
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ animationFinished(animator);
}
- return null;
- }
- private void updateExternalKeyguardView() {
- ComponentName cn = mLiveLockScreenEnabled ?
- mLockPatternUtils.getThirdPartyKeyguardComponent() : null;
- // If mThirdPartyKeyguardViewComponent differs from cn, go ahead and update
- if (!Objects.equals(mThirdPartyKeyguardViewComponent, cn)) {
- mThirdPartyKeyguardViewComponent = cn;
- if (mKeyguardExternalView != null) {
- if (indexOfChild(mKeyguardExternalView) >= 0) {
- removeView(mKeyguardExternalView);
- }
- mKeyguardExternalView.unregisterKeyguardExternalViewCallback(
- mExternalKeyguardViewCallbacks);
- if (mThirdPartyKeyguardViewComponent != null) {
- mKeyguardExternalView =
- getExternalKeyguardView(mThirdPartyKeyguardViewComponent);
- mKeyguardExternalView.registerKeyguardExternalViewCallback(
- mExternalKeyguardViewCallbacks);
- } else {
- mKeyguardExternalView = null;
- }
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ animationFinished(animator);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {}
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ View statusBarView = mStatusBar.getStatusBarWindow();
+ if (valueAnimator.getAnimatedFraction() > 0 &&
+ statusBarView.getVisibility() != View.VISIBLE) {
+ statusBarView.setVisibility(View.VISIBLE);
}
+ float translationX = (Float) valueAnimator.getAnimatedValue();
+ float alpha = valueAnimator.getAnimatedFraction();
+
+ mViewLinker.getParent().setTranslationX(translationX);
+ mViewLinker.getParent().setAlpha(alpha);
+
+ float alpha1 = ScrimController.SCRIM_BEHIND_ALPHA_KEYGUARD * alpha;
+ alpha1 = Math.max(0, alpha1);
+ mStatusBar.getScrimController().setScrimBehindColor(alpha1);
+ mLiveLockscreenController.getLiveLockScreenView()
+ .onLockscreenSlideOffsetChanged(alpha);
}
+
+ private void animationFinished(Animator animator) {
+ mLiveLockscreenController.onLiveLockScreenFocusChanged(false);
+ }
+ }
+
+ private SlideInAnimationListener mSlideInAnimationListener = new SlideInAnimationListener();
+
+ public void slideLockScreenIn() {
+ mNotificationStackScroller.setVisibility(View.VISIBLE);
+ mNotificationStackScroller.setAlpha(0f);
+ mNotificationStackScroller.setTranslationX(-mNotificationStackScroller.getWidth());
+ mKeyguardStatusView.setVisibility(View.VISIBLE);
+ mKeyguardStatusView.setAlpha(0f);
+ mKeyguardStatusView.setTranslationX(mNotificationStackScroller.getTranslationX());
+ mKeyguardStatusBar.setAlpha(0f);
+
+ mStatusBar.getScrimController().setScrimBehindColor(0f);
+ ValueAnimator animator = ValueAnimator.ofFloat(
+ mNotificationStackScroller.getTranslationX(),
+ 0f);
+ animator.setDuration(SLIDE_PANEL_IN_ANIMATION_DURATION);
+ animator.addUpdateListener(mSlideInAnimationListener);
+ animator.addListener(mSlideInAnimationListener);
+ animator.start();
+
+ if (!mUserReturnedFromLiveLockScreen) {
+ mUserReturnedFromLiveLockScreen = true;
+ saveUserReturnedFromLls(true);
+ }
+ }
+
+ private void saveBooleanSharedPreference(String key, boolean value) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ prefs.edit().putBoolean(key, value).apply();
+ }
+
+ private boolean getSharedPreferenceBoolean(String key, boolean defValue) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ return prefs.getBoolean(key, defValue);
+ }
+
+ private void saveUserExpandedNotificationsInKeyguard(boolean expanded) {
+ saveBooleanSharedPreference(KEY_USER_EXPANDED_NOTIFICATIONS_IN_KEYGUARD, expanded);
+ }
+
+ private boolean getUserExpandedNotificationsInKeyguard() {
+ return getSharedPreferenceBoolean(KEY_USER_EXPANDED_NOTIFICATIONS_IN_KEYGUARD, false);
+ }
+
+ private void saveUserInteractedWithLls(boolean interacted) {
+ saveBooleanSharedPreference(KEY_USER_INTERACTED_WITH_LLS, interacted);
+ }
+
+ private boolean getUserInteractedWithLls() {
+ return getSharedPreferenceBoolean(KEY_USER_INTERACTED_WITH_LLS, false);
+ }
+
+ private void saveUserUnlocked(boolean unlocked) {
+ saveBooleanSharedPreference(KEY_USER_UNLOCKED, unlocked);
+ }
+
+ private boolean getUserUnlocked() {
+ return getSharedPreferenceBoolean(KEY_USER_UNLOCKED, false);
+ }
+
+ private void saveUserReturnedFromLls(boolean revealed) {
+ saveBooleanSharedPreference(KEY_USER_RETURNED_FROM_LLS, revealed);
+ }
+
+ private boolean getUserReturnedFromLls() {
+ return getSharedPreferenceBoolean(KEY_USER_RETURNED_FROM_LLS, false);
+ }
+
+ public boolean shouldShowScreenOnHints() {
+ return mScreenOnHintsEnabled && mStatusBar.isDeviceProvisioned() &&
+ mStatusBarState == StatusBarState.KEYGUARD;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 82b1e1d..e1a400d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -146,16 +146,6 @@ public abstract class PanelBar extends FrameLayout {
return result;
}
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- for (PanelView pv : mPanels) {
- pv.setBar(null);
- }
- mPanels.clear();
- mPanelHolder.setBar(null);
- }
-
// called from PanelView when self-expanding, too
public void startOpeningPanel(PanelView panel) {
if (DEBUG) LOG("startOpeningPanel: " + panel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e5711b8..3a2c84c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -49,6 +49,9 @@ public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
+ private static final long ANIMATION_FADE_DURATION = 1000L;
+ private static final long HINT_DELAY_DURATION = 1500L;
+
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
}
@@ -94,7 +97,7 @@ public abstract class PanelView extends FrameLayout {
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
// update expand height
- if (mHeightAnimator != null && mExpanding && mUpdateExpandOnLayout) {
+ if (mHeightAnimator != null && mExpanding && mUpdateExpandOnLayout && !mJustPeeked) {
final int maxPanelHeight = getMaxPanelHeight();
final PropertyValuesHolder[] values = mHeightAnimator.getValues();
values[0].setFloatValues(maxPanelHeight);
@@ -121,6 +124,9 @@ public abstract class PanelView extends FrameLayout {
private boolean mPeekPending;
private boolean mCollapseAfterPeek;
+ private boolean mShowExpandHint;
+ private boolean mShowUnlockHint;
+ private boolean mScreenOnHintAnimationRunning;
/**
* Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
@@ -674,7 +680,7 @@ public abstract class PanelView extends FrameLayout {
}
mUpdateExpandOnLayout = isFullyCollapsed();
mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
- if (expandBecauseOfFalsing) {
+ if (expandBecauseOfFalsing && vel == 0) {
animator.setDuration(350);
}
} else {
@@ -928,6 +934,7 @@ public abstract class PanelView extends FrameLayout {
private void abortAnimations() {
cancelPeek();
cancelHeightAnimator();
+ mKeyguardBottomArea.getIndicationView().animate().cancel();
removeCallbacks(mPostCollapseRunnable);
removeCallbacks(mFlingCollapseRunnable);
}
@@ -946,6 +953,8 @@ public abstract class PanelView extends FrameLayout {
}
cancelPeek();
notifyExpandingStarted();
+ mKeyguardBottomArea.getIndicationView().animate().cancel();
+ mStatusBar.onUnlockHintStarted();
startUnlockHintAnimationPhase1(new Runnable() {
@Override
public void run() {
@@ -954,8 +963,8 @@ public abstract class PanelView extends FrameLayout {
mHintAnimationRunning = false;
}
});
- mStatusBar.onUnlockHintStarted();
mHintAnimationRunning = true;
+ mShowExpandHint = false;
}
/**
@@ -989,6 +998,7 @@ public abstract class PanelView extends FrameLayout {
mKeyguardBottomArea.getIndicationView().animate()
.translationY(-mHintDistance)
.setDuration(250)
+ .setStartDelay(0)
.setInterpolator(mFastOutSlowInInterpolator)
.withEndAction(new Runnable() {
@Override
@@ -1011,17 +1021,213 @@ public abstract class PanelView extends FrameLayout {
animator.setDuration(450);
animator.setInterpolator(mBounceInterpolator);
animator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
mHeightAnimator = null;
- onAnimationFinished.run();
- notifyBarPanelExpansionChanged();
+ if (mCancelled) {
+ onAnimationFinished.run();
+ } else {
+ if (mShowExpandHint) {
+ startUnlockHintFadeOutAnimationPhase(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();
+ notifyBarPanelExpansionChanged();
+ }
+ }
}
});
animator.start();
mHeightAnimator = animator;
}
+ /**
+ * Fade in unlock hint
+ */
+ private void startUnlockHintFadeInAnimationPhase(final Runnable onAnimationFinished) {
+ mStatusBar.onUnlockHintStarted();
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(0)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mShowExpandHint) {
+ startUnlockHintFadeOutAnimationPhase(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();
+ notifyBarPanelExpansionChanged();
+ }
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade out unlock hint
+ */
+ private void startUnlockHintFadeOutAnimationPhase(final Runnable onAnimationFinished) {
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(0)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(HINT_DELAY_DURATION)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ startExpandHintAnimation(onAnimationFinished);
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade in Lls hint
+ */
+ private void startLlsHintFadeInAnimationPhase(final Runnable onAnimationFinished) {
+ mKeyguardBottomArea.getIndicationView().setAlpha(0);
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(0)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mShowUnlockHint || mShowExpandHint) {
+ startLlsHintFadeOutAnimationPhase(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();;
+ }
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade out Lls hint
+ */
+ private void startLlsHintFadeOutAnimationPhase(final Runnable onAnimationFinished) {
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(0)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(HINT_DELAY_DURATION)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mShowUnlockHint) {
+ startUnlockHintFadeInAnimationPhase(onAnimationFinished);
+ } else if (mShowExpandHint) {
+ startExpandHintAnimation(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();
+ }
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade in expand hint
+ */
+ private void startExpandHintAnimation(final Runnable onAnimationFinished) {
+ mStatusBar.onExpandHintStarted();
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(0)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ onAnimationFinished.run();
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Show notifications hint (swipe right hint)
+ */
+ protected void startShowNotificationsHintAnimation() {
+ cancelPeek();
+ mStatusBar.onNotificationsHintStarted();
+ mHintAnimationRunning = true;
+ mKeyguardBottomArea.getIndicationView().setAlpha(0);
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBar.onHintFinished();
+ mHintAnimationRunning = false;
+ }
+ })
+ .start();
+ }
+
+ protected void startScreenOnHintAnimation(boolean showSwipeLeftHint, boolean showUnlockHint,
+ boolean showExpandHint) {
+ // We don't need to hint the user if an animation is already running or the user is changing
+ // the expansion.
+ if (mHintAnimationRunning || mScreenOnHintAnimationRunning) return;
+
+ final View indicationView = mKeyguardBottomArea.getIndicationView();
+ indicationView.animate().cancel();
+ indicationView.animate().setListener(
+ new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) { }
+
+ @Override
+ public void onAnimationEnd(Animator animation) { }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mScreenOnHintAnimationRunning = false;
+ indicationView.setAlpha(1f);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
+ });
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ mStatusBar.onHintFinished();
+ mScreenOnHintAnimationRunning = false;
+ }
+ };
+ if (showSwipeLeftHint) {
+ mStatusBar.onLlsHintStarted();
+ startLlsHintFadeInAnimationPhase(r);
+ } else if (showUnlockHint) {
+ mStatusBar.onUnlockHintStarted();
+ startUnlockHintFadeInAnimationPhase(r);
+ } else if (showExpandHint) {
+ mStatusBar.onExpandHintStarted();
+ startExpandHintAnimation(r);
+ } else {
+ return;
+ }
+ indicationView.setAlpha(0);
+ mShowUnlockHint = showUnlockHint;
+ mShowExpandHint = showExpandHint;
+ mScreenOnHintAnimationRunning = true;
+ }
+
private ValueAnimator createHeightAnimator(float targetHeight) {
ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index adff973..7df8346 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -17,14 +17,11 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.settings.BrightnessController.BRIGHTNESS_ADJ_RESOLUTION;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -103,13 +100,13 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
+import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -136,10 +133,7 @@ import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSDragPanel;
-import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSTile;
import com.android.systemui.recents.ScreenPinningRequest;
-import com.android.systemui.settings.BrightnessController;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -150,6 +144,7 @@ import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.MediaExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationOverflowContainer;
@@ -173,6 +168,7 @@ import com.android.systemui.statusbar.policy.HotspotControllerImpl;
import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
+import com.android.systemui.statusbar.policy.LiveLockScreenController;
import com.android.systemui.statusbar.policy.LocationControllerImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
@@ -321,6 +317,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
WeatherControllerImpl mWeatherController;
SuControllerImpl mSuController;
FingerprintUnlockController mFingerprintUnlockController;
+ LiveLockScreenController mLiveLockScreenController;
int mNaturalBarHeight = -1;
@@ -329,7 +326,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
StatusBarWindowView mStatusBarWindow;
FrameLayout mStatusBarWindowContent;
- PhoneStatusBarView mStatusBarView;
+ private PhoneStatusBarView mStatusBarView;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
private StatusBarWindowManager mStatusBarWindowManager;
private UnlockMethodCache mUnlockMethodCache;
@@ -497,6 +494,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+ public void setStatusBarViewVisibility(boolean visible) {
+ mStatusBarView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+
class DevForceNavbarObserver extends UserContentObserver {
DevForceNavbarObserver(Handler handler) {
super(handler);
@@ -506,14 +507,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
protected void observe() {
super.observe();
ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(CMSettings.Secure.getUriFor(
- CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Global.getUriFor(
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR), false, this, UserHandle.USER_ALL);
}
@Override
public void update() {
- boolean visible = CMSettings.Secure.getIntForUser(mContext.getContentResolver(),
- CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
+ boolean visible = CMSettings.Global.getIntForUser(mContext.getContentResolver(),
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
if (visible) {
forceAddNavigationBar();
@@ -539,7 +540,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNavigationBarView.setDisabledFlags(mDisabled1);
mNavigationBarView.setBar(this);
- addNavigationBar();
+ addNavigationBar(true); // dynamically adding nav bar, reset System UI visibility!
}
// ensure quick settings is disabled until the current user makes it through the setup wizard
@@ -792,6 +793,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private RankingMap mLatestRankingMap;
private boolean mNoAnimationOnNextBarModeChange;
+ public ScrimController getScrimController() {
+ return mScrimController;
+ }
+
@Override
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
@@ -809,7 +814,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStatusBarWindow = new StatusBarWindowView(mContext, null);
mStatusBarWindow.setService(this);
-
+
super.start(); // calls createAndAddWindows()
mMediaSessionManager
@@ -817,7 +822,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// TODO: use MediaSessionManager.SessionListener to hook us up to future updates
// in session state
- addNavigationBar();
+ addNavigationBar(false);
// Developer options - Force Navigation bar
try {
@@ -882,9 +887,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Resources res = context.getResources();
- mScreenWidth = (float) context.getResources().getDisplayMetrics().widthPixels;
- mMinBrightness = context.getResources().getInteger(
- com.android.internal.R.integer.config_screenBrightnessDim);
+ mScreenWidth = (float) res.getDisplayMetrics().widthPixels;
+ mMinBrightness = res.getInteger(com.android.internal.R.integer.config_screenBrightnessDim);
updateDisplaySize(); // populates mDisplayMetrics
updateResources(null);
@@ -920,6 +924,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
R.color.notification_panel_solid_background)));
}
+ mLiveLockScreenController = new LiveLockScreenController(mContext, this,
+ mNotificationPanel);
+ mNotificationPanel.setLiveController(mLiveLockScreenController);
+ if (mStatusBarWindowManager != null) {
+ mStatusBarWindowManager.setLiveLockscreenController(mLiveLockScreenController);
+ }
if (mHeadsUpManager == null) {
mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
@@ -1032,12 +1042,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mHeader.setActivityStarter(this);
mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindowContent.findViewById(R.id.keyguard_header);
mKeyguardStatusView = mStatusBarWindowContent.findViewById(R.id.keyguard_status_view);
- mKeyguardBottomArea =
- (KeyguardBottomAreaView) mStatusBarWindowContent.findViewById(R.id.keyguard_bottom_area);
+ mKeyguardBottomArea = mNotificationPanel.getKeyguardBottomArea();
+
mKeyguardBottomArea.setActivityStarter(this);
mKeyguardBottomArea.setAssistManager(mAssistManager);
mKeyguardIndicationController = new KeyguardIndicationController(mContext,
- (KeyguardIndicationTextView) mStatusBarWindowContent.findViewById(
+ (KeyguardIndicationTextView) mKeyguardBottomArea.findViewById(
R.id.keyguard_indication_text),
mKeyguardBottomArea.getLockIcon());
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
@@ -1181,7 +1191,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNetworkController, mZenModeController, mHotspotController,
mCastController, mFlashlightController,
mUserSwitcherController, mKeyguardMonitor,
- mSecurityController);
+ mSecurityController, mBatteryController);
}
mQSPanel.setHost(mQSTileHost);
if (mBrightnessMirrorController == null) {
@@ -1315,10 +1325,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- mVisualizerView.setKeyguardMonitor(mKeyguardMonitor);
mHeader.setNextAlarmController(mNextAlarmController);
mHeader.setWeatherController(mWeatherController);
+ mNotificationPanel.setWeatherController(mWeatherController);
+
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mBroadcastReceiver.onReceive(mContext,
new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
@@ -1490,7 +1501,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void run() {
boolean isUpdate = mQSPanel.getHost().getCustomTileData()
- .get(sbc.getKey()) != null;
+ .get(sbc.persistableKey()) != null;
if (isUpdate) {
mQSPanel.getHost().updateCustomTile(sbc);
} else {
@@ -1506,7 +1517,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mHandler.post(new Runnable() {
@Override
public void run() {
- mQSPanel.getHost().removeCustomTileSysUi(sbc.getKey());
+ mQSPanel.getHost().removeCustomTileSysUi(sbc.persistableKey());
}
});
}
@@ -1568,16 +1579,26 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- private void prepareNavigationBarView() {
+ private void prepareNavigationBarView(boolean forceReset) {
mNavigationBarView.reorient();
mNavigationBarView.setListeners(mRecentsClickListener, mRecentsPreloadOnTouchListener,
mLongPressBackRecentsListener, mHomeActionListener, mLongPressHomeListener);
mAssistManager.onConfigurationChanged();
+ if (forceReset) {
+ // Nav Bar was added dynamically - we need to reset the mSystemUiVisibility and call
+ // setSystemUiVisibility so that mNavigationBarMode is set to the correct value
+ int newVal = mSystemUiVisibility;
+ mSystemUiVisibility = 0;
+ setSystemUiVisibility(newVal, SYSTEM_UI_VISIBILITY_MASK);
+ checkBarMode(mNavigationBarMode,
+ mNavigationBarWindowState, mNavigationBarView.getBarTransitions(),
+ mNoAnimationOnNextBarModeChange);
+ }
}
// For small-screen devices (read: phones) that lack hardware navigation buttons
- private void addNavigationBar() {
+ private void addNavigationBar(boolean forceReset) {
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
if (mNavigationBarView == null) return;
@@ -1588,7 +1609,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return;
}
- prepareNavigationBarView();
+ prepareNavigationBarView(forceReset);
mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}
@@ -1604,7 +1625,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void repositionNavigationBar() {
if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
- prepareNavigationBarView();
+ prepareNavigationBarView(false);
mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams());
}
@@ -1966,7 +1987,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- protected void updateRowStates() {
+ public void updateRowStates() {
super.updateRowStates();
mNotificationPanel.notifyVisibleChildrenChanged();
}
@@ -2080,6 +2101,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
+ mMediaMetadata);
}
+ if (mediaNotification != null
+ && mediaNotification.row != null
+ && mediaNotification.row instanceof MediaExpandableNotificationRow) {
+ ((MediaExpandableNotificationRow) mediaNotification.row)
+ .setMediaController(controller);
+ }
if (mediaNotification != null) {
mMediaNotificationKey = mediaNotification.notification.getKey();
@@ -2195,7 +2222,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
// apply user lockscreen image
- if (backdropBitmap == null && !mNotificationPanel.hasExternalKeyguardView()) {
+ if (backdropBitmap == null && !mLiveLockScreenController.isShowingLiveLockScreenView()) {
backdropBitmap = mKeyguardWallpaper;
}
@@ -2476,6 +2503,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mMediaNotificationKey;
}
+ @Override
+ protected MediaController getCurrentMediaController() {
+ return mMediaController;
+ }
+
public boolean isScrimSrcModeEnabled() {
return mScrimSrcModeEnabled;
}
@@ -2938,7 +2970,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
}
- if (mBrightnessChanged && upOrCancel) {
+ if (mBrightnessChanged && upOrCancel && !isQsExpanded()) {
mBrightnessChanged = false;
if (mJustPeeked && mExpandedVisible) {
mNotificationPanel.fling(10, false);
@@ -3433,6 +3465,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStatusBarWindowManager = new StatusBarWindowManager(mContext, mKeyguardMonitor);
mStatusBarWindowManager.setShowingMedia(mKeyguardShowingMedia);
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
+ if (mLiveLockScreenController != null) {
+ mStatusBarWindowManager.setLiveLockscreenController(mLiveLockScreenController);
+ }
}
// called by makeStatusbar and also by PhoneStatusBarView
@@ -3565,10 +3600,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else if (cyanogenmod.content.Intent.ACTION_SCREEN_CAMERA_GESTURE.equals(action)) {
boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
- if (!userSetupComplete) {
- if (DEBUG) Log.d(TAG, String.format(
- "userSetupComplete = %s, ignoring camera launch gesture.",
- userSetupComplete));
+ if (!userSetupComplete || !isDeviceProvisioned()) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("userSetupComplete = $1%s, " +
+ "deviceProvisioned = $2%s, ignoring camera launch gesture.",
+ userSetupComplete, isDeviceProvisioned()));
+ }
return;
}
@@ -3661,6 +3698,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mIconController.updateResources();
mScreenPinningRequest.onConfigurationChanged();
mNetworkController.onConfigurationChanged();
+ mStatusBarWindowManager.onConfigurationChanged(newConfig);
}
@Override
@@ -3686,6 +3724,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+ public void hideHeadsUp() {
+ if (mUseHeadsUp && mHeadsUpManager != null) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ }
+
private void setControllerUsers() {
if (mZenModeController != null) {
mZenModeController.setUserId(mCurrentUserId);
@@ -3753,7 +3797,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mKeyguardIndicationController != null) {
mKeyguardIndicationController.cleanup();
}
+ if (mLiveLockScreenController != null) {
+ mLiveLockScreenController.cleanup();
+ }
+ mKeyguardBottomArea.cleanup();
mStatusBarWindow.removeContent(mStatusBarWindowContent);
mStatusBarWindow.clearDisappearingChildren();
@@ -3836,6 +3884,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mState == StatusBarState.KEYGUARD) {
// this will make sure the keyguard is showing
showKeyguard();
+ // make sure to hide the notification icon area and system iconography
+ // to avoid overlap (CYNGNOS-2253)
+ mIconController.hideNotificationIconArea(false);
+ mIconController.hideSystemIconArea(false);
}
// update mLastThemeChangeTime
@@ -3854,7 +3906,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
removeAllViews((ViewGroup) child);
}
}
- parent.removeAllViews();
+
+ // AdapterView does not support removeAllViews so check before calling
+ if (!(parent instanceof AdapterView)) parent.removeAllViews();
}
/**
@@ -4307,8 +4361,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mDraggedDownRow = null;
}
mAssistManager.onLockscreenShown();
- if (mNotificationPanel.hasExternalKeyguardView()) {
- mNotificationPanel.getExternalKeyguardView().onKeyguardShowing(
+ mKeyguardBottomArea.requestFocus();
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .setLiveLockscreenEdgeDetector(false);
+ } catch (RemoteException e){
+ e.printStackTrace();
+ }
+ if (mLiveLockScreenController.isShowingLiveLockScreenView()) {
+ mLiveLockScreenController.onLiveLockScreenFocusChanged(false);
+ mLiveLockScreenController.getLiveLockScreenView().onKeyguardShowing(
mStatusBarKeyguardViewManager.isScreenTurnedOn());
}
}
@@ -4461,8 +4523,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNotificationPanel.onAffordanceLaunchEnded();
mNotificationPanel.animate().cancel();
mNotificationPanel.setAlpha(1f);
- if ( mNotificationPanel.getExternalKeyguardView() != null) {
- mNotificationPanel.getExternalKeyguardView().onKeyguardDismissed();
+ if (mLiveLockScreenController.isShowingLiveLockScreenView()) {
+ mLiveLockScreenController.getLiveLockScreenView().onKeyguardDismissed();
}
return staying;
}
@@ -4477,6 +4539,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isSecure();
}
+ public boolean isKeyguardInputRestricted() {
+ return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isInputRestricted();
+ }
+
public long calculateGoingToFullShadeDelay() {
return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
}
@@ -4552,6 +4618,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mIconPolicy.setKeyguardShowing(false);
}
mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
+ mLiveLockScreenController.setBarState(mState);
updateDozingState();
updatePublicMode();
updateStackScrollerState(goingToFullShade);
@@ -4640,24 +4707,28 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return false;
}
- protected void showBouncer() {
- if (!mRecreating &&
- (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
+ public void showBouncer() {
+ if (!mRecreating && mNotificationPanel.mCanDismissKeyguard
+ && (mState != StatusBarState.SHADE || mLiveLockScreenController.getLiveLockScreenHasFocus())) {
mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
mStatusBarKeyguardViewManager.dismiss();
}
}
protected void showBouncerOrFocusKeyguardExternalView() {
- if (mNotificationPanel.hasExternalKeyguardView() && !isKeyguardShowingMedia() &&
- mNotificationPanel.isExternalKeyguardViewInteractive()) {
+ if (mLiveLockScreenController.isShowingLiveLockScreenView() && !isKeyguardShowingMedia() &&
+ mLiveLockScreenController.isLiveLockScreenInteractive()) {
focusKeyguardExternalView();
} else {
showBouncer();
}
}
- protected void focusKeyguardExternalView() {
+ protected void unfocusKeyguardExternalView() {
+ mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(false);
+ }
+
+ public void focusKeyguardExternalView() {
mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/,
1.0f /* speedUpFactor */);
mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(true);
@@ -4701,6 +4772,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
clearNotificationEffects();
}
mState = state;
+ mVisualizerView.setStatusBarState(state);
mGroupManager.setStatusBarState(state);
mStatusBarWindowManager.setStatusBarState(state);
updateDozing();
@@ -4723,12 +4795,33 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public void onUnlockHintStarted() {
- mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
+ mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock,
+ mNotificationPanel.shouldShowScreenOnHints() ?
+ KeyguardIndicationController.IndicationDirection.UP :
+ KeyguardIndicationController.IndicationDirection.NONE);
+ }
+
+ public void onLlsHintStarted() {
+ String llsName = mLiveLockScreenController.getLiveLockScreenName();
+ mKeyguardIndicationController.showTransientIndication(
+ mContext.getString(R.string.swipe_left_hint, llsName),
+ KeyguardIndicationController.IndicationDirection.LEFT);
+ }
+
+ public void onExpandHintStarted() {
+ mKeyguardIndicationController.showTransientIndication(R.string.expand_hint,
+ KeyguardIndicationController.IndicationDirection.DOWN);
+ }
+
+ public void onNotificationsHintStarted() {
+ mKeyguardIndicationController.showTransientIndication(R.string.swipe_right_hint,
+ KeyguardIndicationController.IndicationDirection.RIGHT);
}
public void onHintFinished() {
// Delay the reset a bit so the user can read the text.
mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
+ mKeyguardBottomArea.expand(false);
}
public void onCameraHintStarted(String hint) {
@@ -4741,19 +4834,22 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void onTrackingStopped(boolean expand) {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- if (!expand && (!mUnlockMethodCache.canSkipBouncer() ||
- mNotificationPanel.hasExternalKeyguardView())) {
- showBouncerOrFocusKeyguardExternalView();
+ if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
+ showBouncer();
}
- } else if (expand && mStatusBarWindowManager.keyguardExternalViewHasFocus()) {
- mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(false);
- setBarState(StatusBarState.KEYGUARD);
}
}
@Override
protected int getMaxKeyguardNotifications() {
- return mKeyguardMaxNotificationCount;
+ int max = mKeyguardMaxNotificationCount;
+ // When an interactive live lockscreen is showing
+ // we want to limit the number of maximum notifications
+ // by 1 so there is additional space for the user to dismiss keygard
+ if (mLiveLockScreenController.isLiveLockScreenInteractive()) {
+ max--;
+ }
+ return max;
}
public NavigationBarView getNavigationBarView() {
@@ -4911,15 +5007,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mScreenTurningOn = false;
mDozeScrimController.onScreenTurnedOn();
mVisualizerView.setVisible(true);
- if (mNotificationPanel.hasExternalKeyguardView()) {
- mNotificationPanel.getExternalKeyguardView().onScreenTurnedOn();
+ if (mLiveLockScreenController.isShowingLiveLockScreenView()) {
+ mLiveLockScreenController.onScreenTurnedOn();
}
}
public void onScreenTurnedOff() {
mVisualizerView.setVisible(false);
- if (mNotificationPanel.hasExternalKeyguardView()) {
- mNotificationPanel.getExternalKeyguardView().onScreenTurnedOff();
+ if (mLiveLockScreenController.isShowingLiveLockScreenView()) {
+ mLiveLockScreenController.onScreenTurnedOff();
}
}
@@ -5326,6 +5422,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mVisualizerView;
}
+ public boolean isShowingLiveLockScreenView() {
+ return mLiveLockScreenController.isShowingLiveLockScreenView();
+ }
+
+ public void slideNotificationPanelIn() {
+ mNotificationPanel.slideLockScreenIn();
+ }
+
private final class ShadeUpdates {
private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
@@ -5478,4 +5582,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
}
+
+ public boolean isAffordanceSwipeInProgress() {
+ return mNotificationPanel.isAffordanceSwipeInProgress();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index ed4880b..1395ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,6 +22,8 @@ import android.app.AlarmManager.AlarmClockInfo;
import android.app.IUserSwitchObserver;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.bluetooth.BluetoothAssignedNumbers;
+import android.bluetooth.BluetoothHeadset;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -103,6 +105,7 @@ public class PhoneStatusBarPolicy implements Callback {
private boolean mZenVisible;
private boolean mVolumeVisible;
private boolean mCurrentUserSetup;
+ private Float mBluetoothBatteryLevel = null;
private int mZen;
@@ -129,6 +132,9 @@ public class PhoneStatusBarPolicy implements Callback {
else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
updateTTY(intent);
}
+ else if (action.equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
+ updateBluetoothBattery(intent);
+ }
}
};
@@ -166,6 +172,9 @@ public class PhoneStatusBarPolicy implements Callback {
filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
+ filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
+ filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY
+ + "." + Integer.toString(BluetoothAssignedNumbers.APPLE));
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// listen for user / profile change.
@@ -357,6 +366,27 @@ public class PhoneStatusBarPolicy implements Callback {
updateBluetooth();
}
+ private void updateBluetoothBattery(Intent intent) {
+ if (intent.hasExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD)) {
+ String command = intent.getStringExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
+ if ("+IPHONEACCEV".equals(command)) {
+ Object[] args = (Object[]) intent.getSerializableExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
+ if (args.length >= 3 && args[0] instanceof Integer && ((Integer)args[0])*2+1<=args.length) {
+ for (int i=0;i<((Integer)args[0]);i++) {
+ if (!(args[i*2+1] instanceof Integer) || !(args[i*2+2] instanceof Integer)) {
+ continue;
+ }
+ if (args[i*2+1].equals(1)) {
+ mBluetoothBatteryLevel = (((Integer)args[i*2+2])+1)/10.0f;
+ updateBluetooth();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
private final void updateBluetooth() {
int iconId = R.drawable.stat_sys_data_bluetooth;
String contentDescription =
@@ -365,8 +395,24 @@ public class PhoneStatusBarPolicy implements Callback {
if (mBluetooth != null) {
bluetoothEnabled = mBluetooth.isBluetoothEnabled();
if (mBluetooth.isBluetoothConnected()) {
- iconId = R.drawable.stat_sys_data_bluetooth_connected;
+ if (mBluetoothBatteryLevel == null) {
+ iconId = R.drawable.stat_sys_data_bluetooth_connected;
+ } else {
+ if (mBluetoothBatteryLevel<=0.15f) {
+ iconId = R.drawable.stat_sys_data_bluetooth_connected_battery_1;
+ } else if (mBluetoothBatteryLevel<=0.375f) {
+ iconId = R.drawable.stat_sys_data_bluetooth_connected_battery_2;
+ } else if (mBluetoothBatteryLevel<=0.625f) {
+ iconId = R.drawable.stat_sys_data_bluetooth_connected_battery_3;
+ } else if (mBluetoothBatteryLevel<=0.85f) {
+ iconId = R.drawable.stat_sys_data_bluetooth_connected_battery_4;
+ } else {
+ iconId = R.drawable.stat_sys_data_bluetooth_connected_battery_5;
+ }
+ }
contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
+ } else {
+ mBluetoothBatteryLevel = null;
}
}
@@ -474,6 +520,12 @@ public class PhoneStatusBarPolicy implements Callback {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
mUserInfoController.reloadUserInfo();
+ if (reply != null) {
+ try {
+ reply.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 3b068d6..8c9daee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -111,6 +111,7 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public void onPanelPeeked() {
super.onPanelPeeked();
+ removePendingHideExpandedRunnables();
mBar.makeExpandedVisible(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index b776a9f..e88ed73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -54,7 +54,6 @@ import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HeadsUpTile;
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.IntentTile;
-import com.android.systemui.qs.tiles.LiveDisplayTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.LockscreenToggleTile;
import com.android.systemui.qs.tiles.NfcTile;
@@ -67,6 +66,7 @@ import com.android.systemui.qs.tiles.UsbTetherTile;
import com.android.systemui.qs.tiles.VolumeTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.statusbar.CustomTileData;
+import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -115,6 +115,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
private final UserSwitcherController mUserSwitcherController;
private final KeyguardMonitor mKeyguard;
private final SecurityController mSecurity;
+ private final BatteryController mBattery;
private CustomTileData mCustomTileData;
private CustomTileListenerService mCustomTileListenerService;
@@ -127,7 +128,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
ZenModeController zen, HotspotController hotspot,
CastController cast, FlashlightController flashlight,
UserSwitcherController userSwitcher, KeyguardMonitor keyguard,
- SecurityController security) {
+ SecurityController security, BatteryController battery) {
mContext = context;
mStatusBar = statusBar;
mBluetooth = bluetooth;
@@ -141,6 +142,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
mUserSwitcherController = userSwitcher;
mKeyguard = keyguard;
mSecurity = security;
+ mBattery = battery;
mCustomTileData = new CustomTileData();
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
@@ -281,6 +283,11 @@ public class QSTileHost implements QSTile.Host, Tunable {
return mKeyguard;
}
+ @Override
+ public BatteryController getBatteryController() {
+ return mBattery;
+ }
+
public UserSwitcherController getUserSwitcherController() {
return mUserSwitcherController;
}
@@ -311,10 +318,12 @@ public class QSTileHost implements QSTile.Host, Tunable {
if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
try {
if (mCustomTileData.get(tileSpec) != null) {
- newTiles.put(tileSpec, new CustomQSTile(this,
- mCustomTileData.get(tileSpec).sbc));
+ final CustomQSTile value = new CustomQSTile(this,
+ mCustomTileData.get(tileSpec).sbc);
+ newTiles.put(tileSpec, value);
} else {
- newTiles.put(tileSpec, createTile(tileSpec));
+ final QSTile<?> tile = createTile(tileSpec);
+ newTiles.put(tileSpec, tile);
}
} catch (Throwable t) {
Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
@@ -361,12 +370,16 @@ public class QSTileHost implements QSTile.Host, Tunable {
else if (tileSpec.equals("performance")) return new PerfProfileTile(this);
else if (tileSpec.equals("lockscreen")) return new LockscreenToggleTile(this);
else if (tileSpec.equals("ambient_display")) return new AmbientDisplayTile(this);
- else if (tileSpec.equals("live_display")) return new LiveDisplayTile(this);
else if (tileSpec.equals("heads_up")) return new HeadsUpTile(this);
else if (tileSpec.equals("battery_saver")) return new BatterySaverTile(this);
else if (tileSpec.equals("caffeine")) return new CaffeineTile(this);
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
- else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
+ else if (TextUtils.split(tileSpec, "\\|").length == 3) {
+ /** restores placeholder for
+ * {@link cyanogenmod.app.StatusBarPanelCustomTile#persistableKey()} **/
+ return new CustomQSTile(this, tileSpec);
+ } else
+ throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
}
protected List<String> loadTileSpecs(String tileList) {
@@ -393,11 +406,10 @@ public class QSTileHost implements QSTile.Host, Tunable {
tiles.add(tile);
}
}
- // ensure edit tile is present
- if (tiles.size() < TILES_PER_PAGE && !tiles.contains("edit")) {
+ // ensure edit tile is present, default placement should be handled in the default
+ // tile list.
+ if (!tiles.contains("edit")) {
tiles.add("edit");
- } else if (tiles.size() > TILES_PER_PAGE && !tiles.contains("edit")) {
- tiles.add((TILES_PER_PAGE - 1), "edit");
}
return tiles;
}
@@ -455,7 +467,6 @@ public class QSTileHost implements QSTile.Host, Tunable {
else if (spec.equals("performance")) return R.string.qs_tile_performance;
else if (spec.equals("lockscreen")) return R.string.quick_settings_lockscreen_label;
else if (spec.equals("ambient_display")) return R.string.quick_settings_ambient_display_label;
- else if (spec.equals("live_display")) return R.string.live_display_title;
else if (spec.equals("heads_up")) return R.string.quick_settings_heads_up_label;
else if (spec.equals("battery_saver")) return R.string.quick_settings_battery_saver_label;
else if (spec.equals("caffeine")) return R.string.quick_settings_caffeine_label;
@@ -486,7 +497,6 @@ public class QSTileHost implements QSTile.Host, Tunable {
else if (spec.equals("performance")) return R.drawable.ic_qs_perf_profile;
else if (spec.equals("lockscreen")) return R.drawable.ic_qs_lock_screen_on;
else if (spec.equals("ambient_display")) return R.drawable.ic_qs_ambientdisplay_on;
- else if (spec.equals("live_display")) return R.drawable.ic_livedisplay_auto;
else if (spec.equals("heads_up")) return R.drawable.ic_qs_heads_up_on;
else if (spec.equals("battery_saver")) return R.drawable.ic_qs_battery_saver_on;
else if (spec.equals("caffeine")) return R.drawable.ic_qs_caffeine_on;
@@ -495,8 +505,8 @@ public class QSTileHost implements QSTile.Host, Tunable {
void updateCustomTile(StatusBarPanelCustomTile sbc) {
synchronized (mTiles) {
- if (mTiles.containsKey(sbc.getKey())) {
- QSTile<?> tile = mTiles.get(sbc.getKey());
+ if (mTiles.containsKey(sbc.persistableKey())) {
+ QSTile<?> tile = mTiles.get(sbc.persistableKey());
if (tile instanceof CustomQSTile) {
CustomQSTile qsTile = (CustomQSTile) tile;
qsTile.update(sbc);
@@ -508,8 +518,8 @@ public class QSTileHost implements QSTile.Host, Tunable {
void addCustomTile(StatusBarPanelCustomTile sbc) {
synchronized (mTiles) {
mCustomTileData.add(new CustomTileData.Entry(sbc));
- mTileSpecs.add(sbc.getKey());
- mTiles.put(sbc.getKey(), new CustomQSTile(this, sbc));
+ mTileSpecs.add(sbc.persistableKey());
+ mTiles.put(sbc.persistableKey(), new CustomQSTile(this, sbc));
if (mCallback != null) {
mCallback.onTilesChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index b9e9292..975cb77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -45,9 +45,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
public static final long ANIMATION_DURATION = 220;
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
= new PathInterpolator(0f, 0, 0.7f, 1f);
+ public static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
private static final float SCRIM_BEHIND_ALPHA = 0.62f;
- private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
private static final int TAG_KEY_ANIM = R.id.scrim;
@@ -255,7 +255,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
}
- private void setScrimBehindColor(float alpha) {
+ public void setScrimBehindColor(float alpha) {
setScrimColor(mScrimBehind, alpha);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 339d469..f9b1f38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -76,6 +76,7 @@ import java.text.NumberFormat;
import cyanogenmod.app.StatusBarPanelCustomTile;
import cyanogenmod.providers.CMSettings;
+import cyanogenmod.weather.util.WeatherUtils;
import org.cyanogenmod.internal.logging.CMMetricsLogger;
/**
@@ -280,6 +281,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize;
+ if (mEditTileDoneText != null) {
+ mEditTileDoneText.setText(R.string.quick_settings_done);
+ }
+
updateClockScale();
updateClockCollapsedMargin();
}
@@ -515,12 +520,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
@Override
public void onWeatherChanged(WeatherController.WeatherInfo info) {
- if (info.temp == null || info.condition == null) {
+ if (Double.isNaN(info.temp) || info.condition == null) {
mWeatherLine1.setText(null);
} else {
mWeatherLine1.setText(mContext.getString(
R.string.status_bar_expanded_header_weather_format,
- info.temp,
+ WeatherUtils.formatTemperature(info.temp, info.tempUnit),
info.condition));
}
mWeatherLine2.setText(info.city);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 19f2b09..96cf093 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -83,8 +83,6 @@ public class StatusBarKeyguardViewManager {
private boolean mDeviceWillWakeUp;
private boolean mDeferScrimFadeOut;
- private View mUnlockFab;
-
public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils) {
mContext = context;
@@ -103,7 +101,7 @@ public class StatusBarKeyguardViewManager {
if (mBouncer != null) mBouncer.removeView();
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
- mStatusBarWindowManager, container);
+ mStatusBarWindowManager, container, mPhoneStatusBar);
}
/**
@@ -257,8 +255,8 @@ public class StatusBarKeyguardViewManager {
mOccluded = occluded;
mStatusBarWindowManager.setKeyguardOccluded(occluded);
mPhoneStatusBar.getVisualizer().setOccluded(occluded);
- if (mUnlockFab != null && mUnlockFab.isAttachedToWindow() && !occluded) {
- hideUnlockFab();
+ if (!occluded) {
+ mPhoneStatusBar.mKeyguardBottomArea.setVisibility(View.GONE);
}
reset(false);
}
@@ -393,20 +391,9 @@ public class StatusBarKeyguardViewManager {
}
}
- /**
- * Dismisses the keyguard by going to the next screen or making it gone.
- */
public void dismiss() {
- dismiss(false);
- }
-
- public void dismiss(boolean focusKeyguardExternalView) {
- if ((mDeviceInteractive || mDeviceWillWakeUp) && !focusKeyguardExternalView) {
+ if ((mDeviceInteractive || mDeviceWillWakeUp)) {
showBouncer();
- hideUnlockFab();
- } else if (focusKeyguardExternalView) {
- showUnlockFab();
- mStatusBarWindowManager.setKeyguardExternalViewFocus(true);
}
}
@@ -542,7 +529,7 @@ public class StatusBarKeyguardViewManager {
public boolean shouldDisableWindowAnimationsForUnlock() {
return mPhoneStatusBar.isInLaunchTransition() ||
- mPhoneStatusBar.mNotificationPanel.hasExternalKeyguardView();
+ mPhoneStatusBar.isShowingLiveLockScreenView();
}
public boolean isGoingToNotificationShade() {
@@ -566,7 +553,7 @@ public class StatusBarKeyguardViewManager {
false /* delayed */, speedUpFactor);
if (mStatusBarWindowManager.keyguardExternalViewHasFocus()) {
mStatusBarWindowManager.setKeyguardExternalViewFocus(false);
- dismiss(false);
+ dismiss();
}
}
@@ -591,50 +578,6 @@ public class StatusBarKeyguardViewManager {
}
public void setKeyguardExternalViewFocus(boolean hasFocus) {
- if (hasFocus) {
- showUnlockFab();
- } else {
- hideUnlockFab();
- }
mStatusBarWindowManager.setKeyguardExternalViewFocus(hasFocus);
}
-
- private void showUnlockFab() {
- if (mUnlockFab == null) {
- mUnlockFab = View.inflate(mContext, R.layout.unlock_fab, null);
- }
- if (!mUnlockFab.isAttachedToWindow()) {
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT);
- lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
- lp.setTitle("UnlockFab");
- lp.packageName = mContext.getPackageName();
- lp.width = lp.height =
- mContext.getResources().getDimensionPixelSize(R.dimen.unlock_fab_size);
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.addView(mUnlockFab, lp);
- mUnlockFab.setOnClickListener(mUnlockFabClickListener);
- }
- }
-
- private void hideUnlockFab() {
- if (mUnlockFab != null && mUnlockFab.isAttachedToWindow()) {
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.removeViewImmediate(mUnlockFab);
- }
- }
-
- private View.OnClickListener mUnlockFabClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mStatusBarWindowManager.setKeyguardExternalViewFocus(false);
- dismiss(false);
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 9a991f4..f0d7828 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -18,11 +18,14 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.PixelFormat;
+import android.os.Handler;
import android.os.SystemProperties;
-import android.util.Log;
+import android.provider.Settings;
import android.view.Gravity;
import android.view.Display;
import android.view.SurfaceSession;
@@ -35,8 +38,8 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LiveLockScreenController;
import cyanogenmod.providers.CMSettings;
-import org.cyanogenmod.internal.util.CmLockPatternUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,8 +56,9 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
private WindowManager.LayoutParams mLp;
private WindowManager.LayoutParams mLpChanged;
private int mBarHeight;
- private final boolean mKeyguardScreenRotation;
+ private boolean mKeyguardScreenRotation;
private final float mScreenBrightnessDoze;
+ private final boolean mBlurSupported;
private boolean mKeyguardBlurEnabled;
private boolean mShowingMedia;
@@ -62,6 +66,7 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
private final SurfaceSession mFxSession;
private final KeyguardMonitor mKeyguardMonitor;
+ private int mCurrentOrientation;
private static final int TYPE_LAYER_MULTIPLIER = 10000; // refer to WindowManagerService.TYPE_LAYER_MULTIPLIER
private static final int TYPE_LAYER_OFFSET = 1000; // refer to WindowManagerService.TYPE_LAYER_OFFSET
@@ -69,6 +74,7 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
private static final int STATUS_BAR_LAYER = 16 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
private final State mCurrentState = new State();
+ private LiveLockScreenController mLiveLockScreenController;
public StatusBarWindowManager(Context context, KeyguardMonitor kgm) {
mContext = context;
@@ -76,18 +82,23 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
mScreenBrightnessDoze = mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
+ mBlurSupported = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_ui_blur_enabled);
mKeyguardMonitor = kgm;
mKeyguardMonitor.addCallback(this);
- mKeyguardBlurEnabled = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_ui_blur_enabled);
mFxSession = new SurfaceSession();
}
private boolean shouldEnableKeyguardScreenRotation() {
Resources res = mContext.getResources();
+ boolean enableAccelerometerRotation = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 1) != 0;
+ boolean enableLockScreenRotation = CMSettings.System.getInt(mContext.getContentResolver(),
+ CMSettings.System.LOCKSCREEN_ROTATION, 0) != 0;
return SystemProperties.getBoolean("lockscreen.rot_override", false)
- || res.getBoolean(R.bool.config_enableLockScreenRotation);
+ || (res.getBoolean(R.bool.config_enableLockScreenRotation)
+ && (enableLockScreenRotation && enableAccelerometerRotation));
}
/**
@@ -121,27 +132,34 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
- if (mKeyguardBlurEnabled) {
+ mKeyguardBlurEnabled = mBlurSupported ?
+ CMSettings.Secure.getInt(mContext.getContentResolver(),
+ CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED, 1) == 1 : false;
+ if (mBlurSupported) {
Display display = mWindowManager.getDefaultDisplay();
Point xy = new Point();
display.getRealSize(xy);
+ mCurrentOrientation = mContext.getResources().getConfiguration().orientation;
mKeyguardBlur = new BlurLayer(mFxSession, xy.x, xy.y, "KeyGuard");
if (mKeyguardBlur != null) {
mKeyguardBlur.setLayer(STATUS_BAR_LAYER - 2);
}
}
+
+ SettingsObserver observer = new SettingsObserver(new Handler());
+ observer.observe(mContext);
}
private void applyKeyguardFlags(State state) {
if (state.keyguardShowing) {
mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
- if (!mKeyguardBlurEnabled) {
+ if (!mKeyguardBlurEnabled || mShowingMedia) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
}
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
- if (mKeyguardBlurEnabled) {
+ if (mKeyguardBlurEnabled && mKeyguardBlur != null) {
mKeyguardBlur.hide();
}
}
@@ -260,8 +278,7 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
boolean isblur = false;
if (mCurrentState.keyguardShowing && mKeyguardBlurEnabled
&& !mCurrentState.keyguardOccluded
- && !mShowingMedia
- && !isShowingLiveLockScreen()) {
+ && !mShowingMedia) {
isblur = true;
}
if (mKeyguardBlur != null) {
@@ -341,11 +358,21 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
}
public void setKeyguardExternalViewFocus(boolean hasFocus) {
- mCurrentState.keyguardExternalViewHasFocus = hasFocus;
+ mLiveLockScreenController.onLiveLockScreenFocusChanged(hasFocus);
// make the keyguard occluded so the external view gets full focus
setKeyguardOccluded(hasFocus);
}
+ public void onConfigurationChanged(Configuration newConfig) {
+ if (mKeyguardBlur != null && newConfig.orientation != mCurrentOrientation) {
+ Display display = mWindowManager.getDefaultDisplay();
+ Point xy = new Point();
+ display.getRealSize(xy);
+ mKeyguardBlur.setSize(xy.x, xy.y);
+ mCurrentOrientation = newConfig.orientation;
+ }
+ }
+
/**
* @param state The {@link StatusBarState} of the status bar.
*/
@@ -394,14 +421,11 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
}
public boolean keyguardExternalViewHasFocus() {
- return mCurrentState.keyguardExternalViewHasFocus;
+ return mLiveLockScreenController.getLiveLockScreenHasFocus();
}
- private boolean isShowingLiveLockScreen() {
- CmLockPatternUtils lockPatternUtils = new CmLockPatternUtils(mContext);
- return (CMSettings.Secure.getInt(mContext.getContentResolver(),
- CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED, 0) == 1)
- && lockPatternUtils.isThirdPartyKeyguardEnabled();
+ public void setLiveLockscreenController(LiveLockScreenController liveLockScreenController) {
+ mLiveLockScreenController = liveLockScreenController;
}
private static class State {
@@ -418,7 +442,6 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
boolean forceStatusBarVisible;
boolean forceCollapsed;
boolean forceDozeBrightness;
- boolean keyguardExternalViewHasFocus;
/**
* The {@link BaseStatusBar} state from the status bar.
@@ -455,4 +478,39 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback {
return result.toString();
}
}
+
+ private class SettingsObserver extends ContentObserver {
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void observe(Context context) {
+ context.getContentResolver().registerContentObserver(
+ CMSettings.Secure.getUriFor(CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED),
+ false,
+ this);
+ context.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
+ false,
+ this);
+ context.getContentResolver().registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.LOCKSCREEN_ROTATION),
+ false,
+ this);
+ }
+
+ public void unobserve(Context context) {
+ context.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mKeyguardBlurEnabled = mBlurSupported ?
+ CMSettings.Secure.getInt(mContext.getContentResolver(),
+ CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED, 1) == 1 : false;
+ mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
+ // update the state
+ apply(mCurrentState);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java
new file mode 100644
index 0000000..48457c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java
@@ -0,0 +1,76 @@
+package com.android.systemui.statusbar.phone;
+
+import android.view.View;
+
+/*
+ Allows mirroring of view states such as alpha, translation...etc
+ */
+public class ViewLinker<T extends View & ViewLinker.ViewLinkerParent> {
+
+ public static final int LINK_ALPHA = 0x1;
+ public static final int LINK_TRANSLATION = 0x2;
+
+ private final LinkInfo[] mLinkedViews;
+ private final T mParent;
+
+ public interface ViewLinkerCallback {
+ void onAlphaChanged(float alpha);
+ void onTranslationXChanged(float translationX);
+ }
+
+ public interface ViewLinkerParent {
+ void registerLinker(ViewLinkerCallback callback);
+ }
+
+ public static class LinkInfo {
+ private View mView;
+ private int mFlags;
+ public LinkInfo(View v, int linkFlags) {
+ mView = v;
+ mFlags = linkFlags;
+ }
+ private boolean supportsFlag(int flag) {
+ return (mFlags & flag) != 0;
+ }
+ }
+
+ private ViewLinkerCallback mCallback = new ViewLinkerCallback() {
+ @Override
+ public void onAlphaChanged(float alpha) {
+ for (LinkInfo v : mLinkedViews) {
+ if (v.supportsFlag(LINK_ALPHA)) {
+ v.mView.setAlpha(alpha);
+ }
+ }
+ }
+
+ @Override
+ public void onTranslationXChanged(float translationX) {
+ for (LinkInfo v : mLinkedViews) {
+ if (v.supportsFlag(LINK_TRANSLATION)) {
+ v.mView.setTranslationX(translationX);
+ }
+ }
+ }
+ };
+
+ public ViewLinker(T parent, LinkInfo... viewsToLink) {
+ mLinkedViews = viewsToLink;
+ mParent = parent;
+ ensureParentNotInLink();
+ parent.registerLinker(mCallback);
+ }
+
+ private void ensureParentNotInLink() {
+ for (LinkInfo v : mLinkedViews) {
+ if (v.mView == mParent) {
+ throw new IllegalStateException("Parent cannot be" +
+ "one of the linked views");
+ }
+ }
+ }
+
+ public View getParent() {
+ return mParent;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java
new file mode 100644
index 0000000..2f290cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java
@@ -0,0 +1,349 @@
+package com.android.systemui.statusbar.policy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.EventLog;
+
+import android.view.View;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.EventLogTags;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+import cyanogenmod.app.CMContextConstants;
+import cyanogenmod.app.ILiveLockScreenChangeListener;
+import cyanogenmod.app.ILiveLockScreenManager;
+import cyanogenmod.app.LiveLockScreenInfo;
+import cyanogenmod.externalviews.KeyguardExternalView;
+
+import java.util.Objects;
+
+public class LiveLockScreenController {
+ private static final String TAG = LiveLockScreenController.class.getSimpleName();
+
+ private ILiveLockScreenManager mLLSM;
+ private Context mContext;
+ private PhoneStatusBar mBar;
+ private NotificationPanelView mPanelView;
+ private ComponentName mLiveLockScreenComponentName;
+ private KeyguardExternalView mLiveLockScreenView;
+ private Handler mHandler;
+
+ private int mStatusBarState;
+
+ private PowerManager mPowerManager;
+
+ private boolean mLlsHasFocus = false;
+
+ private boolean mScreenOnAndInteractive;
+
+ private String mLlsName;
+ private KeyguardViewMediator mKeyguardViewMediator;
+
+ public LiveLockScreenController(Context context, PhoneStatusBar bar,
+ NotificationPanelView panelView) {
+ mContext = context;
+ mHandler = new Handler(Looper.getMainLooper());
+
+ mLLSM = ILiveLockScreenManager.Stub.asInterface(ServiceManager.getService(
+ CMContextConstants.CM_LIVE_LOCK_SCREEN_SERVICE));
+ mBar = bar;
+ mPanelView = panelView;
+ mPowerManager = context.getSystemService(PowerManager.class);
+ mKeyguardViewMediator = ((SystemUIApplication)
+ mContext.getApplicationContext()).getComponent(KeyguardViewMediator.class);
+ registerListener();
+ try {
+ LiveLockScreenInfo llsInfo = mLLSM.getCurrentLiveLockScreen();
+ if (llsInfo != null && llsInfo.component != null) {
+ updateLiveLockScreenView(llsInfo.component);
+ }
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+
+ public void cleanup() {
+ unregisterListener();
+ mPanelView = null;
+ if (mLiveLockScreenView != null) {
+ mLiveLockScreenView.setProviderComponent(null);
+ }
+ mLiveLockScreenView = null;
+ mLiveLockScreenComponentName = null;
+ }
+
+ public void setBarState(int statusBarState) {
+ if (mStatusBarState != StatusBarState.SHADE && statusBarState == StatusBarState.SHADE) {
+ // going from KEYGUARD or SHADE_LOCKED to SHADE so device has been unlocked
+ onKeyguardDismissed();
+ }
+
+ if (statusBarState == StatusBarState.KEYGUARD) {
+ mBar.getScrimController().forceHideScrims(false);
+ }
+
+ mStatusBarState = statusBarState;
+ if (statusBarState == StatusBarState.KEYGUARD ||
+ statusBarState == StatusBarState.SHADE_LOCKED) {
+ if (mLiveLockScreenComponentName != null) {
+ if (mLiveLockScreenView == null) {
+ mLiveLockScreenView =
+ getExternalKeyguardView(mLiveLockScreenComponentName);
+ if (mLiveLockScreenView != null) {
+ mLiveLockScreenView.registerKeyguardExternalViewCallback(
+ mExternalKeyguardViewCallbacks);
+ }
+ }
+ if (mLiveLockScreenView != null && !mLiveLockScreenView.isAttachedToWindow()) {
+ mBar.updateRowStates();
+ mPanelView.addView(mLiveLockScreenView, 0);
+ }
+ }
+ } else {
+ if (isShowingLiveLockScreenView() && !mBar.isKeyguardInputRestricted()) {
+ mPanelView.removeView(mLiveLockScreenView);
+ }
+ mLlsHasFocus = false;
+ }
+ }
+
+ private ILiveLockScreenChangeListener mChangeListener =
+ new ILiveLockScreenChangeListener.Stub() {
+ @Override
+ public void onLiveLockScreenChanged(LiveLockScreenInfo llsInfo) throws RemoteException {
+ if (mPanelView != null) {
+ updateLiveLockScreenView(llsInfo != null ? llsInfo.component : null);
+ }
+ }
+ };
+
+ private void registerListener() {
+ try {
+ mLLSM.registerChangeListener(mChangeListener);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+
+ private void unregisterListener() {
+ try {
+ mLLSM.unregisterChangeListener(mChangeListener);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+
+ private KeyguardExternalView getExternalKeyguardView(ComponentName componentName) {
+ try {
+ return new KeyguardExternalView(mContext, null, componentName);
+ } catch (Exception e) {
+ // just return null below and move on
+ }
+ return null;
+ }
+
+ private KeyguardExternalView.KeyguardExternalViewCallbacks mExternalKeyguardViewCallbacks =
+ new KeyguardExternalView.KeyguardExternalViewCallbacks() {
+ @Override
+ public boolean requestDismiss() {
+ if (isShowingLiveLockScreenView()) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mBar.showKeyguard();
+ mBar.showBouncer();
+ }
+ });
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean requestDismissAndStartActivity(final Intent intent) {
+ if (isShowingLiveLockScreenView()) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mBar.startActivityDismissingKeyguard(intent, false, true, true,
+ null);
+ }
+ });
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void providerDied() {
+ mLiveLockScreenView.unregisterKeyguardExternalViewCallback(
+ mExternalKeyguardViewCallbacks);
+ mLiveLockScreenView = null;
+ // make sure we're showing the notification panel if the LLS crashed while it had focus
+ if (mLlsHasFocus) {
+ mLlsHasFocus = false;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mBar.showKeyguard();
+ }
+ });
+ }
+ }
+
+ @Override
+ public void slideLockscreenIn() {
+ if (mLlsHasFocus) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mBar.showKeyguard();
+ }
+ });
+ }
+ }
+ };
+
+ public boolean isShowingLiveLockScreenView() {
+ return mLiveLockScreenView != null && mLiveLockScreenView.isAttachedToWindow();
+ }
+
+ public boolean isLiveLockScreenInteractive() {
+ return mLiveLockScreenView != null && mLiveLockScreenView.isInteractive();
+ }
+
+ public KeyguardExternalView getLiveLockScreenView() {
+ return mLiveLockScreenView;
+ }
+
+ public void onScreenTurnedOn() {
+ mScreenOnAndInteractive = mPowerManager.isInteractive();
+ if (mScreenOnAndInteractive) {
+ if (mLiveLockScreenView != null) mLiveLockScreenView.onScreenTurnedOn();
+ EventLog.writeEvent(EventLogTags.SYSUI_LLS_KEYGUARD_SHOWING, 1);
+ }
+ }
+
+ public void onScreenTurnedOff() {
+ if (mScreenOnAndInteractive) {
+ if (mLiveLockScreenView != null) mLiveLockScreenView.onScreenTurnedOff();
+ if (mStatusBarState != StatusBarState.SHADE) {
+ EventLog.writeEvent(EventLogTags.SYSUI_LLS_KEYGUARD_SHOWING, 0);
+ }
+ mScreenOnAndInteractive = false;
+ }
+ }
+
+ public void onLiveLockScreenFocusChanged(boolean hasFocus) {
+ mKeyguardViewMediator.notifyKeyguardPanelFocusChanged(hasFocus);
+ if (mLiveLockScreenView != null) {
+ // make sure the LLS knows where the notification panel is
+ mLiveLockScreenView.onLockscreenSlideOffsetChanged(hasFocus ? 0f : 1f);
+ }
+ // don't log focus changes when screen is not interactive
+ if (hasFocus != mLlsHasFocus && mPowerManager.isInteractive()) {
+ EventLog.writeEvent(EventLogTags.SYSUI_LLS_NOTIFICATION_PANEL_SHOWN,
+ hasFocus ? 0 : 1);
+ }
+ // Hide statusbar and scrim if live lockscreen
+ // currently has focus
+ mBar.setStatusBarViewVisibility(!hasFocus);
+ mBar.getScrimController().forceHideScrims(hasFocus);
+ mLlsHasFocus = hasFocus;
+ }
+
+ public void onKeyguardDismissed() {
+ if (mLiveLockScreenView != null) mLiveLockScreenView.onKeyguardDismissed();
+ EventLog.writeEvent(EventLogTags.SYSUI_LLS_KEYGUARD_DISMISSED, mLlsHasFocus ? 1 : 0);
+ // Ensure we reset visibility when keyguard is dismissed
+ mBar.setStatusBarViewVisibility(true);
+ mBar.getScrimController().forceHideScrims(false);
+ }
+
+ public boolean getLiveLockScreenHasFocus() {
+ return mLlsHasFocus;
+ }
+
+ public String getLiveLockScreenName() {
+ return mLlsName;
+ }
+
+ private String getLlsNameFromComponentName(ComponentName cn) {
+ if (cn == null) return null;
+
+ PackageManager pm = mContext.getPackageManager();
+ Intent intent = new Intent();
+ intent.setComponent(cn);
+ ResolveInfo ri = pm.resolveService(intent, 0);
+ return ri != null ? ri.serviceInfo.loadLabel(pm).toString() : null;
+ }
+
+ private Runnable mAddNewLiveLockScreenRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mLiveLockScreenComponentName != null) {
+ mLiveLockScreenView =
+ getExternalKeyguardView(mLiveLockScreenComponentName);
+ mLiveLockScreenView.registerKeyguardExternalViewCallback(
+ mExternalKeyguardViewCallbacks);
+ if (mStatusBarState != StatusBarState.SHADE) {
+ mPanelView.addView(mLiveLockScreenView);
+ mLiveLockScreenView.onKeyguardShowing(true);
+ }
+ } else {
+ mLiveLockScreenView = null;
+ }
+ }
+ };
+
+ private void updateLiveLockScreenView(final ComponentName cn) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // If mThirdPartyKeyguardViewComponent differs from cn, go ahead and update
+ if (!Objects.equals(mLiveLockScreenComponentName, cn)) {
+ mLiveLockScreenComponentName = cn;
+ mLlsName = getLlsNameFromComponentName(cn);
+ if (mLiveLockScreenView != null) {
+ mLiveLockScreenView.unregisterKeyguardExternalViewCallback(
+ mExternalKeyguardViewCallbacks);
+ // setProviderComponent(null) will unbind the existing service
+ mLiveLockScreenView.setProviderComponent(null);
+ if (mPanelView.indexOfChild(mLiveLockScreenView) >= 0) {
+ mLiveLockScreenView.registerOnWindowAttachmentChangedListener(
+ new KeyguardExternalView.OnWindowAttachmentChangedListener() {
+ @Override
+ public void onAttachedToWindow() {
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ mLiveLockScreenView
+ .unregisterOnWindowAttachmentChangedListener(
+ this);
+ mHandler.post(mAddNewLiveLockScreenRunnable);
+ }
+ }
+ );
+ mPanelView.removeView(mLiveLockScreenView);
+ } else {
+ mAddNewLiveLockScreenRunnable.run();
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index a8e977f..f7d6f85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -279,13 +279,15 @@ public class MobileSignalController extends SignalController<
}
private boolean isRoaming() {
- if (isCdma()) {
+ if (mServiceState == null) {
+ return false;
+ } else if (isCdma()) {
final int iconMode = mServiceState.getCdmaEriIconMode();
return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
&& (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
|| iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
} else {
- return mServiceState != null && mServiceState.getRoaming();
+ return mServiceState.getRoaming();
}
}
@@ -395,7 +397,8 @@ public class MobileSignalController extends SignalController<
mCurrentState.iconGroup = mDefaultIcons;
}
mCurrentState.dataConnected = mCurrentState.connected
- && mDataState == TelephonyManager.DATA_CONNECTED;
+ && mDataState == TelephonyManager.DATA_CONNECTED
+ && mCurrentState.dataSim;
mCurrentState.showSeparateRoaming = false;
if (isCarrierNetworkChangeActive()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
index 1fa4956..0f71bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
@@ -25,8 +25,9 @@ public interface WeatherController {
void onWeatherChanged(WeatherInfo temp);
}
public static class WeatherInfo {
- public String temp = null;
+ public double temp = Double.NaN;
public String city = null;
public String condition = null;
+ public int tempUnit;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
index 288bc7e..1a798f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
@@ -16,43 +16,49 @@
package com.android.systemui.statusbar.policy;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
-import android.provider.Settings;
import android.util.Log;
+import cyanogenmod.providers.CMSettings;
+import cyanogenmod.providers.WeatherContract;
+import cyanogenmod.weather.CMWeatherManager;
+import cyanogenmod.weather.util.WeatherUtils;
import java.util.ArrayList;
+import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_CITY;
+import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_CONDITION;
+import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_TEMPERATURE;
+import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_TEMPERATURE_UNIT;
+import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.CELSIUS;
+import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT;
+
public class WeatherControllerImpl implements WeatherController {
private static final String TAG = WeatherController.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private WeatherContentObserver mWeatherContentObserver;
+ private Handler mHandler;
+ private int mWeatherUnit;
+ private Uri mWeatherTempetarureUri;
public static final ComponentName COMPONENT_WEATHER_FORECAST = new ComponentName(
"com.cyanogenmod.lockclock", "com.cyanogenmod.lockclock.weather.ForecastActivity");
- public static final String ACTION_UPDATE_FINISHED
- = "com.cyanogenmod.lockclock.action.WEATHER_UPDATE_FINISHED";
- public static final String EXTRA_UPDATE_CANCELLED = "update_cancelled";
public static final String ACTION_FORCE_WEATHER_UPDATE
= "com.cyanogenmod.lockclock.action.FORCE_WEATHER_UPDATE";
- public static final Uri CURRENT_WEATHER_URI
- = Uri.parse("content://com.cyanogenmod.lockclock.weather.provider/weather/current");
- public static final String[] WEATHER_PROJECTION = new String[]{
- "temperature",
- "city",
- "condition"
+ private static final String[] WEATHER_PROJECTION = new String[]{
+ CURRENT_TEMPERATURE,
+ CURRENT_TEMPERATURE_UNIT,
+ CURRENT_CITY,
+ CURRENT_CONDITION
};
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
- private final Receiver mReceiver = new Receiver();
private final Context mContext;
private WeatherInfo mCachedInfo = new WeatherInfo();
@@ -60,10 +66,16 @@ public class WeatherControllerImpl implements WeatherController {
public WeatherControllerImpl(Context context) {
mContext = context;
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mHandler = new Handler();
+ mWeatherContentObserver = new WeatherContentObserver(mHandler);
+ mWeatherTempetarureUri
+ = CMSettings.Global.getUriFor(CMSettings.Global.WEATHER_TEMPERATURE_UNIT);
+ mContext.getContentResolver().registerContentObserver(
+ WeatherContract.WeatherColumns.CURRENT_WEATHER_URI,true, mWeatherContentObserver);
+ mContext.getContentResolver().registerContentObserver(mWeatherTempetarureUri, true,
+ mWeatherContentObserver);
+ queryWeatherTempUnit();
queryWeather();
- final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_UPDATE_FINISHED);
- mContext.registerReceiver(mReceiver, filter);
}
public void addCallback(Callback callback) {
@@ -85,17 +97,29 @@ public class WeatherControllerImpl implements WeatherController {
}
private void queryWeather() {
- Cursor c = mContext.getContentResolver().query(CURRENT_WEATHER_URI, WEATHER_PROJECTION,
+ Cursor c = mContext.getContentResolver().query(
+ WeatherContract.WeatherColumns.CURRENT_WEATHER_URI, WEATHER_PROJECTION,
null, null, null);
if (c == null) {
if(DEBUG) Log.e(TAG, "cursor was null for temperature, forcing weather update");
+ //LockClock keeps track of the user settings (temp unit, search by geo location/city)
+ //so we delegate the responsibility of handling a weather update to LockClock
mContext.sendBroadcast(new Intent(ACTION_FORCE_WEATHER_UPDATE));
} else {
try {
c.moveToFirst();
- mCachedInfo.temp = c.getString(0);
- mCachedInfo.city = c.getString(1);
- mCachedInfo.condition = c.getString(2);
+ double temp = c.getDouble(0);
+ int reportedUnit = c.getInt(1);
+ if (reportedUnit == CELSIUS && mWeatherUnit == FAHRENHEIT) {
+ temp = WeatherUtils.celsiusToFahrenheit(temp);
+ } else if (reportedUnit == FAHRENHEIT && mWeatherUnit == CELSIUS) {
+ temp = WeatherUtils.fahrenheitToCelsius(temp);
+ }
+
+ mCachedInfo.temp = temp;
+ mCachedInfo.tempUnit = mWeatherUnit;
+ mCachedInfo.city = c.getString(2);
+ mCachedInfo.condition = c.getString(3);
} finally {
c.close();
}
@@ -108,19 +132,53 @@ public class WeatherControllerImpl implements WeatherController {
}
}
- private final class Receiver extends BroadcastReceiver {
+ private class WeatherContentObserver extends ContentObserver {
+
+ public WeatherContentObserver(Handler handler) {
+ super(handler);
+ }
+
@Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
- if (intent.hasExtra(EXTRA_UPDATE_CANCELLED)) {
- if (intent.getBooleanExtra(EXTRA_UPDATE_CANCELLED, false)) {
- // no update
- return;
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri != null) {
+ if (uri.compareTo(WeatherContract.WeatherColumns.CURRENT_WEATHER_URI) == 0) {
+ queryWeather();
+ fireCallback();
+ } else if (uri.compareTo(mWeatherTempetarureUri) == 0) {
+ queryWeatherTempUnit();
+ fixCachedWeatherInfo();
+ fireCallback();
+ } else {
+ super.onChange(selfChange, uri);
}
}
- queryWeather();
- fireCallback();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ onChange(selfChange, null);
}
}
+ private void queryWeatherTempUnit() {
+ try {
+ mWeatherUnit = CMSettings.Global.getInt(mContext.getContentResolver(),
+ CMSettings.Global.WEATHER_TEMPERATURE_UNIT);
+ } catch (CMSettings.CMSettingNotFoundException e) {
+ //CMSettingsProvider should have taken care of setting a default value for this setting
+ //so how is that we ended up here?? We need to set a valid temp unit anyway to keep
+ //this going
+ mWeatherUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS;
+ }
+ }
+
+ private void fixCachedWeatherInfo() {
+ if (mCachedInfo.tempUnit == CELSIUS && mWeatherUnit == FAHRENHEIT) {
+ mCachedInfo.temp = WeatherUtils.celsiusToFahrenheit(mCachedInfo.temp);
+ mCachedInfo.tempUnit = FAHRENHEIT;
+ } else if (mCachedInfo.tempUnit == FAHRENHEIT && mWeatherUnit == CELSIUS) {
+ mCachedInfo.temp = WeatherUtils.fahrenheitToCelsius(mCachedInfo.temp);
+ mCachedInfo.tempUnit = CELSIUS;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 2f04b42..b6e131a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -50,6 +50,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ViewLinker;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -63,7 +64,8 @@ import java.util.HashSet;
*/
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
- ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
+ ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
+ ViewLinker.ViewLinkerParent {
private static final String TAG = "NotificationStackScrollLayout";
private static final boolean DEBUG = false;
@@ -234,6 +236,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private boolean mForceNoOverlappingRendering;
private NotificationOverflowContainer mOverflowContainer;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
+ private ViewLinker.ViewLinkerCallback mLinkerCallback;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -2879,6 +2882,23 @@ public class NotificationStackScrollLayout extends ViewGroup
return !mForceNoOverlappingRendering && super.hasOverlappingRendering();
}
+ @Override
+ public void registerLinker(ViewLinker.ViewLinkerCallback callback) {
+ mLinkerCallback = callback;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+ mLinkerCallback.onAlphaChanged(alpha);
+ }
+
+ @Override
+ public void setTranslationX(float translationX) {
+ super.setTranslationX(translationX);
+ mLinkerCallback.onTranslationXChanged(translationX);
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 9d63d08..53fbef7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -163,7 +163,7 @@ public class QsTuner extends Fragment implements Callback {
public CustomHost(Context context) {
super(context, null, null, null, null, null, null, null, null, null,
- null, null, new BlankSecurityController());
+ null, null, new BlankSecurityController(), null);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index b2c90be..3e7477c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -132,6 +132,12 @@ public class TunerService extends SystemUI {
public void reloadSetting(Uri uri) {
String key = mListeningUris.get(uri);
+
+ // Handle possible null keys
+ if (TextUtils.isEmpty(key)) {
+ return;
+ }
+
String value;
if (uri.getAuthority().equals(CMSettings.AUTHORITY)) {
value = CMSettings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 7d34cdc..baa5321 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -327,7 +327,7 @@ public class StorageNotification extends SystemUI {
// Don't annoy when user dismissed in past. (But make sure the disk is adoptable; we
// used to allow snoozing non-adoptable disks too.)
- if (rec.isSnoozed() && disk.isAdoptable()) {
+ if (rec == null || (rec.isSnoozed() && disk.isAdoptable())) {
return null;
}
@@ -364,6 +364,11 @@ public class StorageNotification extends SystemUI {
.setContentIntent(browseIntent)
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW);
+ // USB disks notification can be persistent
+ if (disk.isUsb()) {
+ builder.setOngoing(mContext.getResources().getBoolean(
+ R.bool.config_persistUsbDriveNotification));
+ }
// Non-adoptable disks can't be snoozed.
if (disk.isAdoptable()) {
builder.setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()));
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 27c6601..9fda531 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -106,7 +106,6 @@ public class VolumeDialog {
private final SpTexts mSpTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
private final KeyguardManager mKeyguard;
- private final AudioManager mAudioManager;
private final int mExpandButtonAnimationDuration;
private final ZenFooter mZenFooter;
private final LayoutTransition mLayoutTransition;
@@ -139,7 +138,6 @@ public class VolumeDialog {
mCallback = callback;
mSpTexts = new SpTexts(mContext);
mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mDialog = new CustomDialog(mContext);
@@ -666,8 +664,7 @@ public class VolumeDialog {
private void updateFooterH() {
if (D.BUG) Log.d(TAG, "updateFooterH");
final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
- final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
- && mAudioManager.isStreamAffectedByRingerMode(mActiveStream);
+ final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF;
if (wasVisible != visible && !visible) {
prepareForCollapse();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 9494e27..9269c1c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -371,6 +371,7 @@ public class VolumeDialogController {
updateZenModeW();
updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
updateZenModeConfigW();
+ updateLinkNotificationConfigW();
mCallbacks.onStateChanged(mState);
}