blob: 4a8bf720aae183ed5f89cc87bf2726713d8287c7 [file] [log] [blame]
Dan Murphyc9f4eaf2009-08-12 15:15:43 -05001/*
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
17package com.android.server;
18
Daniel Sandler0e9d2af2010-01-25 11:33:03 -050019import android.content.ContentResolver;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050020import android.content.Context;
21import android.content.Intent;
Daniel Sandlerec2c88d2010-02-20 01:04:57 -050022import android.media.AudioManager;
Daniel Sandler0e9d2af2010-01-25 11:33:03 -050023import android.media.Ringtone;
24import android.media.RingtoneManager;
25import android.net.Uri;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050026import android.os.Handler;
27import android.os.Message;
Jeff Brown96307042012-07-27 15:51:34 -070028import android.os.PowerManager;
Ken Schultzf02c0742009-09-10 18:37:37 -050029import android.os.SystemClock;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050030import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070031import android.os.UserHandle;
Dianne Hackborn49493342009-10-02 10:44:41 -070032import android.provider.Settings;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050033import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080034import android.util.Slog;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050035
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050036import java.io.FileNotFoundException;
Jaikumar Ganesh3fbf7b62009-12-02 17:28:38 -080037import java.io.FileReader;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050038
39/**
40 * <p>DockObserver monitors for a docking station.
41 */
Jeff Brown008b1762012-08-20 20:15:34 -070042final class DockObserver extends UEventObserver {
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050043 private static final String TAG = DockObserver.class.getSimpleName();
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050044
45 private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
46 private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
47
Jeff Brown008b1762012-08-20 20:15:34 -070048 private static final int MSG_DOCK_STATE_CHANGED = 0;
49
50 private final Object mLock = new Object();
Bernd Holzheybfca3a02010-02-10 17:39:51 +010051
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070052 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
Daniel Sandler0e9d2af2010-01-25 11:33:03 -050053 private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
54
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070055 private boolean mSystemReady;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050056
57 private final Context mContext;
Jeff Brown62c82e42012-09-26 01:30:41 -070058 private final PowerManager mPowerManager;
59 private final PowerManager.WakeLock mWakeLock;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050060
Jeff Brown96307042012-07-27 15:51:34 -070061 public DockObserver(Context context) {
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050062 mContext = context;
Tobias Haamel27b28b32010-02-09 23:09:17 +010063
Jeff Brown62c82e42012-09-26 01:30:41 -070064 mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
65 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
66
67 init(); // set initial status
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070068 startObserving(DOCK_UEVENT_MATCH);
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050069 }
70
71 @Override
72 public void onUEvent(UEventObserver.UEvent event) {
73 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080074 Slog.v(TAG, "Dock UEVENT: " + event.toString());
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050075 }
76
Jeff Brown008b1762012-08-20 20:15:34 -070077 synchronized (mLock) {
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070078 try {
79 int newState = Integer.parseInt(event.get("SWITCH_STATE"));
80 if (newState != mDockState) {
Daniel Sandler0e9d2af2010-01-25 11:33:03 -050081 mPreviousDockState = mDockState;
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070082 mDockState = newState;
83 if (mSystemReady) {
Jeff Brown62c82e42012-09-26 01:30:41 -070084 // Wake up immediately when docked or undocked.
85 mPowerManager.wakeUp(SystemClock.uptimeMillis());
86
Jeff Brown008b1762012-08-20 20:15:34 -070087 updateLocked();
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070088 }
89 }
90 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080091 Slog.e(TAG, "Could not parse switch state from event " + event);
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -070092 }
Dan Murphyc9f4eaf2009-08-12 15:15:43 -050093 }
94 }
95
Jeff Brown008b1762012-08-20 20:15:34 -070096 private void init() {
97 synchronized (mLock) {
98 try {
99 char[] buffer = new char[1024];
100 FileReader file = new FileReader(DOCK_STATE_PATH);
101 try {
102 int len = file.read(buffer, 0, 1024);
103 mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
104 mPreviousDockState = mDockState;
105 } finally {
106 file.close();
107 }
108 } catch (FileNotFoundException e) {
109 Slog.w(TAG, "This kernel does not have dock station support");
110 } catch (Exception e) {
111 Slog.e(TAG, "" , e);
112 }
Dan Murphyc9f4eaf2009-08-12 15:15:43 -0500113 }
Dan Murphyc9f4eaf2009-08-12 15:15:43 -0500114 }
115
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -0700116 void systemReady() {
Jeff Brown008b1762012-08-20 20:15:34 -0700117 synchronized (mLock) {
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -0700118 // don't bother broadcasting undocked here
119 if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
Jeff Brown008b1762012-08-20 20:15:34 -0700120 updateLocked();
Mike Lockwoodd0e82ce2009-08-27 16:19:07 -0700121 }
122 mSystemReady = true;
Dan Murphyc9f4eaf2009-08-12 15:15:43 -0500123 }
124 }
125
Jeff Brown008b1762012-08-20 20:15:34 -0700126 private void updateLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700127 mWakeLock.acquire();
Jeff Brown008b1762012-08-20 20:15:34 -0700128 mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
129 }
130
131 private void handleDockStateChange() {
132 synchronized (mLock) {
133 Slog.i(TAG, "Dock state changed: " + mDockState);
134
Jeff Brown62c82e42012-09-26 01:30:41 -0700135 // Skip the dock intent if not yet provisioned.
Jeff Brown008b1762012-08-20 20:15:34 -0700136 final ContentResolver cr = mContext.getContentResolver();
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700137 if (Settings.Global.getInt(cr,
138 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
Jeff Brown008b1762012-08-20 20:15:34 -0700139 Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
140 return;
141 }
142
143 // Pack up the values and broadcast them to everyone
144 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
145 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
146 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
147
Jeff Brown62c82e42012-09-26 01:30:41 -0700148 // Play a sound to provide feedback to confirm dock connection.
149 // Particularly useful for flaky contact pins...
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700150 if (Settings.Global.getInt(cr,
151 Settings.Global.DOCK_SOUNDS_ENABLED, 1) == 1) {
Jeff Brown008b1762012-08-20 20:15:34 -0700152 String whichSound = null;
153 if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
154 if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
155 (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
156 (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700157 whichSound = Settings.Global.DESK_UNDOCK_SOUND;
Jeff Brown008b1762012-08-20 20:15:34 -0700158 } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700159 whichSound = Settings.Global.CAR_UNDOCK_SOUND;
Jeff Brown008b1762012-08-20 20:15:34 -0700160 }
161 } else {
162 if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
163 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
164 (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700165 whichSound = Settings.Global.DESK_DOCK_SOUND;
Jeff Brown008b1762012-08-20 20:15:34 -0700166 } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700167 whichSound = Settings.Global.CAR_DOCK_SOUND;
Jeff Brown008b1762012-08-20 20:15:34 -0700168 }
169 }
170
171 if (whichSound != null) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700172 final String soundPath = Settings.Global.getString(cr, whichSound);
Jeff Brown008b1762012-08-20 20:15:34 -0700173 if (soundPath != null) {
174 final Uri soundUri = Uri.parse("file://" + soundPath);
175 if (soundUri != null) {
176 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
177 if (sfx != null) {
178 sfx.setStreamType(AudioManager.STREAM_SYSTEM);
179 sfx.play();
180 }
181 }
182 }
183 }
184 }
185
Jeff Brown62c82e42012-09-26 01:30:41 -0700186 // Send the dock event intent.
187 // There are many components in the system watching for this so as to
188 // adjust audio routing, screen orientation, etc.
189 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
190
191 // Release the wake lock that was acquired when the message was posted.
192 mWakeLock.release();
Jeff Brown008b1762012-08-20 20:15:34 -0700193 }
Dan Murphyc9f4eaf2009-08-12 15:15:43 -0500194 }
195
Jeff Browna2910d02012-08-25 12:29:46 -0700196 private final Handler mHandler = new Handler(true /*async*/) {
Dan Murphyc9f4eaf2009-08-12 15:15:43 -0500197 @Override
198 public void handleMessage(Message msg) {
Bernd Holzheybfca3a02010-02-10 17:39:51 +0100199 switch (msg.what) {
Jeff Brown008b1762012-08-20 20:15:34 -0700200 case MSG_DOCK_STATE_CHANGED:
201 handleDockStateChange();
Bernd Holzheybfca3a02010-02-10 17:39:51 +0100202 break;
203 }
204 }
Tobias Haamel27b28b32010-02-09 23:09:17 +0100205 };
Dan Murphyc9f4eaf2009-08-12 15:15:43 -0500206}