Loading core/java/android/service/dreams/DreamService.java +64 −40 Original line number Diff line number Diff line Loading @@ -161,6 +161,7 @@ public class DreamService extends Service implements Window.Callback { private boolean mFinished; private boolean mCanDoze; private boolean mDozing; private boolean mWindowless; private DozeHardware mDozeHardware; private boolean mDebug = false; Loading Loading @@ -519,6 +520,24 @@ public class DreamService extends Service implements Window.Callback { return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright); } /** * Marks this dream as windowless. Only available to doze dreams. * * @hide */ public void setWindowless(boolean windowless) { mWindowless = windowless; } /** * Returns whether or not this dream is windowless. Only available to doze dreams. * * @hide */ public boolean isWindowless() { return mWindowless; } /** * Returns true if this dream is allowed to doze. * <p> Loading Loading @@ -715,6 +734,7 @@ public class DreamService extends Service implements Window.Callback { WindowManagerGlobal.getInstance().closeAll(mWindowToken, this.getClass().getName(), "Dream"); mWindowToken = null; mCanDoze = false; } } Loading Loading @@ -744,7 +764,10 @@ public class DreamService extends Service implements Window.Callback { mWindowToken = windowToken; mCanDoze = canDoze; if (mWindowless && !mCanDoze) { throw new IllegalStateException("Only doze dreams can be windowless"); } if (!mWindowless) { mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.requestFeature(Window.FEATURE_NO_TITLE); Loading Loading @@ -784,7 +807,7 @@ public class DreamService extends Service implements Window.Callback { mWindow = null; return; } } // We need to defer calling onDreamingStarted until after onWindowAttached, // which is posted to the handler by addView, so we post onDreamingStarted // to the handler also. Need to watch out here in case detach occurs before Loading @@ -792,7 +815,7 @@ public class DreamService extends Service implements Window.Callback { mHandler.post(new Runnable() { @Override public void run() { if (mWindow != null) { if (mWindow != null || mWindowless) { if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()"); mStarted = true; onDreamingStarted(); Loading Loading @@ -878,6 +901,7 @@ public class DreamService extends Service implements Window.Callback { if (isLowProfile()) pw.print(" lowprofile"); if (isFullscreen()) pw.print(" fullscreen"); if (isScreenBright()) pw.print(" bright"); if (isWindowless()) pw.print(" windowless"); if (isDozing()) pw.print(" dozing"); pw.println(); } Loading core/res/res/values/config.xml +2 −3 Original line number Diff line number Diff line Loading @@ -1184,7 +1184,7 @@ <bool name="config_dreamsActivatedOnDockByDefault">true</bool> <!-- If supported and enabled, are dreams activated when asleep and charging? (by default) --> <bool name="config_dreamsActivatedOnSleepByDefault">false</bool> <!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) --> <!-- ComponentName of the default dream (Settings.Secure.DEFAULT_SCREENSAVER_COMPONENT) --> <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string> <!-- Are we allowed to dream while not plugged in? --> Loading @@ -1205,8 +1205,7 @@ try to start this dream if possible. The dream should typically call startDozing() to put the display into a low power state and allow the application processor to be suspended. When the dream ends, the system will go to sleep as usual. Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an empty string if none. Specify the component name or an empty string if none. Note that doze dreams are not subject to the same start conditions as ordinary dreams. Doze dreams will run whenever the power manager is in a dozing state. --> Loading packages/SystemUI/AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -300,5 +300,11 @@ <category android:name="android.intent.category.DESK_DOCK" /> </intent-filter> </activity> <!-- I dream of notifications --> <service android:name=".doze.DozeService" android:exported="true" /> </application> </manifest> packages/SystemUI/src/com/android/systemui/doze/DozeService.java 0 → 100644 +238 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.systemui.doze; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; import android.os.PowerManager; import android.os.Vibrator; import android.service.dreams.DozeHardware; import android.service.dreams.DreamService; import android.util.Log; import com.android.systemui.SystemUIApplication; public class DozeService extends DreamService { private static final boolean DEBUG = false; private static final String TEASE_ACTION = "com.android.systemui.doze.tease"; private final String mTag = String.format("DozeService.%08x", hashCode()); private final Context mContext = this; private Host mHost; private DozeHardware mDozeHardware; private SensorManager mSensors; private Sensor mSigMotionSensor; private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; private boolean mDreaming; private boolean mTeaseReceiverRegistered; public DozeService() { if (DEBUG) Log.d(mTag, "new DozeService()"); setDebug(DEBUG); } @Override public void onCreate() { if (DEBUG) Log.d(mTag, "onCreate"); super.onCreate(); if (getApplication() instanceof SystemUIApplication) { final SystemUIApplication app = (SystemUIApplication) getApplication(); mHost = app.getComponent(Host.class); } setWindowless(true); mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); } @Override public void onAttachedToWindow() { if (DEBUG) Log.d(mTag, "onAttachedToWindow"); super.onAttachedToWindow(); } @Override public void onDreamingStarted() { super.onDreamingStarted(); mDozeHardware = getDozeHardware(); if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " dozeHardware=" + mDozeHardware); mDreaming = true; listenForTeaseSignals(true); requestDoze(); } public void stayAwake(long millis) { if (mDreaming && millis > 0) { mWakeLock.acquire(millis); } } public void startDozing() { if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming); if (!mDreaming) { Log.w(mTag, "Not dozing, no longer dreaming"); return; } super.startDozing(); } @Override public void onDreamingStopped() { if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing()); super.onDreamingStopped(); mDreaming = false; mDozeHardware = null; if (mWakeLock.isHeld()) { mWakeLock.release(); } listenForTeaseSignals(false); stopDozing(); dozingStopped(); } @Override public void onDetachedFromWindow() { if (DEBUG) Log.d(mTag, "onDetachedFromWindow"); super.onDetachedFromWindow(); dozingStopped(); } @Override public void onDestroy() { if (DEBUG) Log.d(mTag, "onDestroy"); super.onDestroy(); dozingStopped(); } private void requestDoze() { if (mHost != null) { mHost.requestDoze(this); } } private void requestTease() { if (mHost != null) { mHost.requestTease(this); } } private void dozingStopped() { if (mHost != null) { mHost.dozingStopped(this); } } private void listenForTeaseSignals(boolean listen) { if (DEBUG) Log.d(mTag, "listenForTeaseSignals: " + listen); if (mHost == null) return; listenForSignificantMotion(listen); if (listen) { mContext.registerReceiver(mTeaseReceiver, new IntentFilter(TEASE_ACTION)); mTeaseReceiverRegistered = true; mHost.addCallback(mHostCallback); } else { if (mTeaseReceiverRegistered) { mContext.unregisterReceiver(mTeaseReceiver); } mTeaseReceiverRegistered = false; mHost.removeCallback(mHostCallback); } } private void listenForSignificantMotion(boolean listen) { if (mSigMotionSensor == null) return; if (listen) { mSensors.requestTriggerSensor(mSigMotionListener, mSigMotionSensor); } else { mSensors.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor); } } private static String triggerEventToString(TriggerEvent event) { if (event == null) return null; final StringBuilder sb = new StringBuilder("TriggerEvent[") .append(event.timestamp).append(',') .append(event.sensor.getName()); if (event.values != null) { for (int i = 0; i < event.values.length; i++) { sb.append(',').append(event.values[i]); } } return sb.append(']').toString(); } private final TriggerEventListener mSigMotionListener = new TriggerEventListener() { @Override public void onTrigger(TriggerEvent event) { if (DEBUG) Log.d(mTag, "sigMotion.onTrigger: " + triggerEventToString(event)); if (DEBUG) { final Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { v.vibrate(1000); } } requestTease(); listenForSignificantMotion(true); // reregister, this sensor only fires once } }; private final BroadcastReceiver mTeaseReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(mTag, "Received tease intent"); requestTease(); } }; private final Host.Callback mHostCallback = new Host.Callback() { @Override public void onNewNotifications() { if (DEBUG) Log.d(mTag, "onNewNotifications"); requestTease(); } }; public interface Host { void addCallback(Callback callback); void removeCallback(Callback callback); void requestDoze(DozeService dozeService); void requestTease(DozeService dozeService); void dozingStopped(DozeService dozeService); public interface Callback { void onNewNotifications(); } } } packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +32 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; Loading Loading @@ -89,6 +91,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView = new PathInterpolator(0, 0, 0.5f, 1); private boolean mDimmed; private boolean mDark; private final Paint mDarkPaint = createDarkPaint(); private int mBgResId = com.android.internal.R.drawable.notification_material_bg; private int mDimmedBgResId = com.android.internal.R.drawable.notification_material_bg_dim; Loading Loading @@ -295,6 +299,34 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } public void setDark(boolean dark, boolean fade) { // TODO implement fade if (mDark != dark) { mDark = dark; if (mDark) { setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint); } else { setLayerType(View.LAYER_TYPE_NONE, null); } } } private static Paint createDarkPaint() { final Paint p = new Paint(); final float[] invert = { -1f, 0f, 0f, 1f, 1f, 0f, -1f, 0f, 1f, 1f, 0f, 0f, -1f, 1f, 1f, 0f, 0f, 0f, 1f, 0f }; final ColorMatrix m = new ColorMatrix(invert); final ColorMatrix grayscale = new ColorMatrix(); grayscale.setSaturation(0); m.preConcat(grayscale); p.setColorFilter(new ColorMatrixColorFilter(m)); return p; } /** * Sets the resource id for the background of this notification. * Loading Loading
core/java/android/service/dreams/DreamService.java +64 −40 Original line number Diff line number Diff line Loading @@ -161,6 +161,7 @@ public class DreamService extends Service implements Window.Callback { private boolean mFinished; private boolean mCanDoze; private boolean mDozing; private boolean mWindowless; private DozeHardware mDozeHardware; private boolean mDebug = false; Loading Loading @@ -519,6 +520,24 @@ public class DreamService extends Service implements Window.Callback { return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright); } /** * Marks this dream as windowless. Only available to doze dreams. * * @hide */ public void setWindowless(boolean windowless) { mWindowless = windowless; } /** * Returns whether or not this dream is windowless. Only available to doze dreams. * * @hide */ public boolean isWindowless() { return mWindowless; } /** * Returns true if this dream is allowed to doze. * <p> Loading Loading @@ -715,6 +734,7 @@ public class DreamService extends Service implements Window.Callback { WindowManagerGlobal.getInstance().closeAll(mWindowToken, this.getClass().getName(), "Dream"); mWindowToken = null; mCanDoze = false; } } Loading Loading @@ -744,7 +764,10 @@ public class DreamService extends Service implements Window.Callback { mWindowToken = windowToken; mCanDoze = canDoze; if (mWindowless && !mCanDoze) { throw new IllegalStateException("Only doze dreams can be windowless"); } if (!mWindowless) { mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.requestFeature(Window.FEATURE_NO_TITLE); Loading Loading @@ -784,7 +807,7 @@ public class DreamService extends Service implements Window.Callback { mWindow = null; return; } } // We need to defer calling onDreamingStarted until after onWindowAttached, // which is posted to the handler by addView, so we post onDreamingStarted // to the handler also. Need to watch out here in case detach occurs before Loading @@ -792,7 +815,7 @@ public class DreamService extends Service implements Window.Callback { mHandler.post(new Runnable() { @Override public void run() { if (mWindow != null) { if (mWindow != null || mWindowless) { if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()"); mStarted = true; onDreamingStarted(); Loading Loading @@ -878,6 +901,7 @@ public class DreamService extends Service implements Window.Callback { if (isLowProfile()) pw.print(" lowprofile"); if (isFullscreen()) pw.print(" fullscreen"); if (isScreenBright()) pw.print(" bright"); if (isWindowless()) pw.print(" windowless"); if (isDozing()) pw.print(" dozing"); pw.println(); } Loading
core/res/res/values/config.xml +2 −3 Original line number Diff line number Diff line Loading @@ -1184,7 +1184,7 @@ <bool name="config_dreamsActivatedOnDockByDefault">true</bool> <!-- If supported and enabled, are dreams activated when asleep and charging? (by default) --> <bool name="config_dreamsActivatedOnSleepByDefault">false</bool> <!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) --> <!-- ComponentName of the default dream (Settings.Secure.DEFAULT_SCREENSAVER_COMPONENT) --> <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string> <!-- Are we allowed to dream while not plugged in? --> Loading @@ -1205,8 +1205,7 @@ try to start this dream if possible. The dream should typically call startDozing() to put the display into a low power state and allow the application processor to be suspended. When the dream ends, the system will go to sleep as usual. Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an empty string if none. Specify the component name or an empty string if none. Note that doze dreams are not subject to the same start conditions as ordinary dreams. Doze dreams will run whenever the power manager is in a dozing state. --> Loading
packages/SystemUI/AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -300,5 +300,11 @@ <category android:name="android.intent.category.DESK_DOCK" /> </intent-filter> </activity> <!-- I dream of notifications --> <service android:name=".doze.DozeService" android:exported="true" /> </application> </manifest>
packages/SystemUI/src/com/android/systemui/doze/DozeService.java 0 → 100644 +238 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.systemui.doze; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; import android.os.PowerManager; import android.os.Vibrator; import android.service.dreams.DozeHardware; import android.service.dreams.DreamService; import android.util.Log; import com.android.systemui.SystemUIApplication; public class DozeService extends DreamService { private static final boolean DEBUG = false; private static final String TEASE_ACTION = "com.android.systemui.doze.tease"; private final String mTag = String.format("DozeService.%08x", hashCode()); private final Context mContext = this; private Host mHost; private DozeHardware mDozeHardware; private SensorManager mSensors; private Sensor mSigMotionSensor; private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; private boolean mDreaming; private boolean mTeaseReceiverRegistered; public DozeService() { if (DEBUG) Log.d(mTag, "new DozeService()"); setDebug(DEBUG); } @Override public void onCreate() { if (DEBUG) Log.d(mTag, "onCreate"); super.onCreate(); if (getApplication() instanceof SystemUIApplication) { final SystemUIApplication app = (SystemUIApplication) getApplication(); mHost = app.getComponent(Host.class); } setWindowless(true); mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); } @Override public void onAttachedToWindow() { if (DEBUG) Log.d(mTag, "onAttachedToWindow"); super.onAttachedToWindow(); } @Override public void onDreamingStarted() { super.onDreamingStarted(); mDozeHardware = getDozeHardware(); if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " dozeHardware=" + mDozeHardware); mDreaming = true; listenForTeaseSignals(true); requestDoze(); } public void stayAwake(long millis) { if (mDreaming && millis > 0) { mWakeLock.acquire(millis); } } public void startDozing() { if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming); if (!mDreaming) { Log.w(mTag, "Not dozing, no longer dreaming"); return; } super.startDozing(); } @Override public void onDreamingStopped() { if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing()); super.onDreamingStopped(); mDreaming = false; mDozeHardware = null; if (mWakeLock.isHeld()) { mWakeLock.release(); } listenForTeaseSignals(false); stopDozing(); dozingStopped(); } @Override public void onDetachedFromWindow() { if (DEBUG) Log.d(mTag, "onDetachedFromWindow"); super.onDetachedFromWindow(); dozingStopped(); } @Override public void onDestroy() { if (DEBUG) Log.d(mTag, "onDestroy"); super.onDestroy(); dozingStopped(); } private void requestDoze() { if (mHost != null) { mHost.requestDoze(this); } } private void requestTease() { if (mHost != null) { mHost.requestTease(this); } } private void dozingStopped() { if (mHost != null) { mHost.dozingStopped(this); } } private void listenForTeaseSignals(boolean listen) { if (DEBUG) Log.d(mTag, "listenForTeaseSignals: " + listen); if (mHost == null) return; listenForSignificantMotion(listen); if (listen) { mContext.registerReceiver(mTeaseReceiver, new IntentFilter(TEASE_ACTION)); mTeaseReceiverRegistered = true; mHost.addCallback(mHostCallback); } else { if (mTeaseReceiverRegistered) { mContext.unregisterReceiver(mTeaseReceiver); } mTeaseReceiverRegistered = false; mHost.removeCallback(mHostCallback); } } private void listenForSignificantMotion(boolean listen) { if (mSigMotionSensor == null) return; if (listen) { mSensors.requestTriggerSensor(mSigMotionListener, mSigMotionSensor); } else { mSensors.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor); } } private static String triggerEventToString(TriggerEvent event) { if (event == null) return null; final StringBuilder sb = new StringBuilder("TriggerEvent[") .append(event.timestamp).append(',') .append(event.sensor.getName()); if (event.values != null) { for (int i = 0; i < event.values.length; i++) { sb.append(',').append(event.values[i]); } } return sb.append(']').toString(); } private final TriggerEventListener mSigMotionListener = new TriggerEventListener() { @Override public void onTrigger(TriggerEvent event) { if (DEBUG) Log.d(mTag, "sigMotion.onTrigger: " + triggerEventToString(event)); if (DEBUG) { final Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { v.vibrate(1000); } } requestTease(); listenForSignificantMotion(true); // reregister, this sensor only fires once } }; private final BroadcastReceiver mTeaseReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(mTag, "Received tease intent"); requestTease(); } }; private final Host.Callback mHostCallback = new Host.Callback() { @Override public void onNewNotifications() { if (DEBUG) Log.d(mTag, "onNewNotifications"); requestTease(); } }; public interface Host { void addCallback(Callback callback); void removeCallback(Callback callback); void requestDoze(DozeService dozeService); void requestTease(DozeService dozeService); void dozingStopped(DozeService dozeService); public interface Callback { void onNewNotifications(); } } }
packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +32 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; Loading Loading @@ -89,6 +91,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView = new PathInterpolator(0, 0, 0.5f, 1); private boolean mDimmed; private boolean mDark; private final Paint mDarkPaint = createDarkPaint(); private int mBgResId = com.android.internal.R.drawable.notification_material_bg; private int mDimmedBgResId = com.android.internal.R.drawable.notification_material_bg_dim; Loading Loading @@ -295,6 +299,34 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } public void setDark(boolean dark, boolean fade) { // TODO implement fade if (mDark != dark) { mDark = dark; if (mDark) { setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint); } else { setLayerType(View.LAYER_TYPE_NONE, null); } } } private static Paint createDarkPaint() { final Paint p = new Paint(); final float[] invert = { -1f, 0f, 0f, 1f, 1f, 0f, -1f, 0f, 1f, 1f, 0f, 0f, -1f, 1f, 1f, 0f, 0f, 0f, 1f, 0f }; final ColorMatrix m = new ColorMatrix(invert); final ColorMatrix grayscale = new ColorMatrix(); grayscale.setSaturation(0); m.preConcat(grayscale); p.setColorFilter(new ColorMatrixColorFilter(m)); return p; } /** * Sets the resource id for the background of this notification. * Loading