/services/java/com/android/server/DockObserver.java

https://github.com/aizuzi/platform_frameworks_base · Java · 206 lines · 151 code · 27 blank · 28 comment · 36 complexity · 35ea09da98bdc046b59326b6e47af88e MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.server;
  17. import android.content.ContentResolver;
  18. import android.content.Context;
  19. import android.content.Intent;
  20. import android.media.AudioManager;
  21. import android.media.Ringtone;
  22. import android.media.RingtoneManager;
  23. import android.net.Uri;
  24. import android.os.Handler;
  25. import android.os.Message;
  26. import android.os.PowerManager;
  27. import android.os.SystemClock;
  28. import android.os.UEventObserver;
  29. import android.os.UserHandle;
  30. import android.provider.Settings;
  31. import android.util.Log;
  32. import android.util.Slog;
  33. import java.io.FileNotFoundException;
  34. import java.io.FileReader;
  35. /**
  36. * <p>DockObserver monitors for a docking station.
  37. */
  38. final class DockObserver extends UEventObserver {
  39. private static final String TAG = DockObserver.class.getSimpleName();
  40. private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
  41. private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
  42. private static final int MSG_DOCK_STATE_CHANGED = 0;
  43. private final Object mLock = new Object();
  44. private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
  45. private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
  46. private boolean mSystemReady;
  47. private final Context mContext;
  48. private final PowerManager mPowerManager;
  49. private final PowerManager.WakeLock mWakeLock;
  50. public DockObserver(Context context) {
  51. mContext = context;
  52. mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
  53. mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
  54. init(); // set initial status
  55. startObserving(DOCK_UEVENT_MATCH);
  56. }
  57. @Override
  58. public void onUEvent(UEventObserver.UEvent event) {
  59. if (Log.isLoggable(TAG, Log.VERBOSE)) {
  60. Slog.v(TAG, "Dock UEVENT: " + event.toString());
  61. }
  62. synchronized (mLock) {
  63. try {
  64. int newState = Integer.parseInt(event.get("SWITCH_STATE"));
  65. if (newState != mDockState) {
  66. mPreviousDockState = mDockState;
  67. mDockState = newState;
  68. if (mSystemReady) {
  69. // Wake up immediately when docked or undocked.
  70. mPowerManager.wakeUp(SystemClock.uptimeMillis());
  71. updateLocked();
  72. }
  73. }
  74. } catch (NumberFormatException e) {
  75. Slog.e(TAG, "Could not parse switch state from event " + event);
  76. }
  77. }
  78. }
  79. private void init() {
  80. synchronized (mLock) {
  81. try {
  82. char[] buffer = new char[1024];
  83. FileReader file = new FileReader(DOCK_STATE_PATH);
  84. try {
  85. int len = file.read(buffer, 0, 1024);
  86. mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
  87. mPreviousDockState = mDockState;
  88. } finally {
  89. file.close();
  90. }
  91. } catch (FileNotFoundException e) {
  92. Slog.w(TAG, "This kernel does not have dock station support");
  93. } catch (Exception e) {
  94. Slog.e(TAG, "" , e);
  95. }
  96. }
  97. }
  98. void systemReady() {
  99. synchronized (mLock) {
  100. // don't bother broadcasting undocked here
  101. if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
  102. updateLocked();
  103. }
  104. mSystemReady = true;
  105. }
  106. }
  107. private void updateLocked() {
  108. mWakeLock.acquire();
  109. mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
  110. }
  111. private void handleDockStateChange() {
  112. synchronized (mLock) {
  113. Slog.i(TAG, "Dock state changed: " + mDockState);
  114. // Skip the dock intent if not yet provisioned.
  115. final ContentResolver cr = mContext.getContentResolver();
  116. if (Settings.Global.getInt(cr,
  117. Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
  118. Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
  119. return;
  120. }
  121. // Pack up the values and broadcast them to everyone
  122. Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
  123. intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
  124. intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
  125. // Play a sound to provide feedback to confirm dock connection.
  126. // Particularly useful for flaky contact pins...
  127. if (Settings.Global.getInt(cr,
  128. Settings.Global.DOCK_SOUNDS_ENABLED, 1) == 1) {
  129. String whichSound = null;
  130. if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
  131. if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
  132. (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
  133. (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
  134. whichSound = Settings.Global.DESK_UNDOCK_SOUND;
  135. } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
  136. whichSound = Settings.Global.CAR_UNDOCK_SOUND;
  137. }
  138. } else {
  139. if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
  140. (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
  141. (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
  142. whichSound = Settings.Global.DESK_DOCK_SOUND;
  143. } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
  144. whichSound = Settings.Global.CAR_DOCK_SOUND;
  145. }
  146. }
  147. if (whichSound != null) {
  148. final String soundPath = Settings.Global.getString(cr, whichSound);
  149. if (soundPath != null) {
  150. final Uri soundUri = Uri.parse("file://" + soundPath);
  151. if (soundUri != null) {
  152. final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
  153. if (sfx != null) {
  154. sfx.setStreamType(AudioManager.STREAM_SYSTEM);
  155. sfx.play();
  156. }
  157. }
  158. }
  159. }
  160. }
  161. // Send the dock event intent.
  162. // There are many components in the system watching for this so as to
  163. // adjust audio routing, screen orientation, etc.
  164. mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
  165. // Release the wake lock that was acquired when the message was posted.
  166. mWakeLock.release();
  167. }
  168. }
  169. private final Handler mHandler = new Handler(true /*async*/) {
  170. @Override
  171. public void handleMessage(Message msg) {
  172. switch (msg.what) {
  173. case MSG_DOCK_STATE_CHANGED:
  174. handleDockStateChange();
  175. break;
  176. }
  177. }
  178. };
  179. }