PageRenderTime 21ms CodeModel.GetById 9ms app.highlight 8ms RepoModel.GetById 2ms app.codeStats 0ms

/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
 17package com.android.server;
 18
 19import android.content.ContentResolver;
 20import android.content.Context;
 21import android.content.Intent;
 22import android.media.AudioManager;
 23import android.media.Ringtone;
 24import android.media.RingtoneManager;
 25import android.net.Uri;
 26import android.os.Handler;
 27import android.os.Message;
 28import android.os.PowerManager;
 29import android.os.SystemClock;
 30import android.os.UEventObserver;
 31import android.os.UserHandle;
 32import android.provider.Settings;
 33import android.util.Log;
 34import android.util.Slog;
 35
 36import java.io.FileNotFoundException;
 37import java.io.FileReader;
 38
 39/**
 40 * <p>DockObserver monitors for a docking station.
 41 */
 42final class DockObserver extends UEventObserver {
 43    private static final String TAG = DockObserver.class.getSimpleName();
 44
 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
 48    private static final int MSG_DOCK_STATE_CHANGED = 0;
 49
 50    private final Object mLock = new Object();
 51
 52    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 53    private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 54
 55    private boolean mSystemReady;
 56
 57    private final Context mContext;
 58    private final PowerManager mPowerManager;
 59    private final PowerManager.WakeLock mWakeLock;
 60
 61    public DockObserver(Context context) {
 62        mContext = context;
 63
 64        mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
 65        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 66
 67        init();  // set initial status
 68        startObserving(DOCK_UEVENT_MATCH);
 69    }
 70
 71    @Override
 72    public void onUEvent(UEventObserver.UEvent event) {
 73        if (Log.isLoggable(TAG, Log.VERBOSE)) {
 74            Slog.v(TAG, "Dock UEVENT: " + event.toString());
 75        }
 76
 77        synchronized (mLock) {
 78            try {
 79                int newState = Integer.parseInt(event.get("SWITCH_STATE"));
 80                if (newState != mDockState) {
 81                    mPreviousDockState = mDockState;
 82                    mDockState = newState;
 83                    if (mSystemReady) {
 84                        // Wake up immediately when docked or undocked.
 85                        mPowerManager.wakeUp(SystemClock.uptimeMillis());
 86
 87                        updateLocked();
 88                    }
 89                }
 90            } catch (NumberFormatException e) {
 91                Slog.e(TAG, "Could not parse switch state from event " + event);
 92            }
 93        }
 94    }
 95
 96    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            }
113        }
114    }
115
116    void systemReady() {
117        synchronized (mLock) {
118            // don't bother broadcasting undocked here
119            if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
120                updateLocked();
121            }
122            mSystemReady = true;
123        }
124    }
125
126    private void updateLocked() {
127        mWakeLock.acquire();
128        mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
129    }
130
131    private void handleDockStateChange() {
132        synchronized (mLock) {
133            Slog.i(TAG, "Dock state changed: " + mDockState);
134
135            // Skip the dock intent if not yet provisioned.
136            final ContentResolver cr = mContext.getContentResolver();
137            if (Settings.Global.getInt(cr,
138                    Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
139                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
148            // Play a sound to provide feedback to confirm dock connection.
149            // Particularly useful for flaky contact pins...
150            if (Settings.Global.getInt(cr,
151                    Settings.Global.DOCK_SOUNDS_ENABLED, 1) == 1) {
152                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)) {
157                        whichSound = Settings.Global.DESK_UNDOCK_SOUND;
158                    } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
159                        whichSound = Settings.Global.CAR_UNDOCK_SOUND;
160                    }
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)) {
165                        whichSound = Settings.Global.DESK_DOCK_SOUND;
166                    } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
167                        whichSound = Settings.Global.CAR_DOCK_SOUND;
168                    }
169                }
170
171                if (whichSound != null) {
172                    final String soundPath = Settings.Global.getString(cr, whichSound);
173                    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
186            // 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();
193        }
194    }
195
196    private final Handler mHandler = new Handler(true /*async*/) {
197        @Override
198        public void handleMessage(Message msg) {
199            switch (msg.what) {
200                case MSG_DOCK_STATE_CHANGED:
201                    handleDockStateChange();
202                    break;
203            }
204        }
205    };
206}