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;
2795e4f70624ae9695bdd9029eb22a9e271401fbd5Joe Onoratoimport android.os.Handler;
283a32213c4029a03fe39486f3d6ebd0ea18928ee1Mike Lockwoodimport android.os.IVibratorService;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.PowerManager;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
34a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.os.ServiceManager;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
36d49359631bc2642be73dc162a8a73207df1e0bafJeff Brownimport android.os.UserHandle;
377f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.os.Vibrator;
387e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackbornimport android.os.WorkSource;
397f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.provider.Settings;
407f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.provider.Settings.SettingNotFoundException;
418a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
427f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport android.view.InputDevice;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
44a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport com.android.internal.app.IAppOpsService;
45a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport com.android.internal.app.IBatteryStats;
46a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
477f6c231a76f0bedaf9655a24707737d343244312Jeff Brownimport java.util.ArrayList;
4818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scottimport java.util.LinkedList;
4918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scottimport java.util.ListIterator;
5018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
517f6c231a76f0bedaf9655a24707737d343244312Jeff Brownpublic class VibratorService extends IVibratorService.Stub
527f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        implements InputManager.InputDeviceListener {
533a32213c4029a03fe39486f3d6ebd0ea18928ee1Mike Lockwood    private static final String TAG = "VibratorService";
54cc9a63dbc2b5569ef65ec3a04d86dbdfdee3f134Mike Lockwood
5518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private final LinkedList<Vibration> mVibrations;
5618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private Vibration mCurrentVibration;
577e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn    private final WorkSource mTmpWorkSource = new WorkSource();
587f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final Handler mH = new Handler();
597f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
607f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final Context mContext;
617f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final PowerManager.WakeLock mWakeLock;
62a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private final IAppOpsService mAppOpsService;
63a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private final IBatteryStats mBatteryStatsService;
647f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private InputManager mIm;
657f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
667f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    volatile VibrateThread mThread;
677f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
687f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
697f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    // to be acquired
707f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
717f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
727f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
737f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
74a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private int mCurVibUid = -1;
75a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
767f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    native static boolean vibratorExists();
777f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    native static void vibratorOn(long milliseconds);
787f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    native static void vibratorOff();
7918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
8018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private class Vibration implements IBinder.DeathRecipient {
8118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final IBinder mToken;
8218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final long    mTimeout;
8318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final long    mStartTime;
8418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final long[]  mPattern;
8518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private final int     mRepeat;
867e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn        private final int     mUid;
87a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        private final String  mPackageName;
8818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
89a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Vibration(IBinder token, long millis, int uid, String packageName) {
90a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            this(token, millis, null, 0, uid, packageName);
9118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
9218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
93a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Vibration(IBinder token, long[] pattern, int repeat, int uid, String packageName) {
94a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            this(token, 0, pattern, repeat, uid, packageName);
9518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
9618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
9718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        private Vibration(IBinder token, long millis, long[] pattern,
98a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                int repeat, int uid, String packageName) {
9918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mToken = token;
10018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mTimeout = millis;
10118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mStartTime = SystemClock.uptimeMillis();
10218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mPattern = pattern;
10318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mRepeat = repeat;
1047e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn            mUid = uid;
105a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            mPackageName = packageName;
10618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
10718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
10818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        public void binderDied() {
10918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
11018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                mVibrations.remove(this);
11118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (this == mCurrentVibration) {
11218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    doCancelVibrateLocked();
11318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
11418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                }
11518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
11618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
11718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
11818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        public boolean hasLongerTimeout(long millis) {
11918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            if (mTimeout == 0) {
12018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // This is a pattern, return false to play the simple
12118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // vibration.
12218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return false;
12318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
12418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            if ((mStartTime + mTimeout)
12518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    < (SystemClock.uptimeMillis() + millis)) {
12618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // If this vibration will end before the time passed in, let
12718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                // the new vibration play.
12818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return false;
12918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
13018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return true;
13118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
13218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
13318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
1343a32213c4029a03fe39486f3d6ebd0ea18928ee1Mike Lockwood    VibratorService(Context context) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Reset the hardware to a default state, in case this is a runtime
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // restart instead of a fresh boot.
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        vibratorOff();
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PowerManager pm = (PowerManager)context.getSystemService(
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Context.POWER_SERVICE);
1427e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWakeLock.setReferenceCounted(true);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
145a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
146a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
147a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
14818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        mVibrations = new LinkedList<Vibration>();
14918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntentFilter filter = new IntentFilter();
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        filter.addAction(Intent.ACTION_SCREEN_OFF);
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        context.registerReceiver(mIntentReceiver, filter);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1557f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void systemReady() {
1567f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
157d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown
1587f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        mContext.getContentResolver().registerContentObserver(
1597f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
1607f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                new ContentObserver(mH) {
1617f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    @Override
1627f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    public void onChange(boolean selfChange) {
1638206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        updateInputDeviceVibrators();
1647f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    }
165d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                }, UserHandle.USER_ALL);
166d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown
167d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown        mContext.registerReceiver(new BroadcastReceiver() {
168d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown            @Override
169d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown            public void onReceive(Context context, Intent intent) {
170d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                updateInputDeviceVibrators();
171d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown            }
172d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
173d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown
1748206525b242ceb012d882849c4e355223ba81b9dJeff Brown        updateInputDeviceVibrators();
1757f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
1767f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
177ea9020e0854427d47e566a1394df6749f3265410Dianne Hackborn    public boolean hasVibrator() {
1787f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        return doVibratorExists();
179ea9020e0854427d47e566a1394df6749f3265410Dianne Hackborn    }
1807f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
181f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    private void verifyIncomingUid(int uid) {
182f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        if (uid == Binder.getCallingUid()) {
183f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn            return;
184f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        }
185f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        if (Binder.getCallingPid() == Process.myPid()) {
186f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn            return;
187f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        }
188f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
189f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
190f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    }
191f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn
192f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    public void vibrate(int uid, String packageName, long milliseconds, IBinder token) {
193105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
194105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
195105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            throw new SecurityException("Requires VIBRATE permission");
196105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
197f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        verifyIncomingUid(uid);
19824f1076097588b7db1269044fb55af58bc420e58Patrick Scott        // We're running in the system server so we cannot crash. Check for a
19924f1076097588b7db1269044fb55af58bc420e58Patrick Scott        // timeout of 0 or negative. This will ensure that a vibration has
20024f1076097588b7db1269044fb55af58bc420e58Patrick Scott        // either a timeout of > 0 or a non-null pattern.
20124f1076097588b7db1269044fb55af58bc420e58Patrick Scott        if (milliseconds <= 0 || (mCurrentVibration != null
20224f1076097588b7db1269044fb55af58bc420e58Patrick Scott                && mCurrentVibration.hasLongerTimeout(milliseconds))) {
20318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // Ignore this vibration since the current vibration will play for
20418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // longer than milliseconds.
20518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return;
20618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
2077f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
208a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Vibration vib = new Vibration(token, milliseconds, uid, packageName);
209a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
210a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
211a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        try {
212a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            synchronized (mVibrations) {
213a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                removeVibrationLocked(token);
214a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                doCancelVibrateLocked();
215a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mCurrentVibration = vib;
216a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                startVibrationLocked(vib);
217a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
218a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        } finally {
219a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            Binder.restoreCallingIdentity(ident);
22018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isAll0(long[] pattern) {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int N = pattern.length;
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pattern[i] != 0) {
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
233f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn    public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
234f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn            IBinder token) {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires VIBRATE permission");
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
239f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn        verifyIncomingUid(uid);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // so wakelock calls will succeed
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (false) {
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String s = "";
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int N = pattern.length;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i=0; i<N; i++) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    s += " " + pattern[i];
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2498a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.i(TAG, "vibrating with pattern: " + s);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we're running in the server so we can't fail
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pattern == null || pattern.length == 0
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || isAll0(pattern)
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || repeat >= pattern.length || token == null) {
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            Vibration vib = new Vibration(token, pattern, repeat, uid, packageName);
26018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            try {
26118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                token.linkToDeath(vib, 0);
26218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            } catch (RemoteException e) {
26318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return;
26418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
26718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                removeVibrationLocked(token);
26818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                doCancelVibrateLocked();
26918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (repeat >= 0) {
27018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    mVibrations.addFirst(vib);
27118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
27218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                } else {
27318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // A negative repeat means that this pattern is not meant
27418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // to repeat. Treat it like a simple vibration.
27518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    mCurrentVibration = vib;
27618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startVibrationLocked(vib);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        finally {
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(identity);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    public void cancelVibrate(IBinder token) {
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                android.Manifest.permission.VIBRATE,
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "cancelVibrate");
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // so wakelock calls will succeed
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
29318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
29418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                final Vibration vib = removeVibrationLocked(token);
29518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (vib == mCurrentVibration) {
29618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    doCancelVibrateLocked();
29718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
29818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                }
29918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        finally {
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(identity);
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
305f42f15cf450772d8eeb9c0c81a8403d33ffe1c9bEric Olsen
30618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private final Runnable mVibrationRunnable = new Runnable() {
30718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        public void run() {
30818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
30918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                doCancelVibrateLocked();
31018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                startNextVibrationLocked();
31118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
31218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
31318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    };
31418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
31518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
31618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private void doCancelVibrateLocked() {
31718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (mThread != null) {
31818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mThread) {
31918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                mThread.mDone = true;
32018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                mThread.notify();
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mThread = null;
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3247f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        doVibratorOff();
32518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        mH.removeCallbacks(mVibrationRunnable);
326a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        reportFinishVibrationLocked();
32718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
32818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
32918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
33018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private void startNextVibrationLocked() {
33118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (mVibrations.size() <= 0) {
332a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            reportFinishVibrationLocked();
333b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            mCurrentVibration = null;
33418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return;
33518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
33618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        mCurrentVibration = mVibrations.getFirst();
33718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        startVibrationLocked(mCurrentVibration);
33818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
33918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
34018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
34118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private void startVibrationLocked(final Vibration vib) {
342a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        try {
343a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            int mode = mAppOpsService.startOperation(AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName);
344a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (mode != AppOpsManager.MODE_ALLOWED) {
345a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                if (mode == AppOpsManager.MODE_ERRORED) {
346a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
347a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
348a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mH.post(mVibrationRunnable);
349a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                return;
350a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
351a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        } catch (RemoteException e) {
352a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
35318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (vib.mTimeout != 0) {
354a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            doVibratorOn(vib.mTimeout, vib.mUid);
35518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mH.postDelayed(mVibrationRunnable, vib.mTimeout);
35618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        } else {
35718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // mThread better be null here. doCancelVibrate should always be
35818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            // called before startNextVibrationLocked or startVibrationLocked.
35918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mThread = new VibrateThread(vib);
36018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mThread.start();
36118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
36218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    }
36318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott
364a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private void reportFinishVibrationLocked() {
365a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (mCurrentVibration != null) {
366a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            try {
367a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mAppOpsService.finishOperation(AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
368a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        mCurrentVibration.mPackageName);
369a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            } catch (RemoteException e) {
370a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
371a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            mCurrentVibration = null;
372a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
373a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
374a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
37518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    // Lock held on mVibrations
37618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    private Vibration removeVibrationLocked(IBinder token) {
37718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        ListIterator<Vibration> iter = mVibrations.listIterator(0);
37818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        while (iter.hasNext()) {
37918dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            Vibration vib = iter.next();
38018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            if (vib.mToken == token) {
38118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                iter.remove();
382b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson                unlinkVibration(vib);
38318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                return vib;
38418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            }
38518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
38618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        // We might be looking for a simple vibration which is only stored in
38718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        // mCurrentVibration.
38818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
389b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            unlinkVibration(mCurrentVibration);
39018dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            return mCurrentVibration;
39118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        }
39218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        return null;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
395b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson    private void unlinkVibration(Vibration vib) {
396b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson        if (vib.mPattern != null) {
397b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            // If Vibration object has a pattern,
398b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            // the Vibration object has also been linkedToDeath.
399b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson            vib.mToken.unlinkToDeath(vib, 0);
400b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson        }
401b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson    }
402b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson
4037f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private void updateInputDeviceVibrators() {
4047f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        synchronized (mVibrations) {
4057f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            doCancelVibrateLocked();
4067f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4077f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            synchronized (mInputDeviceVibrators) {
4088206525b242ceb012d882849c4e355223ba81b9dJeff Brown                mVibrateInputDevicesSetting = false;
4098206525b242ceb012d882849c4e355223ba81b9dJeff Brown                try {
410d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                    mVibrateInputDevicesSetting = Settings.System.getIntForUser(
411d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                            mContext.getContentResolver(),
412d49359631bc2642be73dc162a8a73207df1e0bafJeff Brown                            Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
4138206525b242ceb012d882849c4e355223ba81b9dJeff Brown                } catch (SettingNotFoundException snfe) {
4148206525b242ceb012d882849c4e355223ba81b9dJeff Brown                }
4158206525b242ceb012d882849c4e355223ba81b9dJeff Brown
4168206525b242ceb012d882849c4e355223ba81b9dJeff Brown                if (mVibrateInputDevicesSetting) {
4178206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    if (!mInputDeviceListenerRegistered) {
4188206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mInputDeviceListenerRegistered = true;
4198206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mIm.registerInputDeviceListener(this, mH);
4208206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    }
4218206525b242ceb012d882849c4e355223ba81b9dJeff Brown                } else {
4228206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    if (mInputDeviceListenerRegistered) {
4238206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mInputDeviceListenerRegistered = false;
4248206525b242ceb012d882849c4e355223ba81b9dJeff Brown                        mIm.unregisterInputDeviceListener(this);
4258206525b242ceb012d882849c4e355223ba81b9dJeff Brown                    }
4268206525b242ceb012d882849c4e355223ba81b9dJeff Brown                }
4278206525b242ceb012d882849c4e355223ba81b9dJeff Brown
4287f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                mInputDeviceVibrators.clear();
4297f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                if (mVibrateInputDevicesSetting) {
4307f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    int[] ids = mIm.getInputDeviceIds();
4317f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    for (int i = 0; i < ids.length; i++) {
4327f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        InputDevice device = mIm.getInputDevice(ids[i]);
4337f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        Vibrator vibrator = device.getVibrator();
4347f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        if (vibrator.hasVibrator()) {
4357f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                            mInputDeviceVibrators.add(vibrator);
4367f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                        }
4377f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    }
4387f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                }
4397f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            }
4407f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4417f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            startNextVibrationLocked();
4427f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        }
4437f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
4447f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4457f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    @Override
4467f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void onInputDeviceAdded(int deviceId) {
4477f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        updateInputDeviceVibrators();
4487f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
4497f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4507f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    @Override
4517f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void onInputDeviceChanged(int deviceId) {
4527f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        updateInputDeviceVibrators();
4537f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
4547f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4557f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    @Override
4567f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    public void onInputDeviceRemoved(int deviceId) {
4577f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        updateInputDeviceVibrators();
4587f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
4597f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4607f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private boolean doVibratorExists() {
4611064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // For now, we choose to ignore the presence of input devices that have vibrators
4621064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // when reporting whether the device has a vibrator.  Applications often use this
4631064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // information to decide whether to enable certain features so they expect the
4641064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // result of hasVibrator() to be constant.  For now, just report whether
4651064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        // the device has a built-in vibrator.
4661064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        //synchronized (mInputDeviceVibrators) {
4671064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
4681064a50dc86c2aea54bc6830c6cae464feb27febJeff Brown        //}
469c2293025a25e04b26bf53713d71f85fd9ca5e8e9Dianne Hackborn        return vibratorExists();
4707f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
4717f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
472a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private void doVibratorOn(long millis, int uid) {
4737f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        synchronized (mInputDeviceVibrators) {
474a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            try {
475a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mBatteryStatsService.noteVibratorOn(uid, millis);
476a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mCurVibUid = uid;
477a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            } catch (RemoteException e) {
478a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
4797f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            final int vibratorCount = mInputDeviceVibrators.size();
4807f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            if (vibratorCount != 0) {
4817f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                for (int i = 0; i < vibratorCount; i++) {
4827f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    mInputDeviceVibrators.get(i).vibrate(millis);
4837f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                }
4847f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            } else {
4857f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                vibratorOn(millis);
4867f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            }
4877f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        }
4887f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
4897f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
4907f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    private void doVibratorOff() {
4917f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        synchronized (mInputDeviceVibrators) {
492a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (mCurVibUid >= 0) {
493a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                try {
494a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    mBatteryStatsService.noteVibratorOff(mCurVibUid);
495a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                } catch (RemoteException e) {
496a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
497a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                mCurVibUid = -1;
498a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
4997f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            final int vibratorCount = mInputDeviceVibrators.size();
5007f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            if (vibratorCount != 0) {
5017f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                for (int i = 0; i < vibratorCount; i++) {
5027f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                    mInputDeviceVibrators.get(i).cancel();
5037f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                }
5047f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            } else {
5057f6c231a76f0bedaf9655a24707737d343244312Jeff Brown                vibratorOff();
5067f6c231a76f0bedaf9655a24707737d343244312Jeff Brown            }
5077f6c231a76f0bedaf9655a24707737d343244312Jeff Brown        }
5087f6c231a76f0bedaf9655a24707737d343244312Jeff Brown    }
5097f6c231a76f0bedaf9655a24707737d343244312Jeff Brown
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class VibrateThread extends Thread {
51118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        final Vibration mVibration;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean mDone;
513f42f15cf450772d8eeb9c0c81a8403d33ffe1c9bEric Olsen
51418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott        VibrateThread(Vibration vib) {
51518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            mVibration = vib;
5167e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn            mTmpWorkSource.set(vib.mUid);
5177e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn            mWakeLock.setWorkSource(mTmpWorkSource);
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mWakeLock.acquire();
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void delay(long duration) {
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (duration > 0) {
523e4c56d9367ae89c705b92e44f327bd1d0132129cVairavan Srinivasan                long bedtime = duration + SystemClock.uptimeMillis();
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                do {
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        this.wait(duration);
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    catch (InterruptedException e) {
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mDone) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
533e4c56d9367ae89c705b92e44f327bd1d0132129cVairavan Srinivasan                    duration = bedtime - SystemClock.uptimeMillis();
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } while (duration > 0);
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (this) {
541a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final long[] pattern = mVibration.mPattern;
542a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final int len = pattern.length;
543a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final int repeat = mVibration.mRepeat;
544a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                final int uid = mVibration.mUid;
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int index = 0;
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long duration = 0;
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (!mDone) {
549f42f15cf450772d8eeb9c0c81a8403d33ffe1c9bEric Olsen                    // add off-time duration to any accumulated on-time duration
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (index < len) {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        duration += pattern[index++];
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // sleep until it is time to start the vibrator
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delay(duration);
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mDone) {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (index < len) {
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // read on-time duration and start the vibrator
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // duration is saved for delay() at top of loop
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        duration = pattern[index++];
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (duration > 0) {
565a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                            VibratorService.this.doVibratorOn(duration, uid);
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
56818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                        if (repeat < 0) {
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
57118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                            index = repeat;
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            duration = 0;
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mWakeLock.release();
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
57818dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott            synchronized (mVibrations) {
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mThread == this) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mThread = null;
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
58218dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                if (!mDone) {
58318dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // If this vibration finished naturally, start the next
58418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    // vibration.
58518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    mVibrations.remove(mVibration);
586b23949b7454ddb65f81e1bd4426b2cc714ab9c3eMathias Jeppsson                    unlinkVibration(mVibration);
58718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    startNextVibrationLocked();
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
59118dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott    };
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
59618dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                synchronized (mVibrations) {
59718dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    doCancelVibrateLocked();
5988a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan
5998a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan                    int size = mVibrations.size();
6008a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan                    for(int i = 0; i < size; i++) {
6018a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan                        unlinkVibration(mVibrations.get(i));
6028a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan                    }
6038a61f496919504a86244d2f833acfec9bc20a745Vairavan Srinivasan
60418dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                    mVibrations.clear();
60518dd5f0d25f1004e123dc265dc498a8bf8897af9Patrick Scott                }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
610