From 154f7a1cc2d4f0468a7cc8dfa36e837c84cd9f7e Mon Sep 17 00:00:00 2001 From: Tobias Haamel Date: Wed, 17 Feb 2010 11:56:39 -0800 Subject: [PATCH] Show car mode notification in status bar. The notification is an ongoing event and can be used to get out of car mode. --- api/current.xml | 11 +++ core/java/android/content/Intent.java | 27 ++++-- .../internal/app/DisableCarModeActivity.java | 42 ++++++++++ core/res/AndroidManifest.xml | 4 + .../drawable-hdpi/stat_notify_car_mode.png | Bin 0 -> 1677 bytes .../drawable-mdpi/stat_notify_car_mode.png | Bin 0 -> 820 bytes core/res/res/values/strings.xml | 5 ++ .../java/com/android/server/DockObserver.java | 78 +++++++++++++----- 8 files changed, 143 insertions(+), 24 deletions(-) create mode 100644 core/java/com/android/internal/app/DisableCarModeActivity.java create mode 100644 core/res/res/drawable-hdpi/stat_notify_car_mode.png create mode 100644 core/res/res/drawable-mdpi/stat_notify_car_mode.png diff --git a/api/current.xml b/api/current.xml index 444b002ed4fec..5592759226a67 100644 --- a/api/current.xml +++ b/api/current.xml @@ -38899,6 +38899,17 @@ visibility="public" > + + The intent will have the following extra values: + * + *

