Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.content.pm.PackageManager;
     24 import android.database.ContentObserver;
     25 import android.hardware.input.InputManager;
     26 import android.os.Handler;
     27 import android.os.IVibratorService;
     28 import android.os.PowerManager;
     29 import android.os.Process;
     30 import android.os.RemoteException;
     31 import android.os.IBinder;
     32 import android.os.Binder;
     33 import android.os.SystemClock;
     34 import android.os.Vibrator;
     35 import android.os.WorkSource;
     36 import android.provider.Settings;
     37 import android.provider.Settings.SettingNotFoundException;
     38 import android.util.Slog;
     39 import android.view.InputDevice;
     40 
     41 import java.util.ArrayList;
     42 import java.util.LinkedList;
     43 import java.util.ListIterator;
     44 
     45 public class VibratorService extends IVibratorService.Stub
     46         implements InputManager.InputDeviceListener {
     47     private static final String TAG = "VibratorService";
     48 
     49     private final LinkedList<Vibration> mVibrations;
     50     private Vibration mCurrentVibration;
     51     private final WorkSource mTmpWorkSource = new WorkSource();
     52     private final Handler mH = new Handler();
     53 
     54     private final Context mContext;
     55     private final PowerManager.WakeLock mWakeLock;
     56     private InputManager mIm;
     57 
     58     volatile VibrateThread mThread;
     59 
     60     // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
     61     // to be acquired
     62     private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
     63     private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
     64     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
     65 
     66     native static boolean vibratorExists();
     67     native static void vibratorOn(long milliseconds);
     68     native static void vibratorOff();
     69 
     70     private class Vibration implements IBinder.DeathRecipient {
     71         private final IBinder mToken;
     72         private final long    mTimeout;
     73         private final long    mStartTime;
     74         private final long[]  mPattern;
     75         private final int     mRepeat;
     76         private final int     mUid;
     77 
     78         Vibration(IBinder token, long millis, int uid) {
     79             this(token, millis, null, 0, uid);
     80         }
     81 
     82         Vibration(IBinder token, long[] pattern, int repeat, int uid) {
     83             this(token, 0, pattern, repeat, uid);
     84         }
     85 
     86         private Vibration(IBinder token, long millis, long[] pattern,
     87                 int repeat, int uid) {
     88             mToken = token;
     89             mTimeout = millis;
     90             mStartTime = SystemClock.uptimeMillis();
     91             mPattern = pattern;
     92             mRepeat = repeat;
     93             mUid = uid;
     94         }
     95 
     96         public void binderDied() {
     97             synchronized (mVibrations) {
     98                 mVibrations.remove(this);
     99                 if (this == mCurrentVibration) {
    100                     doCancelVibrateLocked();
    101                     startNextVibrationLocked();
    102                 }
    103             }
    104         }
    105 
    106         public boolean hasLongerTimeout(long millis) {
    107             if (mTimeout == 0) {
    108                 // This is a pattern, return false to play the simple
    109                 // vibration.
    110                 return false;
    111             }
    112             if ((mStartTime + mTimeout)
    113                     < (SystemClock.uptimeMillis() + millis)) {
    114                 // If this vibration will end before the time passed in, let
    115                 // the new vibration play.
    116                 return false;
    117             }
    118             return true;
    119         }
    120     }
    121 
    122     VibratorService(Context context) {
    123         // Reset the hardware to a default state, in case this is a runtime
    124         // restart instead of a fresh boot.
    125         vibratorOff();
    126 
    127         mContext = context;
    128         PowerManager pm = (PowerManager)context.getSystemService(
    129                 Context.POWER_SERVICE);
    130         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
    131         mWakeLock.setReferenceCounted(true);
    132 
    133         mVibrations = new LinkedList<Vibration>();
    134 
    135         IntentFilter filter = new IntentFilter();
    136         filter.addAction(Intent.ACTION_SCREEN_OFF);
    137         context.registerReceiver(mIntentReceiver, filter);
    138     }
    139 
    140     public void systemReady() {
    141         mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
    142         mContext.getContentResolver().registerContentObserver(
    143                 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
    144                 new ContentObserver(mH) {
    145                     @Override
    146                     public void onChange(boolean selfChange) {
    147                         updateInputDeviceVibrators();
    148                     }
    149                 });
    150         updateInputDeviceVibrators();
    151     }
    152 
    153     public boolean hasVibrator() {
    154         return doVibratorExists();
    155     }
    156 
    157     public void vibrate(long milliseconds, IBinder token) {
    158         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
    159                 != PackageManager.PERMISSION_GRANTED) {
    160             throw new SecurityException("Requires VIBRATE permission");
    161         }
    162         int uid = Binder.getCallingUid();
    163         // We're running in the system server so we cannot crash. Check for a
    164         // timeout of 0 or negative. This will ensure that a vibration has
    165         // either a timeout of > 0 or a non-null pattern.
    166         if (milliseconds <= 0 || (mCurrentVibration != null
    167                 && mCurrentVibration.hasLongerTimeout(milliseconds))) {
    168             // Ignore this vibration since the current vibration will play for
    169             // longer than milliseconds.
    170             return;
    171         }
    172 
    173         Vibration vib = new Vibration(token, milliseconds, uid);
    174         synchronized (mVibrations) {
    175             removeVibrationLocked(token);
    176             doCancelVibrateLocked();
    177             mCurrentVibration = vib;
    178             startVibrationLocked(vib);
    179         }
    180     }
    181 
    182     private boolean isAll0(long[] pattern) {
    183         int N = pattern.length;
    184         for (int i = 0; i < N; i++) {
    185             if (pattern[i] != 0) {
    186                 return false;
    187             }
    188         }
    189         return true;
    190     }
    191 
    192     public void vibratePattern(long[] pattern, int repeat, IBinder token) {
    193         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
    194                 != PackageManager.PERMISSION_GRANTED) {
    195             throw new SecurityException("Requires VIBRATE permission");
    196         }
    197         int uid = Binder.getCallingUid();
    198         // so wakelock calls will succeed
    199         long identity = Binder.clearCallingIdentity();
    200         try {
    201             if (false) {
    202                 String s = "";
    203                 int N = pattern.length;
    204                 for (int i=0; i<N; i++) {
    205                     s += " " + pattern[i];
    206                 }
    207                 Slog.i(TAG, "vibrating with pattern: " + s);
    208             }
    209 
    210             // we're running in the server so we can't fail
    211             if (pattern == null || pattern.length == 0
    212                     || isAll0(pattern)
    213                     || repeat >= pattern.length || token == null) {
    214                 return;
    215             }
    216 
    217             Vibration vib = new Vibration(token, pattern, repeat, uid);
    218             try {
    219                 token.linkToDeath(vib, 0);
    220             } catch (RemoteException e) {
    221                 return;
    222             }
    223 
    224             synchronized (mVibrations) {
    225                 removeVibrationLocked(token);
    226                 doCancelVibrateLocked();
    227                 if (repeat >= 0) {
    228                     mVibrations.addFirst(vib);
    229                     startNextVibrationLocked();
    230                 } else {
    231                     // A negative repeat means that this pattern is not meant
    232                     // to repeat. Treat it like a simple vibration.
    233                     mCurrentVibration = vib;
    234                     startVibrationLocked(vib);
    235                 }
    236             }
    237         }
    238         finally {
    239             Binder.restoreCallingIdentity(identity);
    240         }
    241     }
    242 
    243     public void cancelVibrate(IBinder token) {
    244         mContext.enforceCallingOrSelfPermission(
    245                 android.Manifest.permission.VIBRATE,
    246                 "cancelVibrate");
    247 
    248         // so wakelock calls will succeed
    249         long identity = Binder.clearCallingIdentity();
    250         try {
    251             synchronized (mVibrations) {
    252                 final Vibration vib = removeVibrationLocked(token);
    253                 if (vib == mCurrentVibration) {
    254                     doCancelVibrateLocked();
    255                     startNextVibrationLocked();
    256                 }
    257             }
    258         }
    259         finally {
    260             Binder.restoreCallingIdentity(identity);
    261         }
    262     }
    263 
    264     private final Runnable mVibrationRunnable = new Runnable() {
    265         public void run() {
    266             synchronized (mVibrations) {
    267                 doCancelVibrateLocked();
    268                 startNextVibrationLocked();
    269             }
    270         }
    271     };
    272 
    273     // Lock held on mVibrations
    274     private void doCancelVibrateLocked() {
    275         if (mThread != null) {
    276             synchronized (mThread) {
    277                 mThread.mDone = true;
    278                 mThread.notify();
    279             }
    280             mThread = null;
    281         }
    282         doVibratorOff();
    283         mH.removeCallbacks(mVibrationRunnable);
    284     }
    285 
    286     // Lock held on mVibrations
    287     private void startNextVibrationLocked() {
    288         if (mVibrations.size() <= 0) {
    289             mCurrentVibration = null;
    290             return;
    291         }
    292         mCurrentVibration = mVibrations.getFirst();
    293         startVibrationLocked(mCurrentVibration);
    294     }
    295 
    296     // Lock held on mVibrations
    297     private void startVibrationLocked(final Vibration vib) {
    298         if (vib.mTimeout != 0) {
    299             doVibratorOn(vib.mTimeout);
    300             mH.postDelayed(mVibrationRunnable, vib.mTimeout);
    301         } else {
    302             // mThread better be null here. doCancelVibrate should always be
    303             // called before startNextVibrationLocked or startVibrationLocked.
    304             mThread = new VibrateThread(vib);
    305             mThread.start();
    306         }
    307     }
    308 
    309     // Lock held on mVibrations
    310     private Vibration removeVibrationLocked(IBinder token) {
    311         ListIterator<Vibration> iter = mVibrations.listIterator(0);
    312         while (iter.hasNext()) {
    313             Vibration vib = iter.next();
    314             if (vib.mToken == token) {
    315                 iter.remove();
    316                 unlinkVibration(vib);
    317                 return vib;
    318             }
    319         }
    320         // We might be looking for a simple vibration which is only stored in
    321         // mCurrentVibration.
    322         if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
    323             unlinkVibration(mCurrentVibration);
    324             return mCurrentVibration;
    325         }
    326         return null;
    327     }
    328 
    329     private void unlinkVibration(Vibration vib) {
    330         if (vib.mPattern != null) {
    331             // If Vibration object has a pattern,
    332             // the Vibration object has also been linkedToDeath.
    333             vib.mToken.unlinkToDeath(vib, 0);
    334         }
    335     }
    336 
    337     private void updateInputDeviceVibrators() {
    338         synchronized (mVibrations) {
    339             doCancelVibrateLocked();
    340 
    341             synchronized (mInputDeviceVibrators) {
    342                 mVibrateInputDevicesSetting = false;
    343                 try {
    344                     mVibrateInputDevicesSetting = Settings.System.getInt(mContext.getContentResolver(),
    345                             Settings.System.VIBRATE_INPUT_DEVICES) > 0;
    346                 } catch (SettingNotFoundException snfe) {
    347                 }
    348 
    349                 if (mVibrateInputDevicesSetting) {
    350                     if (!mInputDeviceListenerRegistered) {
    351                         mInputDeviceListenerRegistered = true;
    352                         mIm.registerInputDeviceListener(this, mH);
    353                     }
    354                 } else {
    355                     if (mInputDeviceListenerRegistered) {
    356                         mInputDeviceListenerRegistered = false;
    357                         mIm.unregisterInputDeviceListener(this);
    358                     }
    359                 }
    360 
    361                 mInputDeviceVibrators.clear();
    362                 if (mVibrateInputDevicesSetting) {
    363                     int[] ids = mIm.getInputDeviceIds();
    364                     for (int i = 0; i < ids.length; i++) {
    365                         InputDevice device = mIm.getInputDevice(ids[i]);
    366                         Vibrator vibrator = device.getVibrator();
    367                         if (vibrator.hasVibrator()) {
    368                             mInputDeviceVibrators.add(vibrator);
    369                         }
    370                     }
    371                 }
    372             }
    373 
    374             startNextVibrationLocked();
    375         }
    376     }
    377 
    378     @Override
    379     public void onInputDeviceAdded(int deviceId) {
    380         updateInputDeviceVibrators();
    381     }
    382 
    383     @Override
    384     public void onInputDeviceChanged(int deviceId) {
    385         updateInputDeviceVibrators();
    386     }
    387 
    388     @Override
    389     public void onInputDeviceRemoved(int deviceId) {
    390         updateInputDeviceVibrators();
    391     }
    392 
    393     private boolean doVibratorExists() {
    394         // For now, we choose to ignore the presence of input devices that have vibrators
    395         // when reporting whether the device has a vibrator.  Applications often use this
    396         // information to decide whether to enable certain features so they expect the
    397         // result of hasVibrator() to be constant.  For now, just report whether
    398         // the device has a built-in vibrator.
    399         //synchronized (mInputDeviceVibrators) {
    400         //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
    401         //}
    402         return vibratorExists();
    403     }
    404 
    405     private void doVibratorOn(long millis) {
    406         synchronized (mInputDeviceVibrators) {
    407             final int vibratorCount = mInputDeviceVibrators.size();
    408             if (vibratorCount != 0) {
    409                 for (int i = 0; i < vibratorCount; i++) {
    410                     mInputDeviceVibrators.get(i).vibrate(millis);
    411                 }
    412             } else {
    413                 vibratorOn(millis);
    414             }
    415         }
    416     }
    417 
    418     private void doVibratorOff() {
    419         synchronized (mInputDeviceVibrators) {
    420             final int vibratorCount = mInputDeviceVibrators.size();
    421             if (vibratorCount != 0) {
    422                 for (int i = 0; i < vibratorCount; i++) {
    423                     mInputDeviceVibrators.get(i).cancel();
    424                 }
    425             } else {
    426                 vibratorOff();
    427             }
    428         }
    429     }
    430 
    431     private class VibrateThread extends Thread {
    432         final Vibration mVibration;
    433         boolean mDone;
    434 
    435         VibrateThread(Vibration vib) {
    436             mVibration = vib;
    437             mTmpWorkSource.set(vib.mUid);
    438             mWakeLock.setWorkSource(mTmpWorkSource);
    439             mWakeLock.acquire();
    440         }
    441 
    442         private void delay(long duration) {
    443             if (duration > 0) {
    444                 long bedtime = SystemClock.uptimeMillis();
    445                 do {
    446                     try {
    447                         this.wait(duration);
    448                     }
    449                     catch (InterruptedException e) {
    450                     }
    451                     if (mDone) {
    452                         break;
    453                     }
    454                     duration = duration
    455                             - SystemClock.uptimeMillis() - bedtime;
    456                 } while (duration > 0);
    457             }
    458         }
    459 
    460         public void run() {
    461             Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
    462             synchronized (this) {
    463                 int index = 0;
    464                 long[] pattern = mVibration.mPattern;
    465                 int len = pattern.length;
    466                 int repeat = mVibration.mRepeat;
    467                 long duration = 0;
    468 
    469                 while (!mDone) {
    470                     // add off-time duration to any accumulated on-time duration
    471                     if (index < len) {
    472                         duration += pattern[index++];
    473                     }
    474 
    475                     // sleep until it is time to start the vibrator
    476                     delay(duration);
    477                     if (mDone) {
    478                         break;
    479                     }
    480 
    481                     if (index < len) {
    482                         // read on-time duration and start the vibrator
    483                         // duration is saved for delay() at top of loop
    484                         duration = pattern[index++];
    485                         if (duration > 0) {
    486                             VibratorService.this.doVibratorOn(duration);
    487                         }
    488                     } else {
    489                         if (repeat < 0) {
    490                             break;
    491                         } else {
    492                             index = repeat;
    493                             duration = 0;
    494                         }
    495                     }
    496                 }
    497                 mWakeLock.release();
    498             }
    499             synchronized (mVibrations) {
    500                 if (mThread == this) {
    501                     mThread = null;
    502                 }
    503                 if (!mDone) {
    504                     // If this vibration finished naturally, start the next
    505                     // vibration.
    506                     mVibrations.remove(mVibration);
    507                     unlinkVibration(mVibration);
    508                     startNextVibrationLocked();
    509                 }
    510             }
    511         }
    512     };
    513 
    514     BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    515         public void onReceive(Context context, Intent intent) {
    516             if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
    517                 synchronized (mVibrations) {
    518                     doCancelVibrateLocked();
    519 
    520                     int size = mVibrations.size();
    521                     for(int i = 0; i < size; i++) {
    522                         unlinkVibration(mVibrations.get(i));
    523                     }
    524 
    525                     mVibrations.clear();
    526                 }
    527             }
    528         }
    529     };
    530 }
    531