17299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn/* 27299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * Copyright (C) 2008 The Android Open Source Project 37299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * 47299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 57299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * you may not use this file except in compliance with the License. 67299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * You may obtain a copy of the License at 77299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * 87299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 97299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * 107299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 117299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 127299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * See the License for the specific language governing permissions and 147299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn * limitations under the License. 157299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn */ 167299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 177299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornpackage com.android.server; 187299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 197299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.Activity; 2062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brownimport android.app.ActivityManager; 217299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.ActivityManagerNative; 227299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.IUiModeManager; 237299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.Notification; 247299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.NotificationManager; 257299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.PendingIntent; 267299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.StatusBarManager; 277299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.app.UiModeManager; 287299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.content.BroadcastReceiver; 297299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.content.Context; 307299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.content.Intent; 317299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.content.IntentFilter; 327299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.content.pm.PackageManager; 337299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.content.res.Configuration; 344cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viveretteimport android.content.res.Resources; 35e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwoodimport android.os.BatteryManager; 367299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.os.Binder; 377299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.os.Handler; 38182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskiimport android.os.IBinder; 39e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwoodimport android.os.PowerManager; 407299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.os.RemoteException; 415ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle; 422ccda4dc8d800c3592b4bd4d1d70a064d98dd4feDianne Hackbornimport android.provider.Settings; 4311159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brownimport android.service.dreams.Sandman; 447299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport android.util.Slog; 457299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 467299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport java.io.FileDescriptor; 477299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport java.io.PrintWriter; 487299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 497299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport com.android.internal.R; 507299c41630935a2b106e73e5603579a7747f7535Dianne Hackbornimport com.android.internal.app.DisableCarModeActivity; 51182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskiimport com.android.server.twilight.TwilightListener; 52182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskiimport com.android.server.twilight.TwilightManager; 53182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskiimport com.android.server.twilight.TwilightState; 547299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 55182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskifinal class UiModeManagerService extends SystemService { 567299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private static final String TAG = UiModeManager.class.getSimpleName(); 577299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private static final boolean LOG = false; 587299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 5911ddf533a2165ca68002d3b48e312271b3d0dedbDaniel Sandler // Enable launching of applications when entering the dock. 6011ddf533a2165ca68002d3b48e312271b3d0dedbDaniel Sandler private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true; 61960779d3bbc6f2c767432ce48aca1e12cb0093b7John Spurlock private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true; 6211ddf533a2165ca68002d3b48e312271b3d0dedbDaniel Sandler 637299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn final Object mLock = new Object(); 647299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 65182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 667299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 674cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette private int mNightMode = UiModeManager.MODE_NIGHT_NO; 68ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 697299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private boolean mCarModeEnabled = false; 70e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood private boolean mCharging = false; 71182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private int mDefaultUiModeType; 72182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private boolean mCarModeKeepsScreenOn; 73182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private boolean mDeskModeKeepsScreenOn; 74182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private boolean mTelevision; 756c191299a73388cd593809c0b66bafbd08fd2982John Spurlock private boolean mWatch; 767299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private boolean mComputedNightMode; 771d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung private int mCarModeEnableFlags; 78ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 79182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski int mCurUiMode = 0; 80182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private int mSetUiMode = 0; 81b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn private boolean mHoldingConfiguration = false; 82182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 837299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private Configuration mConfiguration = new Configuration(); 84182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski boolean mSystemReady; 85ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 86182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final Handler mHandler = new Handler(); 877299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 88182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private TwilightManager mTwilightManager; 897299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private NotificationManager mNotificationManager; 907299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private StatusBarManager mStatusBarManager; 919fca9e96989bb70c3a5fa9de37681c9228c88ae6Jeff Brown 92182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private PowerManager.WakeLock mWakeLock; 937299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 94b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown public UiModeManagerService(Context context) { 95b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown super(context); 96b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown } 97b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown 98182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private static Intent buildHomeIntent(String category) { 99f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn Intent intent = new Intent(Intent.ACTION_MAIN); 100f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn intent.addCategory(category); 101f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 102f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 103f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn return intent; 104f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn } 105960779d3bbc6f2c767432ce48aca1e12cb0093b7John Spurlock 1067299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // The broadcast receiver which receives the result of the ordered broadcast sent when 1077299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // the dock state changes. The original ordered broadcast is sent with an initial result 1087299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., 1097299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // to RESULT_CANCELED, then the intent to start a dock app will not be sent. 1107299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { 1117299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn @Override 1127299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn public void onReceive(Context context, Intent intent) { 1137299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (getResultCode() != Activity.RESULT_OK) { 11469a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler if (LOG) { 115960779d3bbc6f2c767432ce48aca1e12cb0093b7John Spurlock Slog.v(TAG, "Handling broadcast result for action " + intent.getAction() 11669a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler + ": canceled: " + getResultCode()); 11769a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler } 1187299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn return; 1197299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 1207299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 12162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown final int enableFlags = intent.getIntExtra("enableFlags", 0); 12262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown final int disableFlags = intent.getIntExtra("disableFlags", 0); 123b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn synchronized (mLock) { 12462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags); 1257299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 1267299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 1277299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn }; 1287299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 1297299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() { 1307299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn @Override 1317299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn public void onReceive(Context context, Intent intent) { 1327299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1337299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn Intent.EXTRA_DOCK_STATE_UNDOCKED); 1347299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn updateDockState(state); 1357299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 1367299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn }; 1377299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 138e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { 139e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood @Override 140e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood public void onReceive(Context context, Intent intent) { 141e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0); 142e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood synchronized (mLock) { 143e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood if (mSystemReady) { 144f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn updateLocked(0, 0); 145e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood } 146e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood } 147e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood } 148e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood }; 149e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood 150182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final TwilightListener mTwilightListener = new TwilightListener() { 15157f4503e1a129d6a648f2378d36a060998a577a0Dianne Hackborn @Override 1522416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onTwilightStateChanged() { 1532416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateTwilight(); 1547299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 1557299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn }; 1567299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 157182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 158182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void onStart() { 159182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final Context context = getContext(); 1604cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette 161182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final PowerManager powerManager = 162182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski (PowerManager) context.getSystemService(Context.POWER_SERVICE); 163182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); 164182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 165182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski context.registerReceiver(mDockModeReceiver, 1667299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn new IntentFilter(Intent.ACTION_DOCK_EVENT)); 167182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski context.registerReceiver(mBatteryReceiver, 168e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 169e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood 1707299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn mConfiguration.setToDefaults(); 171e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood 1724cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette final Resources res = context.getResources(); 1734cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette mDefaultUiModeType = res.getInteger( 17444fcb83b38b062a650ddf556fe7f5e34905df9eaJoe Onorato com.android.internal.R.integer.config_defaultUiModeType); 1754cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette mCarModeKeepsScreenOn = (res.getInteger( 176e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1); 1774cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette mDeskModeKeepsScreenOn = (res.getInteger( 178e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1); 1790cf2c8a53350a800055e76c1c9bf0a6d44480768Dianne Hackborn 1804cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette final PackageManager pm = context.getPackageManager(); 1814cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION) 1824cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK); 1834cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH); 1844cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette 1854cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette final int defaultNightMode = res.getInteger( 1864cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette com.android.internal.R.integer.config_defaultNightMode); 187182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mNightMode = Settings.Secure.getInt(context.getContentResolver(), 1884cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette Settings.Secure.UI_NIGHT_MODE, defaultNightMode); 1892416e09649eb6ab767eba458796e126196c77a34Jeff Brown 19005199e83a460683e2af06212b0dc7310647e8502Adam Lesinski // Update the initial, static configurations. 19105199e83a460683e2af06212b0dc7310647e8502Adam Lesinski synchronized (this) { 19205199e83a460683e2af06212b0dc7310647e8502Adam Lesinski updateConfigurationLocked(); 19305199e83a460683e2af06212b0dc7310647e8502Adam Lesinski sendConfigurationLocked(); 19405199e83a460683e2af06212b0dc7310647e8502Adam Lesinski } 195182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 196182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski publishBinderService(Context.UI_MODE_SERVICE, mService); 1977299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 1987299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 199182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final IBinder mService = new IUiModeManager.Stub() { 200182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 201182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void enableCarMode(int flags) { 202182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final long ident = Binder.clearCallingIdentity(); 203182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski try { 204182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 2051d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung setCarModeLocked(true, flags); 206182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski if (mSystemReady) { 207182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski updateLocked(flags, 0); 208182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 209487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 210182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } finally { 211182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Binder.restoreCallingIdentity(ident); 212924e164a83056600642a3181f19094b3ecb5262dMike Lockwood } 2137299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 2147299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 215182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 216182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void disableCarMode(int flags) { 217182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final long ident = Binder.clearCallingIdentity(); 218182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski try { 219182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 2201d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung setCarModeLocked(false, 0); 221182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski if (mSystemReady) { 222182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski updateLocked(0, flags); 223182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 224487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 225182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } finally { 226182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Binder.restoreCallingIdentity(ident); 227924e164a83056600642a3181f19094b3ecb5262dMike Lockwood } 2287299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 2297299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 230182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 231182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public int getCurrentModeType() { 232182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final long ident = Binder.clearCallingIdentity(); 233182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski try { 234182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 235182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski return mCurUiMode & Configuration.UI_MODE_TYPE_MASK; 236182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 237182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } finally { 238182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Binder.restoreCallingIdentity(ident); 239487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 2407299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 241ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 242182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 243182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void setNightMode(int mode) { 244182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski switch (mode) { 245182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski case UiModeManager.MODE_NIGHT_NO: 246182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski case UiModeManager.MODE_NIGHT_YES: 247182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski case UiModeManager.MODE_NIGHT_AUTO: 248182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski break; 249182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski default: 250182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski throw new IllegalArgumentException("Unknown mode: " + mode); 251182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 252182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 253182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final long ident = Binder.clearCallingIdentity(); 254182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski try { 255182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 2564cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette if (mNightMode != mode) { 257182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Settings.Secure.putInt(getContext().getContentResolver(), 258182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Settings.Secure.UI_NIGHT_MODE, mode); 259182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mNightMode = mode; 260182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski updateLocked(0, 0); 261182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 262182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 263182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } finally { 264182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Binder.restoreCallingIdentity(ident); 265182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 266487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 267ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 268182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 269182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public int getNightMode() { 270487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown synchronized (mLock) { 271182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski return mNightMode; 2727299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 2737299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 274ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 275182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 276182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 277182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 278182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski != PackageManager.PERMISSION_GRANTED) { 279182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 280182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.println("Permission Denial: can't dump uimode service from from pid=" 281182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski + Binder.getCallingPid() 282182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski + ", uid=" + Binder.getCallingUid()); 283182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski return; 284182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 285182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 286182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski dumpImpl(pw); 287182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 288182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski }; 289182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 290182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski void dumpImpl(PrintWriter pw) { 291487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown synchronized (mLock) { 292182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.println("Current UI Mode Service state:"); 293182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mDockState="); pw.print(mDockState); 294182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); 295182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mNightMode="); pw.print(mNightMode); 296182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); 2971d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); 2981d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung pw.print(" mCarModeEnableFlags="); pw.println(mCarModeEnableFlags); 299182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); 300182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); 301182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); 302182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski pw.print(" mSystemReady="); pw.println(mSystemReady); 30305199e83a460683e2af06212b0dc7310647e8502Adam Lesinski if (mTwilightManager != null) { 30405199e83a460683e2af06212b0dc7310647e8502Adam Lesinski // We may not have a TwilightManager. 30505199e83a460683e2af06212b0dc7310647e8502Adam Lesinski pw.print(" mTwilightService.getCurrentState()="); 30605199e83a460683e2af06212b0dc7310647e8502Adam Lesinski pw.println(mTwilightManager.getCurrentState()); 30705199e83a460683e2af06212b0dc7310647e8502Adam Lesinski } 308487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 3097299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 310ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 311182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 312182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void onBootPhase(int phase) { 313182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 314182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 31505199e83a460683e2af06212b0dc7310647e8502Adam Lesinski mTwilightManager = getLocalService(TwilightManager.class); 31605199e83a460683e2af06212b0dc7310647e8502Adam Lesinski if (mTwilightManager != null) { 31705199e83a460683e2af06212b0dc7310647e8502Adam Lesinski mTwilightManager.registerListener(mTwilightListener, mHandler); 31805199e83a460683e2af06212b0dc7310647e8502Adam Lesinski } 319182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mSystemReady = true; 320182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; 321182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski updateComputedNightModeLocked(); 322182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski updateLocked(0, 0); 323182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 3247299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3257299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3267299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 3271d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung void setCarModeLocked(boolean enabled, int flags) { 3287299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mCarModeEnabled != enabled) { 3297299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn mCarModeEnabled = enabled; 3307299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3311d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung mCarModeEnableFlags = flags; 3327299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3337299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 334487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown private void updateDockState(int newState) { 3357299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn synchronized (mLock) { 3367299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (newState != mDockState) { 3377299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn mDockState = newState; 3381d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0); 3397299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mSystemReady) { 340f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0); 3417299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3427299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3437299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 3447299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 345e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood 346487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown private static boolean isDeskDockState(int state) { 34769a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler switch (state) { 34869a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler case Intent.EXTRA_DOCK_STATE_DESK: 34969a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler case Intent.EXTRA_DOCK_STATE_LE_DESK: 35069a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler case Intent.EXTRA_DOCK_STATE_HE_DESK: 35169a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler return true; 35269a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler default: 35369a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler return false; 35469a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler } 35569a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler } 35669a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler 357487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown private void updateConfigurationLocked() { 3586c191299a73388cd593809c0b66bafbd08fd2982John Spurlock int uiMode = mDefaultUiModeType; 3596c191299a73388cd593809c0b66bafbd08fd2982John Spurlock if (mTelevision) { 3606c191299a73388cd593809c0b66bafbd08fd2982John Spurlock uiMode = Configuration.UI_MODE_TYPE_TELEVISION; 3616c191299a73388cd593809c0b66bafbd08fd2982John Spurlock } else if (mWatch) { 3626c191299a73388cd593809c0b66bafbd08fd2982John Spurlock uiMode = Configuration.UI_MODE_TYPE_WATCH; 3636c191299a73388cd593809c0b66bafbd08fd2982John Spurlock } else if (mCarModeEnabled) { 364b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn uiMode = Configuration.UI_MODE_TYPE_CAR; 36569a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler } else if (isDeskDockState(mDockState)) { 366b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn uiMode = Configuration.UI_MODE_TYPE_DESK; 367b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn } 3684cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette 3694cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { 3704cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette updateComputedNightModeLocked(); 3714cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES 3724cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette : Configuration.UI_MODE_NIGHT_NO; 373b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn } else { 3744cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette uiMode |= mNightMode << 4; 3758daf2a47995b4522bceb38eef8c310268b1d91b0Daniel Sandler } 3768daf2a47995b4522bceb38eef8c310268b1d91b0Daniel Sandler 3778daf2a47995b4522bceb38eef8c310268b1d91b0Daniel Sandler if (LOG) { 378960779d3bbc6f2c767432ce48aca1e12cb0093b7John Spurlock Slog.d(TAG, 379960779d3bbc6f2c767432ce48aca1e12cb0093b7John Spurlock "updateConfigurationLocked: mDockState=" + mDockState 3808daf2a47995b4522bceb38eef8c310268b1d91b0Daniel Sandler + "; mCarMode=" + mCarModeEnabled 3818daf2a47995b4522bceb38eef8c310268b1d91b0Daniel Sandler + "; mNightMode=" + mNightMode 3828daf2a47995b4522bceb38eef8c310268b1d91b0Daniel Sandler + "; uiMode=" + uiMode); 383b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn } 384ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 385b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn mCurUiMode = uiMode; 38662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (!mHoldingConfiguration) { 3872ccda4dc8d800c3592b4bd4d1d70a064d98dd4feDianne Hackborn mConfiguration.uiMode = uiMode; 38862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 38962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 390ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 391487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown private void sendConfigurationLocked() { 39262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (mSetUiMode != mConfiguration.uiMode) { 39362c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown mSetUiMode = mConfiguration.uiMode; 39462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 39562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown try { 39662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown ActivityManagerNative.getDefault().updateConfiguration(mConfiguration); 39762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } catch (RemoteException e) { 39862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown Slog.w(TAG, "Failure communicating with activity manager", e); 3997299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 400b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn } 401b8b11a0b1d82e24f7a79f2e1672e7f5cf1611a55Dianne Hackborn } 402ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 403182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski void updateLocked(int enableFlags, int disableFlags) { 404487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown String action = null; 405487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown String oldAction = null; 406487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { 407487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown adjustStatusBarCarModeLocked(); 408487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown oldAction = UiModeManager.ACTION_EXIT_CAR_MODE; 409487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else if (isDeskDockState(mLastBroadcastState)) { 410487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown oldAction = UiModeManager.ACTION_EXIT_DESK_MODE; 411487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 412ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 413487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (mCarModeEnabled) { 414487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) { 415780b2603041a56800ff6e49fb14535c1b1ca8907Tobias Haamel adjustStatusBarCarModeLocked(); 416ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 417487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (oldAction != null) { 418182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); 4197299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 420487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR; 421487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown action = UiModeManager.ACTION_ENTER_CAR_MODE; 422487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 423487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else if (isDeskDockState(mDockState)) { 424487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (!isDeskDockState(mLastBroadcastState)) { 425487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (oldAction != null) { 426182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); 4277299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 428487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mLastBroadcastState = mDockState; 429487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown action = UiModeManager.ACTION_ENTER_DESK_MODE; 4307299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 431487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else { 432487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 433487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown action = oldAction; 434487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 435ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 436487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (action != null) { 437487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (LOG) { 438487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown Slog.v(TAG, String.format( 439487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x", 440487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown action, enableFlags, disableFlags)); 441487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 44269a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler 443487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // Send the ordered broadcast; the result receiver will receive after all 444487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // broadcasts have been sent. If any broadcast receiver changes the result 445487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // code from the initial value of RESULT_OK, then the result receiver will 446487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // not launch the corresponding dock application. This gives apps a chance 447487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // to override the behavior and stay in their app even when the device is 448487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // placed into a dock. 449487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown Intent intent = new Intent(action); 450487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown intent.putExtra("enableFlags", enableFlags); 451487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown intent.putExtra("disableFlags", disableFlags); 452182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, 453487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mResultReceiver, null, Activity.RESULT_OK, null, null); 454487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown 455487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // Attempting to make this transition a little more clean, we are going 456487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // to hold off on doing a configuration change until we have finished 457487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // the broadcast and started the home activity. 458487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mHoldingConfiguration = true; 459487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown updateConfigurationLocked(); 460487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else { 461487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown String category = null; 462487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (mCarModeEnabled) { 463487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (ENABLE_LAUNCH_CAR_DOCK_APP 464487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 465487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown category = Intent.CATEGORY_CAR_DOCK; 466f5c5d22c471f399f215662a8e471bf02b5b6bcfaDianne Hackborn } 467487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else if (isDeskDockState(mDockState)) { 468487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (ENABLE_LAUNCH_DESK_DOCK_APP 469487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 470487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown category = Intent.CATEGORY_DESK_DOCK; 471487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 472487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else { 473487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) { 474487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown category = Intent.CATEGORY_HOME; 47569a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler } 476487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 47769a1da4ddec90db501a54f0c4de94e9557aebd2eDaniel Sandler 478487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (LOG) { 479487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown Slog.v(TAG, "updateLocked: null action, mDockState=" 480487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown + mDockState +", category=" + category); 481d49258fed489bcd72a2b2a6ce3a3c38d4b2531e6Dianne Hackborn } 482e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood 483487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown sendConfigurationAndStartDreamOrDockAppLocked(category); 484487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } 485487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown 486487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown // keep screen on when charging and in car mode 487487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown boolean keepScreenOn = mCharging && 4881d0a7ccd007e7ce62588212f76db09d2e593b742keunyoung ((mCarModeEnabled && mCarModeKeepsScreenOn && 489c093bf26456e55c09ed4e61ad36999d07a86be1fkeunyoung (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) || 490487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn)); 491487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (keepScreenOn != mWakeLock.isHeld()) { 492487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown if (keepScreenOn) { 493487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mWakeLock.acquire(); 494487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown } else { 495487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mWakeLock.release(); 496e29db6a2d2ba8d9458c88fe6c6dbb2164462773eMike Lockwood } 4977299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 4987299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 4997299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 50062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) { 50162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Launch a dock activity 50262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown String category = null; 50362c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) { 50462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Only launch car home when car mode is enabled and the caller 50562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // has asked us to switch to it. 50662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (ENABLE_LAUNCH_CAR_DOCK_APP 50762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 50862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown category = Intent.CATEGORY_CAR_DOCK; 50962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 51062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) { 51162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Only launch car home when desk mode is enabled and the caller 51262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // has asked us to switch to it. Currently re-using the car 51362c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // mode flag since we don't have a formal API for "desk mode". 51462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (ENABLE_LAUNCH_DESK_DOCK_APP 51562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 51662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown category = Intent.CATEGORY_DESK_DOCK; 51762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 51862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } else { 51962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Launch the standard home app if requested. 52062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) { 52162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown category = Intent.CATEGORY_HOME; 52262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 52362c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 52462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 52562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (LOG) { 52662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown Slog.v(TAG, String.format( 52762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, " 52862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown + "category=%s", 52962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown action, enableFlags, disableFlags, category)); 53062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 53162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 53262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown sendConfigurationAndStartDreamOrDockAppLocked(category); 53362c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 53462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 53562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown private void sendConfigurationAndStartDreamOrDockAppLocked(String category) { 53662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Update the configuration but don't send it yet. 53762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown mHoldingConfiguration = false; 53862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown updateConfigurationLocked(); 53962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 54062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Start the dock app, if there is one. 54162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown boolean dockAppStarted = false; 54262c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown if (category != null) { 54362c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Now we are going to be careful about switching the 54462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // configuration and starting the activity -- we need to 54562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // do this in a specific order under control of the 54662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // activity manager, to do it cleanly. So compute the 54762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // new config, but don't set it yet, and let the 54862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // activity manager take care of both the start and config 54962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // change. 55062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown Intent homeIntent = buildHomeIntent(category); 551182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski if (Sandman.shouldStartDockApp(getContext(), homeIntent)) { 55211159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown try { 55311159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown int result = ActivityManagerNative.getDefault().startActivityWithConfig( 554f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn null, null, homeIntent, null, null, null, 0, 0, 55511159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown mConfiguration, null, UserHandle.USER_CURRENT); 55611159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown if (result >= ActivityManager.START_SUCCESS) { 55711159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown dockAppStarted = true; 55811159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) { 55911159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown Slog.e(TAG, "Could not start dock app: " + homeIntent 56011159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown + ", startActivityWithConfig result " + result); 56111159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown } 56211159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown } catch (RemoteException ex) { 56311159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown Slog.e(TAG, "Could not start dock app: " + homeIntent, ex); 56462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 56562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 56662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 56762c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 56862c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // Send the new configuration. 56962c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown sendConfigurationLocked(); 57062c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 57162c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown // If we did not start a dock app, then start dreaming if supported. 57211159e9a785a143c9f3765bdf5a5ccfd77842d7aJeff Brown if (category != null && !dockAppStarted) { 573182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Sandman.startDreamWhenDockedIfAppropriate(getContext()); 57462c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 57562c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown } 57662c82e4d92cc0b856059f905d81885f7808a0e7dJeff Brown 5777299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn private void adjustStatusBarCarModeLocked() { 578182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final Context context = getContext(); 5797299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mStatusBarManager == null) { 580487bb6e20b96aa6920e08669a260118a40e604d5Jeff Brown mStatusBarManager = (StatusBarManager) 581182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski context.getSystemService(Context.STATUS_BAR_SERVICE); 5827299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 5837299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 584089de88fc2f08d284cf8031aa33cff06011a4162Joe Onorato // Fear not: StatusBarManagerService manages a list of requests to disable 5857299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // features of the status bar; these are ORed together to form the 5867299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // active disabled list. So if (for example) the device is locked and 5877299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // the status bar should be totally disabled, the calls below will 5887299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn // have no effect until the device is unlocked. 5897299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mStatusBarManager != null) { 5907299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn mStatusBarManager.disable(mCarModeEnabled 5917299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn ? StatusBarManager.DISABLE_NOTIFICATION_TICKER 5927299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn : StatusBarManager.DISABLE_NONE); 5937299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 5947299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 5957299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mNotificationManager == null) { 5967299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn mNotificationManager = (NotificationManager) 597182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski context.getSystemService(Context.NOTIFICATION_SERVICE); 5987299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 5997299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 6007299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mNotificationManager != null) { 6017299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn if (mCarModeEnabled) { 602182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class); 6037299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 6041ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren Notification.Builder n = new Notification.Builder(context) 6051ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setSmallIcon(R.drawable.stat_notify_car_mode) 6061ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setDefaults(Notification.DEFAULT_LIGHTS) 6071ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setOngoing(true) 6081ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setWhen(0) 6091ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setColor(context.getColor( 6101ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren com.android.internal.R.color.system_notification_accent_color)) 6111ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setContentTitle( 6121ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren context.getString(R.string.car_mode_disable_notification_title)) 6131ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setContentText( 6141ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren context.getString(R.string.car_mode_disable_notification_message)) 6151ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren .setContentIntent( 6161ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0, 6171ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren null, UserHandle.CURRENT)); 61850cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn mNotificationManager.notifyAsUser(null, 6191ce4b6d3c6cb5b2eb9c9d00472be12245db92427Chris Wren R.string.car_mode_disable_notification_title, n.build(), UserHandle.ALL); 6207299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } else { 62150cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn mNotificationManager.cancelAsUser(null, 62250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn R.string.car_mode_disable_notification_title, UserHandle.ALL); 6237299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 6247299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 6257299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 6267299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 627182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski void updateTwilight() { 6282416e09649eb6ab767eba458796e126196c77a34Jeff Brown synchronized (mLock) { 6294cc1e9e707242479e00c4bc4bc0ea02bffccfa85Alan Viverette if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { 6302416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateComputedNightModeLocked(); 6312416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateLocked(0, 0); 6327299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 6337299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 6342416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 6357299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn 6362416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void updateComputedNightModeLocked() { 63705199e83a460683e2af06212b0dc7310647e8502Adam Lesinski if (mTwilightManager != null) { 63805199e83a460683e2af06212b0dc7310647e8502Adam Lesinski TwilightState state = mTwilightManager.getCurrentState(); 63905199e83a460683e2af06212b0dc7310647e8502Adam Lesinski if (state != null) { 64005199e83a460683e2af06212b0dc7310647e8502Adam Lesinski mComputedNightMode = state.isNight(); 64105199e83a460683e2af06212b0dc7310647e8502Adam Lesinski } 6427299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 6437299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn } 644ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 645ba9ab183186cb2ef704759485a8481d5b8c8a650Bernd Holzhey 6467299c41630935a2b106e73e5603579a7747f7535Dianne Hackborn} 647