This is intended for monitoring the current dock state. * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK} * or {@link #CATEGORY_DESK_DOCK} instead. */ @@ -2153,6 +2160,16 @@ public class Intent implements Parcelable, Cloneable { */ public static final int EXTRA_DOCK_STATE_CAR = 2; + /** + * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} + * intents to request the physical dock state. Possible values are + * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED}, + * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or + * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}. + */ + public static final String EXTRA_PHYSICAL_DOCK_STATE = + "android.intent.extra.PHYSICAL_DOCK_STATE"; + /** * Used as an boolean extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} * intents to indicate that the car mode is enabled or not. diff --git a/core/java/com/android/internal/app/DisableCarModeActivity.java b/core/java/com/android/internal/app/DisableCarModeActivity.java new file mode 100644 index 0000000000000..95dc1f9d014b3 --- /dev/null +++ b/core/java/com/android/internal/app/DisableCarModeActivity.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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.internal.app; + +import android.app.Activity; +import android.app.IUiModeManager; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +public class DisableCarModeActivity extends Activity { + private static final String TAG = "DisableCarModeActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + try { + IUiModeManager uiModeManager = IUiModeManager.Stub.asInterface( + ServiceManager.getService("uimode")); + uiModeManager.disableCarMode(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to disable car mode", e); + } + finish(); + } + +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a27d28f6138ac..333db05a10f4b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1252,6 +1252,10 @@ + + 50000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU&FG)l}RCwCtm`hAlR~X0dod?YDkl`f? zR8Wk?n6#iJZJH)ZVi#>vW$&WtqKl?o;HHfWt1i0fMmCMcjcF4%T~V8Ki%t4QWn46( zNM(U2!&@E$!#w)?4`(Kq;a(nX7bZQ)mviUb^Zmd7`ObH~@7%F7nT++KG@tbXwHJy^ zV5bTV4Gqn7UC3#q4T%&?nMI<=cStWXvKii!Cr|Rv_I6{YzP?_DFPD^*oT#g-vn0EA z?XrTw;JSIMtE<-Y=g+P2@$sxIEiK(*_^ctgp^c4=ZJ!JzwDJoW?mm3@aJ;&@I?V4h zk}{HZ*?PYb-_+Dp{Qmv>VF>o{`;zh8&dKcEyEnqh`&wFB+M1i2tyC&y`ThQ7Ud^Y| z>EGz@qW?Ypicu-HZTmg?qduSS4f=9)Lg-i{BO})E@Ng8*bvg+>efo53G9nTP1o}EU zI@-$1%Qch`2qdm2lgS%%b8|6PyErj1vBX#w1Oj$#ZEXo&EUl=h*p2=f#y&7{RWv_8 zZ}s>0N72s{+LFwkJ$tf5jvYIeBeKN2L00t!Uvk;R#rnJa+I6_Q}Cf>oaNl68cH zAuM6$@MTLjT{AF2*Hu~)A0*}k=AJ25aGMk0wsqLCB$3P*PqjGOWly${R=JW|6c%iHwYrbx~+s)^)>-ptx@ zTgC$+5}B{EvQk;rb{Ka#K(@cQxLA0lkUB?#{0tan?hu&LEy~%EP0y;G^9)|_@7uR8 zY+N6<*IGU(x7ifrA!03$VKQ~zj^`D^;gt=b|G|wgkKy7?Pcmtj{F5>APcLI>bK-25 zai1$0TsP~uEXjD%NWvV^8f~)+s8`Dv-AR)Yij2*G!SFdN_&PEK+dcO4c45%n3a{{)-V8989opWhqGHs0!vZwrdZ*RY{56oO*p)g(3sw74j8(E zXv?L0Kv=>Qw&u&$rr%B6Goq}l2Y@1gs#wWOfPBuY76@fO1xWK5Rbf1L1JIe2X?oU} z-sviu^N4hXAuM4ETQ*o&bjy!80535)YO?KaNW25s4W8Qx@Cw8yV+8y(1csQKk?2`t zhKLWTkdAbPAuM4ETQ>Arvn3gVZWecU0-9w`$q!K+TZj>T37iA)2vW!U-2hh8+Y<9E zgLRstxzdrYFw9Yo3LEdv7RKwQX`Y%A0j!TX`O3-`C?8EQcAFKKQGGj@Q*4sv3USbn z!36^JHR7XI1=CSM6#|`jB~L_n+palPRaGK%fyZv=RWn!USh3|+-*g#w6nC{AbS@Qo zgoW+A075GJd8=c;!@89Hyv3-tXG6tz#?6kaG547refZ;z5p9K6rT$lB{x|>6{4Kx$ X#SNjnf9Fzv00000NkvXXu0mjfp<6c( literal 0 HcmV?d00001 diff --git a/core/res/res/drawable-mdpi/stat_notify_car_mode.png b/core/res/res/drawable-mdpi/stat_notify_car_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..c66424414f007accc833f152dce7c7f623189a1e GIT binary patch literal 820 zcmV-41Izr0P)P000>X1^@s6#OZ}&0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!)=5M`RCwCFR?AKzK@=?>ksu_fC?H~B zrHQMaWa66nfXU$2nFRa;SU4XsiNQY*7vmOs#jIrk&Q}i?q z4VcVW$w{Z`o_lZIs#8^MRaI5|Z&<}UH2XBd+S*zIpD#dcjQJEet5&O-Nii%e$0Rs| zrbD4nBoGJ)!q^&(#w#k7N(tQ*lAX?+Bp3{){eFLPYimn5olXw@2F?KnYXHm`0X_pC zyWOt1y1Ei~cXx-iS}ip-$?EEAdUJC#84icpEdV>m$HyhJrHIGlOqKJ!`dE+GM!tUayxtMaIhvC7GX}k8u`IN-m$zYmSSHi$APZ>sP2OXt)18 zR?pAR1PLbBuo5+uJ#C6~-H>#Nlv=Uau$Mko0&w38}2;%F2pBU+5F)5(OU~ z9`<41M>od`d_LcT#bSAlH=-^@Q8byoyu5JP24`fZ#_1@_vgDf zar7`gK0cnYnog&q%+1Y3bh7+}@jc*Po}mHQ-=lrNr62uiXFP2h`p3oXcHaOhl=RE^ z@VH#AC~X6328F2js!++1F$ipzwDUXi`hibB=^ryqLfCA!G{7V( z6mtngj5Z)U7^9s$@}(_pj5+pA=3~W`)Zqa52DD|rE&B%sUV3aiv&Ua5?Zyzq4CKX3 yV@>00RKANQYU?$X?9=0000 We\'ve encountered a problem turning off Tethering. Please try again. + + + Car mode enabled + Select to disable car mode. + diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index b566fb7eb8a58..4791718aad9d8 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -22,8 +22,10 @@ import android.app.AlarmManager; import android.app.IActivityManager; import android.app.IUiModeManager; import android.app.KeyguardManager; -import android.app.StatusBarManager; +import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.StatusBarManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.ActivityNotFoundException; @@ -55,6 +57,8 @@ import android.text.format.DateUtils; import android.text.format.Time; import android.util.Log; +import com.android.internal.R; +import com.android.internal.app.DisableCarModeActivity; import com.android.internal.widget.LockPatternUtils; import java.io.FileNotFoundException; @@ -101,6 +105,7 @@ class DockObserver extends UEventObserver { private final Context mContext; private PowerManagerService mPowerManager; + private NotificationManager mNotificationManager; private KeyguardManager.KeyguardLock mKeyguardLock; private boolean mKeyguardDisabled; @@ -125,7 +130,8 @@ class DockObserver extends UEventObserver { // Launch a dock activity String category; - if (mCarModeEnabled || mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + if (mCarModeEnabled) { + // Only launch car home when car mode is enabled. category = Intent.CATEGORY_CAR_DOCK; } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { category = Intent.CATEGORY_DESK_DOCK; @@ -332,9 +338,13 @@ class DockObserver extends UEventObserver { if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) { // Pretend to be in DOCK_STATE_CAR. intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR); + } else if (!mCarModeEnabled && mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + // Pretend to be in DOCK_STATE_UNDOCKED. + intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); } else { intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); } + intent.putExtra(Intent.EXTRA_PHYSICAL_DOCK_STATE, mDockState); intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled); // Check if this is Bluetooth Dock @@ -462,6 +472,52 @@ class DockObserver extends UEventObserver { } }; + private void adjustStatusBarCarMode() { + if (mStatusBarManager == null) { + mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + + // Fear not: StatusBarService manages a list of requests to disable + // features of the status bar; these are ORed together to form the + // active disabled list. So if (for example) the device is locked and + // the status bar should be totally disabled, the calls below will + // have no effect until the device is unlocked. + if (mStatusBarManager != null) { + long ident = Binder.clearCallingIdentity(); + mStatusBarManager.disable(mCarModeEnabled + ? StatusBarManager.DISABLE_NOTIFICATION_TICKER + : StatusBarManager.DISABLE_NONE); + Binder.restoreCallingIdentity(ident); + } + + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + + if (mNotificationManager != null) { + long ident = Binder.clearCallingIdentity(); + if (mCarModeEnabled) { + Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); + + Notification n = new Notification(); + n.icon = R.drawable.stat_notify_car_mode; + n.defaults = Notification.DEFAULT_LIGHTS; + n.flags = Notification.FLAG_ONGOING_EVENT; + n.when = 0; + n.setLatestEventInfo( + mContext, + mContext.getString(R.string.car_mode_disable_notification_title), + mContext.getString(R.string.car_mode_disable_notification_message), + PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0)); + mNotificationManager.notify(0, n); + } else { + mNotificationManager.cancel(0); + } + Binder.restoreCallingIdentity(ident); + } + } + private void setCarMode(boolean enabled) throws RemoteException { mCarModeEnabled = enabled; if (enabled) { @@ -475,23 +531,7 @@ class DockObserver extends UEventObserver { setMode(Configuration.UI_MODE_TYPE_NORMAL, Configuration.UI_MODE_NIGHT_UNDEFINED); } - - if (mStatusBarManager == null) { - mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - - // Fear not: StatusBarService manages a list of requests to disable - // features of the status bar; these are ORed together to form the - // active disabled list. So if (for example) the device is locked and - // the status bar should be totally disabled, the calls below will - // have no effect until the device is unlocked. - if (mStatusBarManager != null) { - long ident = Binder.clearCallingIdentity(); - mStatusBarManager.disable(enabled - ? StatusBarManager.DISABLE_NOTIFICATION_TICKER - : StatusBarManager.DISABLE_NONE); - Binder.restoreCallingIdentity(ident); - } + adjustStatusBarCarMode(); } private void setMode(int modeType, int modeNight) throws RemoteException {