VibratorService.java revision a5281001dcd420e0d14ccb3d4872da0f200bc9b2
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.app.AppOpsManager;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
257f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.database.ContentObserver;
267f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.hardware.input.InputManager;
272d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebingerimport android.media.AudioManager;
2891268cf21eace600792d04db1ac62e9268f48002Dianne Hackbornimport android.os.BatteryStats;
2995e4f70624ae9695bdd9029eb22a9e271401fbd5Joe Onoratoimport android.os.Handler;
303a32213c4029a03fe39486f3d6ebd0ea18928ee1Mike Lockwoodimport android.os.IVibratorService;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.PowerManager;
32eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackbornimport android.os.PowerManagerInternal;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
35a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Lemeimport android.os.ResultReceiver;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
38a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.os.ServiceManager;
39a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Lemeimport android.os.ShellCallback;
40a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Lemeimport android.os.ShellCommand;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
42d49359631bc2642be73dc162a8a73207df1e0bafJeff Brownimport android.os.UserHandle;
437f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.os.Vibrator;
447e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackbornimport android.os.WorkSource;
457f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.provider.Settings;
467f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.provider.Settings.SettingNotFoundException;
478a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
487f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.view.InputDevice;
497b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlockimport android.media.AudioAttributes;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
51a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport com.android.internal.app.IAppOpsService;
52a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport com.android.internal.app.IBatteryStats;
53a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
543a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynskiimport java.io.FileDescriptor;
553a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynskiimport java.io.PrintWriter;
567f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport java.util.ArrayList;
573a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynskiimport java.util.Arrays;
58969579bb9d208c91e081ff96d2fd788269d254bdJeff Brownimport java.util.Iterator;
5918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scottimport java.util.LinkedList;
6018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scottimport java.util.ListIterator;
6118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
627f6c231a76f0bedaf9655a24707737d343244312Jeff Brownpublic class VibratorService extends IVibratorService.Stub
637f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        implements InputManager.InputDeviceListener {
643a32213c4029a03fe39486f3d6ebd0ea18928ee1Mike Lockwood    private static final String TAG = "VibratorService";
6582379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown    private static final boolean DEBUG = false;
6618f18ae078ee97bbdfc9da39d4a19866dceb6a3eJorim Jaggi    private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
67cc9a63dbc2b5569ef65ec3a04d86dbdfdee3f134Mike Lockwood
6818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private final LinkedList<Vibration> mVibrations;
693a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    private final LinkedList<VibrationInfo> mPreviousVibrations;
703a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    private final int mPreviousVibrationsLimit;
7118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private Vibration mCurrentVibration;
727e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn    private final WorkSource mTmpWorkSource = new WorkSource();
737f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final Handler mH = new Handler();
747f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
757f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final Context mContext;
767f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final PowerManager.WakeLock mWakeLock;
77a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private final IAppOpsService mAppOpsService;
78a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private final IBatteryStats mBatteryStatsService;
79eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn    private PowerManagerInternal mPowerManagerInternal;
807f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private InputManager mIm;
817f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
827f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    volatile VibrateThread mThread;
837f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
847f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
857f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    // to be acquired
867f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
877f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
887f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
897f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
90a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private int mCurVibUid = -1;
9113b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi    private boolean mLowPowerMode;
9213b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi    private SettingsObserver mSettingObserver;
93a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
947f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    native static boolean vibratorExists();
95e6904fbdf7976abbadf3e7e658e9416ca49402f9Vincent Becker    native static void vibratorInit();
967f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    native static void vibratorOn(long milliseconds);
977f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    native static void vibratorOff();
9818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
9918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private class Vibration implements IBinder.DeathRecipient {
10018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final IBinder mToken;
10118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final long    mTimeout;
10218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final long    mStartTime;
10318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final long[]  mPattern;
10418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final int     mRepeat;
1057b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock        private final int     mUsageHint;
1067e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn        private final int     mUid;
1078fd7f1ed7c11d35b3f2a97878e68ee38a551dd15Christoph Studer        private final String  mOpPkg;
10818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
1097b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock        Vibration(IBinder token, long millis, int usageHint, int uid, String opPkg) {
1107b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            this(token, millis, null, 0, usageHint, uid, opPkg);
11118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
11218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
1137b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock        Vibration(IBinder token, long[] pattern, int repeat, int usageHint, int uid,
1148fd7f1ed7c11d35b3f2a97878e68ee38a551dd15Christoph Studer                String opPkg) {
1157b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            this(token, 0, pattern, repeat, usageHint, uid, opPkg);
11618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
11718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
11818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private Vibration(IBinder token, long millis, long[] pattern,
1197b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                int repeat, int usageHint, int uid, String opPkg) {
12018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mToken = token;
12118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mTimeout = millis;
12218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mStartTime = SystemClock.uptimeMillis();
12318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mPattern = pattern;
12418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mRepeat = repeat;
1257b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            mUsageHint = usageHint;
1267e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn            mUid = uid;
1278fd7f1ed7c11d35b3f2a97878e68ee38a551dd15Christoph Studer            mOpPkg = opPkg;
12818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
12918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
13018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        public void binderDied() {
13118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
13218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                mVibrations.remove(this);
13318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (this == mCurrentVibration) {
13418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    doCancelVibrateLocked();
13518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
13618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                }
13718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
13818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
13918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
14018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        public boolean hasLongerTimeout(long millis) {
14118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            if (mTimeout == 0) {
14218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // This is a pattern, return false to play the simple
14318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // vibration.
14418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return false;
14518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
14618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            if ((mStartTime + mTimeout)
14718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    < (SystemClock.uptimeMillis() + millis)) {
14818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // If this vibration will end before the time passed in, let
14918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // the new vibration play.
15018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return false;
15118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
15218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return true;
15318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
154969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown
155969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown        public boolean isSystemHapticFeedback() {
15618f18ae078ee97bbdfc9da39d4a19866dceb6a3eJorim Jaggi            return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
15718f18ae078ee97bbdfc9da39d4a19866dceb6a3eJorim Jaggi                    && mRepeat < 0;
158969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown        }
15918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
16018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
1613a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    private static class VibrationInfo {
1623a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        long timeout;
1633a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        long startTime;
1643a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        long[] pattern;
1653a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        int repeat;
1663a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        int usageHint;
1673a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        int uid;
1683a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        String opPkg;
1693a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
1703a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        public VibrationInfo(long timeout, long startTime, long[] pattern, int repeat,
1713a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                int usageHint, int uid, String opPkg) {
1723a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.timeout = timeout;
1733a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.startTime = startTime;
1743a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.pattern = pattern;
1753a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.repeat = repeat;
1763a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.usageHint = usageHint;
1773a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.uid = uid;
1783a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            this.opPkg = opPkg;
1793a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        }
1803a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
1813a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        @Override
1823a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        public String toString() {
1833a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            return new StringBuilder()
1843a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append("timeout: ")
1853a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(timeout)
1863a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(", startTime: ")
1873a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(startTime)
1883a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(", pattern: ")
1893a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(Arrays.toString(pattern))
1903a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(", repeat: ")
1913a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(repeat)
1923a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(", usageHint: ")
1933a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(usageHint)
1943a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(", uid: ")
1953a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(uid)
1963a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(", opPkg: ")
1973a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .append(opPkg)
1983a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    .toString();
1993a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        }
2003a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    }
2013a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
2023a32213c4029a03fe39486f3d6ebd0ea18928ee1Mike Lockwood    VibratorService(Context context) {
203e6904fbdf7976abbadf3e7e658e9416ca49402f9Vincent Becker        vibratorInit();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Reset the hardware to a default state, in case this is a runtime
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // restart instead of a fresh boot.
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        vibratorOff();
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PowerManager pm = (PowerManager)context.getSystemService(
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Context.POWER_SERVICE);
2117e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWakeLock.setReferenceCounted(true);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
214a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
21591268cf21eace600792d04db1ac62e9268f48002Dianne Hackborn        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
21691268cf21eace600792d04db1ac62e9268f48002Dianne Hackborn                BatteryStats.SERVICE_NAME));
217a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
2183a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        mPreviousVibrationsLimit = mContext.getResources().getInteger(
2193a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                com.android.internal.R.integer.config_previousVibrationsDumpLimit);
2203a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
2213a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        mVibrations = new LinkedList<>();
2223a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        mPreviousVibrations = new LinkedList<>();
22318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntentFilter filter = new IntentFilter();
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        filter.addAction(Intent.ACTION_SCREEN_OFF);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        context.registerReceiver(mIntentReceiver, filter);
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2297f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void systemReady() {
2308ce2a538d9b94a0d8e1543c4ee4620a8af525276Yohei Yukawa        mIm = mContext.getSystemService(InputManager.class);
23113b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi        mSettingObserver = new SettingsObserver(mH);
232d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown
233eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
234eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn        mPowerManagerInternal.registerLowPowerModeObserver(
235eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn                new PowerManagerInternal.LowPowerModeListener() {
236eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn            @Override
237eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn            public void onLowPowerModeChanged(boolean enabled) {
238eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn                updateInputDeviceVibrators();
239eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn            }
240eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn        });
241eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn
2427f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        mContext.getContentResolver().registerContentObserver(
24313b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
24413b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi                true, mSettingObserver, UserHandle.USER_ALL);
24513b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi
246d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown        mContext.registerReceiver(new BroadcastReceiver() {
247d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown            @Override
248d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown            public void onReceive(Context context, Intent intent) {
249d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                updateInputDeviceVibrators();
250d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown            }
251d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
252d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown
2538206525b242ceb012d882849c4e355223ba81b9dJeff Brown        updateInputDeviceVibrators();
2547f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
2557f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
25613b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi    private final class SettingsObserver extends ContentObserver {
25713b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi        public SettingsObserver(Handler handler) {
25813b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi            super(handler);
25913b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi        }
26013b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi
26113b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi        @Override
26213b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi        public void onChange(boolean SelfChange) {
26313b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi            updateInputDeviceVibrators();
26413b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi        }
26513b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi    }
26613b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi
26782379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown    @Override // Binder call
268ea9020e0854427d47e566a1394df6749f3265410Dianne Hackborn    public boolean hasVibrator() {
2697f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        return doVibratorExists();
270ea9020e0854427d47e566a1394df6749f3265410Dianne Hackborn    }
2717f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
272f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    private void verifyIncomingUid(int uid) {
273f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        if (uid == Binder.getCallingUid()) {
274f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn            return;
275f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        }
276f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        if (Binder.getCallingPid() == Process.myPid()) {
277f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn            return;
278f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        }
279f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
280f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
281f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    }
282f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn
28382379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown    @Override // Binder call
2847b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock    public void vibrate(int uid, String opPkg, long milliseconds, int usageHint,
2851af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock            IBinder token) {
286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
287105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
288105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            throw new SecurityException("Requires VIBRATE permission");
289105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
290f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        verifyIncomingUid(uid);
29124f1076097588b7db1269044fb55af58bc420e58Patrick Scott        // We're running in the system server so we cannot crash. Check for a
29224f1076097588b7db1269044fb55af58bc420e58Patrick Scott        // timeout of 0 or negative. This will ensure that a vibration has
29324f1076097588b7db1269044fb55af58bc420e58Patrick Scott        // either a timeout of > 0 or a non-null pattern.
29424f1076097588b7db1269044fb55af58bc420e58Patrick Scott        if (milliseconds <= 0 || (mCurrentVibration != null
29524f1076097588b7db1269044fb55af58bc420e58Patrick Scott                && mCurrentVibration.hasLongerTimeout(milliseconds))) {
29618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // Ignore this vibration since the current vibration will play for
29718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // longer than milliseconds.
29818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return;
29918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
3007f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
30182379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown        if (DEBUG) {
30282379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown            Slog.d(TAG, "Vibrating for " + milliseconds + " ms.");
30382379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown        }
30482379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown
3057b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock        Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);
306a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
307a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
308a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        try {
309a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            synchronized (mVibrations) {
310a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                removeVibrationLocked(token);
311a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                doCancelVibrateLocked();
3123a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                addToPreviousVibrationsLocked(vib);
313a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                startVibrationLocked(vib);
314a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
315a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        } finally {
316a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            Binder.restoreCallingIdentity(ident);
31718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isAll0(long[] pattern) {
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int N = pattern.length;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pattern[i] != 0) {
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33082379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown    @Override // Binder call
331f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
3327b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            int usageHint, IBinder token) {
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires VIBRATE permission");
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
337f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        verifyIncomingUid(uid);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // so wakelock calls will succeed
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
34182379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown            if (DEBUG) {
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String s = "";
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int N = pattern.length;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i=0; i<N; i++) {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    s += " " + pattern[i];
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
34782379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown                Slog.d(TAG, "Vibrating with pattern:" + s);
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we're running in the server so we can't fail
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pattern == null || pattern.length == 0
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || isAll0(pattern)
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || repeat >= pattern.length || token == null) {
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3577b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            Vibration vib = new Vibration(token, pattern, repeat, usageHint, uid, packageName);
35818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            try {
35918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                token.linkToDeath(vib, 0);
36018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            } catch (RemoteException e) {
36118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return;
36218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
36518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                removeVibrationLocked(token);
36618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                doCancelVibrateLocked();
36718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (repeat >= 0) {
36818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    mVibrations.addFirst(vib);
36918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
37018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                } else {
37118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // A negative repeat means that this pattern is not meant
37218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // to repeat. Treat it like a simple vibration.
37318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startVibrationLocked(vib);
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3753a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                addToPreviousVibrationsLocked(vib);
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        finally {
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(identity);
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3833a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    private void addToPreviousVibrationsLocked(Vibration vib) {
3843a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
3853a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            mPreviousVibrations.removeFirst();
3863a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        }
3873a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        mPreviousVibrations.addLast(new VibratorService.VibrationInfo(vib.mTimeout, vib.mStartTime,
3883a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                vib.mPattern, vib.mRepeat, vib.mUsageHint, vib.mUid, vib.mOpPkg));
3893a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    }
3903a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
39182379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown    @Override // Binder call
39218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    public void cancelVibrate(IBinder token) {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                android.Manifest.permission.VIBRATE,
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "cancelVibrate");
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // so wakelock calls will succeed
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
40018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
40118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                final Vibration vib = removeVibrationLocked(token);
40218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (vib == mCurrentVibration) {
40382379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown                    if (DEBUG) {
40482379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown                        Slog.d(TAG, "Canceling vibration.");
40582379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown                    }
40618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    doCancelVibrateLocked();
40718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
40818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                }
40918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        finally {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(identity);
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
415f42f15cf450772d8eeb9c0c81a8403d33ffe1c9bEric Olsen
41618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private final Runnable mVibrationRunnable = new Runnable() {
41782379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown        @Override
41818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        public void run() {
41918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
42018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                doCancelVibrateLocked();
42118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                startNextVibrationLocked();
42218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
42318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
42418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    };
42518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
42618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
42718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private void doCancelVibrateLocked() {
42818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (mThread != null) {
42918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mThread) {
43018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                mThread.mDone = true;
43118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                mThread.notify();
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
43318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mThread = null;
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4357f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        doVibratorOff();
43618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        mH.removeCallbacks(mVibrationRunnable);
437a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        reportFinishVibrationLocked();
43818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
43918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
44018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
44118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private void startNextVibrationLocked() {
44218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (mVibrations.size() <= 0) {
443a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            reportFinishVibrationLocked();
444b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            mCurrentVibration = null;
44518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return;
44618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
4474357e528208c301ccf733b074eb9a815997447c9Julia Reynolds        startVibrationLocked(mVibrations.getFirst());
44818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
44918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
45018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
45118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private void startVibrationLocked(final Vibration vib) {
452a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        try {
4537b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            if (mLowPowerMode
45489c3b29a9bfa0ae9858b913bc1ab6604c4613a15Jean-Michel Trivi                    && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
455664703d6be542d6feb64bca9ca5b2a7dbb8abd84Ruchi Kandoi                return;
456664703d6be542d6feb64bca9ca5b2a7dbb8abd84Ruchi Kandoi            }
45713b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi
4582d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger            if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
4592d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger                    !shouldVibrateForRingtone()) {
460d28967f489996d1d74ff5c0bbb9c19d158efbf37Julia Reynolds                return;
461d28967f489996d1d74ff5c0bbb9c19d158efbf37Julia Reynolds            }
462d28967f489996d1d74ff5c0bbb9c19d158efbf37Julia Reynolds
4631af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock            int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
4647b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                    vib.mUsageHint, vib.mUid, vib.mOpPkg);
4651af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock            if (mode == AppOpsManager.MODE_ALLOWED) {
4661af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock                mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
4678fd7f1ed7c11d35b3f2a97878e68ee38a551dd15Christoph Studer                    AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
4681af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock            }
4694357e528208c301ccf733b074eb9a815997447c9Julia Reynolds            if (mode == AppOpsManager.MODE_ALLOWED) {
4704357e528208c301ccf733b074eb9a815997447c9Julia Reynolds                mCurrentVibration = vib;
4714357e528208c301ccf733b074eb9a815997447c9Julia Reynolds            } else {
472a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                if (mode == AppOpsManager.MODE_ERRORED) {
473a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
474a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
475a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mH.post(mVibrationRunnable);
476a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                return;
477a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
478a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        } catch (RemoteException e) {
479a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
48018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (vib.mTimeout != 0) {
4817b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            doVibratorOn(vib.mTimeout, vib.mUid, vib.mUsageHint);
48218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mH.postDelayed(mVibrationRunnable, vib.mTimeout);
48318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        } else {
48418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // mThread better be null here. doCancelVibrate should always be
48518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // called before startNextVibrationLocked or startVibrationLocked.
48618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mThread = new VibrateThread(vib);
48718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mThread.start();
48818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
48918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
49018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
4912d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger    private boolean shouldVibrateForRingtone() {
4922d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
493dcbdc0df43310d9ecb2324be8c5bd54d7727230eBrad Ebinger        int ringerMode = audioManager.getRingerModeInternal();
4942d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger        // "Also vibrate for calls" Setting in Sound
4952d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger        if (Settings.System.getInt(
4962d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger                mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
4972d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger            return ringerMode != AudioManager.RINGER_MODE_SILENT;
4982d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger        } else {
4992d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger            return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
5002d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger        }
5012d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger    }
5022d1c3b3a6cffd0a573aab5ac19f89a70d334540dBrad Ebinger
503a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private void reportFinishVibrationLocked() {
504a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (mCurrentVibration != null) {
505a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            try {
506e98f5dbe6b6f9f2cb6a73ee750faacda2596b34fDianne Hackborn                mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
507e98f5dbe6b6f9f2cb6a73ee750faacda2596b34fDianne Hackborn                        AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
5088fd7f1ed7c11d35b3f2a97878e68ee38a551dd15Christoph Studer                        mCurrentVibration.mOpPkg);
509a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            } catch (RemoteException e) {
510a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
511a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            mCurrentVibration = null;
512a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
513a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
514a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
51518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
51618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private Vibration removeVibrationLocked(IBinder token) {
51718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        ListIterator<Vibration> iter = mVibrations.listIterator(0);
51818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        while (iter.hasNext()) {
51918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            Vibration vib = iter.next();
52018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            if (vib.mToken == token) {
52118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                iter.remove();
522b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson                unlinkVibration(vib);
52318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return vib;
52418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
52518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
52618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        // We might be looking for a simple vibration which is only stored in
52718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        // mCurrentVibration.
52818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
529b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            unlinkVibration(mCurrentVibration);
53018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return mCurrentVibration;
53118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
53218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        return null;
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
535b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson    private void unlinkVibration(Vibration vib) {
536b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson        if (vib.mPattern != null) {
537b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            // If Vibration object has a pattern,
538b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            // the Vibration object has also been linkedToDeath.
539b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            vib.mToken.unlinkToDeath(vib, 0);
540b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson        }
541b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson    }
542b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson
5437f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private void updateInputDeviceVibrators() {
5447f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        synchronized (mVibrations) {
5457f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            doCancelVibrateLocked();
5467f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
5477f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            synchronized (mInputDeviceVibrators) {
5488206525b242ceb012d882849c4e355223ba81b9dJeff Brown                mVibrateInputDevicesSetting = false;
5498206525b242ceb012d882849c4e355223ba81b9dJeff Brown                try {
550d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                    mVibrateInputDevicesSetting = Settings.System.getIntForUser(
551d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                            mContext.getContentResolver(),
552d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                            Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
5538206525b242ceb012d882849c4e355223ba81b9dJeff Brown                } catch (SettingNotFoundException snfe) {
5548206525b242ceb012d882849c4e355223ba81b9dJeff Brown                }
5558206525b242ceb012d882849c4e355223ba81b9dJeff Brown
556eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3aDianne Hackborn                mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
55713b03aff2993653ef8bde8bedb1bbcc0fe09ba94Ruchi Kandoi
5588206525b242ceb012d882849c4e355223ba81b9dJeff Brown                if (mVibrateInputDevicesSetting) {
5598206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    if (!mInputDeviceListenerRegistered) {
5608206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mInputDeviceListenerRegistered = true;
5618206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mIm.registerInputDeviceListener(this, mH);
5628206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    }
5638206525b242ceb012d882849c4e355223ba81b9dJeff Brown                } else {
5648206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    if (mInputDeviceListenerRegistered) {
5658206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mInputDeviceListenerRegistered = false;
5668206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mIm.unregisterInputDeviceListener(this);
5678206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    }
5688206525b242ceb012d882849c4e355223ba81b9dJeff Brown                }
5698206525b242ceb012d882849c4e355223ba81b9dJeff Brown
5707f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                mInputDeviceVibrators.clear();
5717f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                if (mVibrateInputDevicesSetting) {
5727f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    int[] ids = mIm.getInputDeviceIds();
5737f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    for (int i = 0; i < ids.length; i++) {
5747f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        InputDevice device = mIm.getInputDevice(ids[i]);
5757f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        Vibrator vibrator = device.getVibrator();
5767f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        if (vibrator.hasVibrator()) {
5777f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                            mInputDeviceVibrators.add(vibrator);
5787f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        }
5797f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    }
5807f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                }
5817f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            }
5827f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
5837f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            startNextVibrationLocked();
5847f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        }
5857f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
5867f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
5877f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    @Override
5887f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void onInputDeviceAdded(int deviceId) {
5897f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        updateInputDeviceVibrators();
5907f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
5917f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
5927f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    @Override
5937f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void onInputDeviceChanged(int deviceId) {
5947f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        updateInputDeviceVibrators();
5957f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
5967f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
5977f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    @Override
5987f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void onInputDeviceRemoved(int deviceId) {
5997f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        updateInputDeviceVibrators();
6007f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
6017f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
6027f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private boolean doVibratorExists() {
6031064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // For now, we choose to ignore the presence of input devices that have vibrators
6041064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // when reporting whether the device has a vibrator.  Applications often use this
6051064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // information to decide whether to enable certain features so they expect the
6061064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // result of hasVibrator() to be constant.  For now, just report whether
6071064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // the device has a built-in vibrator.
6081064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        //synchronized (mInputDeviceVibrators) {
6091064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
6101064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        //}
611c2293025a25e04b26bf53713d71f85fd9ca5e8e9Dianne Hackborn        return vibratorExists();
6127f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
6137f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
6147b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock    private void doVibratorOn(long millis, int uid, int usageHint) {
6157f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        synchronized (mInputDeviceVibrators) {
61682379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown            if (DEBUG) {
61782379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown                Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
61882379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown            }
619a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            try {
620a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mBatteryStatsService.noteVibratorOn(uid, millis);
621a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mCurVibUid = uid;
622a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            } catch (RemoteException e) {
623a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
6247f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            final int vibratorCount = mInputDeviceVibrators.size();
6257f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            if (vibratorCount != 0) {
6267b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
6277b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                        .build();
6287f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                for (int i = 0; i < vibratorCount; i++) {
6297b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                    mInputDeviceVibrators.get(i).vibrate(millis, attributes);
6307f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                }
6317f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            } else {
6327f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                vibratorOn(millis);
6337f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            }
6347f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        }
6357f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
6367f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
6377f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private void doVibratorOff() {
6387f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        synchronized (mInputDeviceVibrators) {
63982379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown            if (DEBUG) {
64082379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown                Slog.d(TAG, "Turning vibrator off.");
64182379ba8ddc04116a40aa177df4ef6c2aa428a69Jeff Brown            }
642a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (mCurVibUid >= 0) {
643a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                try {
644a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    mBatteryStatsService.noteVibratorOff(mCurVibUid);
645a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                } catch (RemoteException e) {
646a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
647a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mCurVibUid = -1;
648a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
6497f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            final int vibratorCount = mInputDeviceVibrators.size();
6507f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            if (vibratorCount != 0) {
6517f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                for (int i = 0; i < vibratorCount; i++) {
6527f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    mInputDeviceVibrators.get(i).cancel();
6537f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                }
6547f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            } else {
6557f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                vibratorOff();
6567f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            }
6577f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        }
6587f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
6597f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class VibrateThread extends Thread {
66118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        final Vibration mVibration;
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean mDone;
663f42f15cf450772d8eeb9c0c81a8403d33ffe1c9bEric Olsen
66418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        VibrateThread(Vibration vib) {
66518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mVibration = vib;
6667e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn            mTmpWorkSource.set(vib.mUid);
6677e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn            mWakeLock.setWorkSource(mTmpWorkSource);
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mWakeLock.acquire();
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void delay(long duration) {
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (duration > 0) {
673e4c56d9367ae89c705b92e44f327bd1d0132129cVairavan Srinivasan                long bedtime = duration + SystemClock.uptimeMillis();
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                do {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        this.wait(duration);
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    catch (InterruptedException e) {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mDone) {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
683e4c56d9367ae89c705b92e44f327bd1d0132129cVairavan Srinivasan                    duration = bedtime - SystemClock.uptimeMillis();
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } while (duration > 0);
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (this) {
691a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final long[] pattern = mVibration.mPattern;
692a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final int len = pattern.length;
693a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final int repeat = mVibration.mRepeat;
694a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final int uid = mVibration.mUid;
6957b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                final int usageHint = mVibration.mUsageHint;
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int index = 0;
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long duration = 0;
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (!mDone) {
700f42f15cf450772d8eeb9c0c81a8403d33ffe1c9bEric Olsen                    // add off-time duration to any accumulated on-time duration
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (index < len) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        duration += pattern[index++];
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // sleep until it is time to start the vibrator
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delay(duration);
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mDone) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (index < len) {
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // read on-time duration and start the vibrator
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // duration is saved for delay() at top of loop
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        duration = pattern[index++];
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (duration > 0) {
7167b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock                            VibratorService.this.doVibratorOn(duration, uid, usageHint);
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
71918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                        if (repeat < 0) {
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
72218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                            index = repeat;
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            duration = 0;
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mWakeLock.release();
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
72918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mThread == this) {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mThread = null;
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
73318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (!mDone) {
73418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // If this vibration finished naturally, start the next
73518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // vibration.
736b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson                    unlinkVibration(mVibration);
73718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
741969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown    }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
744969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown        @Override
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
74718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                synchronized (mVibrations) {
748969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    // When the system is entering a non-interactive state, we want
749969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    // to cancel vibrations in case a misbehaving app has abandoned
750969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    // them.  However it may happen that the system is currently playing
751969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    // haptic feedback as part of the transition.  So we don't cancel
752969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    // system vibrations.
753969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    if (mCurrentVibration != null
754969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                            && !mCurrentVibration.isSystemHapticFeedback()) {
755969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                        doCancelVibrateLocked();
7568a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan                    }
7578a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan
758969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    // Clear all remaining vibrations.
759969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    Iterator<Vibration> it = mVibrations.iterator();
760969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    while (it.hasNext()) {
761969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                        Vibration vibration = it.next();
762969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                        if (vibration != mCurrentVibration) {
763969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                            unlinkVibration(vibration);
764969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                            it.remove();
765969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                        }
766969579bb9d208c91e081ff96d2fd788269d254bdJeff Brown                    }
76718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                }
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
7713a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
7723a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    @Override
7733a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
7743a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
7753a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                != PackageManager.PERMISSION_GRANTED) {
7763a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski
7773a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            pw.println("Permission Denial: can't dump vibrator service from from pid="
7783a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    + Binder.getCallingPid()
7793a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                    + ", uid=" + Binder.getCallingUid());
7803a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            return;
7813a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        }
7823a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        pw.println("Previous vibrations:");
7833a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        synchronized (mVibrations) {
7843a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            for (VibrationInfo info : mPreviousVibrations) {
7853a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                pw.print("  ");
7863a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski                pw.println(info.toString());
7873a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski            }
7883a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski        }
7893a8eb0f670cc331b9e16fdedfab8b89ed9254317Filip Gruszczynski    }
790a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
791a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme    @Override
792a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
793a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
794a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            throws RemoteException {
795a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
796a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme    }
797a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
798a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme    private final class VibratorShellCommand extends ShellCommand {
799a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
800a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        private static final long MAX_VIBRATION_MS = 200;
801a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
802a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        private final IBinder mToken;
803a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
804a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        private VibratorShellCommand(IBinder token) {
805a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            mToken = token;
806a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        }
807a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
808a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        @Override
809a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        public int onCommand(String cmd) {
810a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            if ("vibrate".equals(cmd)) {
811a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                return runVibrate();
812a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            }
813a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            return handleDefaultCommands(cmd);
814a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        }
815a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
816a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        private int runVibrate() {
817a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            final long duration = Long.parseLong(getNextArgRequired());
818a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            if (duration > MAX_VIBRATION_MS) {
819a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
820a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            }
821a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            String description = getNextArg();
822a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            if (description == null) {
823a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                description = "Shell command";
824a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            }
825a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            vibrate(Binder.getCallingUid(), description, duration, AudioAttributes.USAGE_UNKNOWN,
826a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                    mToken);
827a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            return 0;
828a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        }
829a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
830a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        @Override
831a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        public void onHelp() {
832a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            try (PrintWriter pw = getOutPrintWriter();) {
833a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("Vibrator commands:");
834a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("  help");
835a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("    Prints this help text.");
836a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("");
837a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("  vibrate duration [description]");
838a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("    Vibrates for duration milliseconds.");
839a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme                pw.println("");
840a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme            }
841a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme        }
842a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme    }
843a5281001dcd420e0d14ccb3d4872da0f200bc9b2Felipe Leme
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
845