AndroidM 振动器系统

来源:互联网 发布:页面加载完毕后调用js 编辑:程序博客网 时间:2024/05/01 08:03
1.马达的使用
在使用马达服务时需要在manifest中加<uses-permission android:name="android.permission.VIBRATE"/>权限
public void testVibrator(Context context, int command) {
   Vibrator mVibrator = (Vibrator)context.getSystemService(context.VIBRATOR_SERVICE);
   switch(command){
   case 0:
      mVibrator.vibrate(1000); // 震动1s
      break;
   case 1:
      // 等待100ms后,按数组所给数值间隔震动,0为一直震动,-1为不重复
      mVibrator.vibrate(new long[]{100,200,100,40,60}, 0);
      break;
   case 2:
      break;
   default :
      mVibrator.cancel(); // 取消震动
   }
}


2.马达服务的framework层的实现
马达系统包含了驱动程序,硬件抽象层,JNI部分,Java框架等几个部分
/frameworks/base/core/java/android/os/Vibrator.java
/frameworks/base/core/java/android/os/SystemVibrator.java
/frameworks/base/services/core/java/com/android/server/VibratorService.java
/frameworks/base/core/java/android/os/IVibratorService.aidl
/frameworks/base/services/core/jni/com_android_server_VibratorService.cpp
/hardware/libhardware_legacy/include/hardware_legacy/vibrator.h
/hardware/libhardware_legacy/vibrator/vibrator.c

// Vibrator的实现代码
public abstract class Vibrator {
   ........
   // 是否有马达
   public abstract boolean hasVibrator();

   // 各种构造函数
   public void vibrate(long milliseconds) {
        vibrate(milliseconds, null); // 震动
    }
   ........
   // 取消震动
   public abstract void cancel();
}

// SystemVibrator的实现代码
public class SystemVibrator extends Vibrator {
   private static final String TAG = "Vibrator";

   private final IVibratorService mService; // 保存VibratorService对象
   private final Binder mToken = new Binder();
   // 构造函数,初始化VibratorService对象
   public SystemVibrator() {
       mService = IVibratorService.Stub.asInterface(
               ServiceManager.getService("vibrator"));
   }

   public SystemVibrator(Context context) {
       super(context);
       mService = IVibratorService.Stub.asInterface(
               ServiceManager.getService("vibrator"));
   }

   @Override
   public boolean hasVibrator() {
       ........
       try { // 调用VibratorService对象的hasVibrator()方法来判断是否有马达
           return mService.hasVibrator(); // 最终将调用到VibratorService的本地方法vibratorExists
       } catch (RemoteException e) {
       }
       return false;
   }

   @Override
   public void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) {
       ........
       try { // 调用VibratorService对象的vibrate方法来使马达震动
           mService.vibrate(uid, opPkg, milliseconds, usageForAttributes(attributes), mToken);
       } catch (RemoteException e) {
           Log.w(TAG, "Failed to vibrate.", e);
       }
   }

   @Override
   public void vibrate(int uid, String opPkg, long[] pattern, int repeat,
           AudioAttributes attributes) {
       ........
       if (repeat < pattern.length) {
           try { // 调用VibratorService对象的vibratePattern方法来使马达震动
               mService.vibratePattern(uid, opPkg, pattern, repeat, usageForAttributes(attributes),
                       mToken);
           } catch (RemoteException e) {
               Log.w(TAG, "Failed to vibrate.", e);
           }
       } else {
           throw new ArrayIndexOutOfBoundsException();
       }
   }
   ........
   @Override
   public void cancel() {
        if (mService == null) {
            return;
        }
        try { // 调用VibratorService对象的cancelVibrate方法来取消振动
            mService.cancelVibrate(mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to cancel vibration.", e);
        }
   }
}

// IVibratorService的定义
interface IVibratorService
{
    boolean hasVibrator();
    void vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token);
    void vibratePattern(int uid, String opPkg, in long[] pattern, int repeat, int usageHint, IBinder token);
    void cancelVibrate(IBinder token);
}

// VibratorService的实现
// VibratorService实际上是通过调用本地方法来控制马达,
// 开始震动vibrate,vibratePattern; 结束震动cancelVibrate; 判断是否有振动器hasVibrator
public class VibratorService extends IVibratorService.Stub
        implements InputManager.InputDeviceListener {
    private static final String TAG = "VibratorService";
    private static final boolean DEBUG = false;

    private final LinkedList<Vibration> mVibrations; // 记录所有马达
    private final LinkedList<VibrationInfo> mPreviousVibrations; // 记录所有马达的信息
    ........

    native static boolean vibratorExists(); // 本地方法,判断是否存在马达
    native static void vibratorOn(long milliseconds); // 开始震动,震动时长为milliseconds
    native static void vibratorOff(); // 停止震动
    ........
    // VibrationInfo 马达信息
    private static class VibrationInfo {
        long timeout;   // 震动时长
        long startTime; // 开始时间
        long[] pattern; // 震动模式
        int repeat;     // 重复次数
        int usageHint;  // 
        int uid;        // 调用马达的线程ID
        String opPkg;  

        public VibrationInfo(long timeout, long startTime, long[] pattern, int repeat,
                int usageHint, int uid, String opPkg) {
            ........
        }

        @Override
        public String toString() {
            ........
        }
    }

    VibratorService(Context context) {
        vibratorOff(); // 关闭马达的震动

        mContext = context;
        PowerManager pm = (PowerManager)context.getSystemService(
                Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
        mWakeLock.setReferenceCounted(true);

        mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                BatteryStats.SERVICE_NAME));

        mPreviousVibrationsLimit = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_previousVibrationsDumpLimit);

        mVibrations = new LinkedList<>();
        mPreviousVibrations = new LinkedList<>();

        // 注册屏幕关闭广播的监听器,当屏幕关闭时取消一些应用发出的震动
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        context.registerReceiver(mIntentReceiver, filter);
    }

    public void systemReady() { // 当system ready时systemserver将会调用此方法
        mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
        mSettingObserver = new SettingsObserver(mH);

        // 低电模式改变时调用updateInputDeviceVibrators方法
        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
        mPowerManagerInternal.registerLowPowerModeObserver(
                new PowerManagerInternal.LowPowerModeListener() {
            @Override
            public void onLowPowerModeChanged(boolean enabled) {
                updateInputDeviceVibrators();
            }
        });

        // VIBRATE_INPUT_DEVICES发生变化时调用updateInputDeviceVibrators方法,在mSettingObserver监听器中进行
        mContext.getContentResolver().registerContentObserver(
                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
                true, mSettingObserver, UserHandle.USER_ALL);

        // 用户切换时调用updateInputDeviceVibrators方法
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updateInputDeviceVibrators();
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);

        //当切换用户,有效的输入设备发生变化,以及低电模式改变时调用以下方法
        updateInputDeviceVibrators();
    }

    private final class SettingsObserver extends ContentObserver {
        public SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean SelfChange) {
            updateInputDeviceVibrators();
        }
    }

    @Override 
    public boolean hasVibrator() {
        return doVibratorExists(); // 最终调用本地方法来进行判断
    }

    private void verifyIncomingUid(int uid) {
        if (uid == Binder.getCallingUid()) {
            return;
        }
        if (Binder.getCallingPid() == Process.myPid()) {
            return;
        }
        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
                Binder.getCallingPid(), Binder.getCallingUid(), null);
    }

    @Override // Binder call
    public void vibrate(int uid, String opPkg, long milliseconds, int usageHint,
            IBinder token) {
        // 做一些基础检查,是否有申请权限,检查线程ID权限,震动时长检查等
        ........
        Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);

        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mVibrations) {
                removeVibrationLocked(token);
                doCancelVibrateLocked();
                mCurrentVibration = vib;
                addToPreviousVibrationsLocked(vib);
                startVibrationLocked(vib);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

    }

    ........


    @Override // Binder call
    public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
            int usageHint, IBinder token) {
        // 做一些基础检查,是否申请权限,检查线程ID权限等
        ........
        long identity = Binder.clearCallingIdentity();
        try {
            ........
            synchronized (mVibrations) {
                removeVibrationLocked(token);
                doCancelVibrateLocked();
                if (repeat >= 0) {
                    mVibrations.addFirst(vib);
                    startNextVibrationLocked();
                } else {
                    // A negative repeat means that this pattern is not meant
                    // to repeat. Treat it like a simple vibration.
                    mCurrentVibration = vib;
                    startVibrationLocked(vib);
                }
                addToPreviousVibrationsLocked(vib);
            }
        }
        finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    ........

    private boolean doVibratorExists() {
        ........
        return vibratorExists();
    }


    private void doVibratorOn(long millis, int uid, int usageHint) {
        synchronized (mInputDeviceVibrators) {

            ........

            if (vibratorCount != 0) {

                final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
                        .build();
                for (int i = 0; i < vibratorCount; i++) {
                    mInputDeviceVibrators.get(i).vibrate(millis, attributes);
                }
            } else {
                vibratorOn(millis); // 调用本地方法启动马达震动
            }
        }
    }


    private void doVibratorOff() {
        synchronized (mInputDeviceVibrators) {
            ........
            if (vibratorCount != 0) {
                for (int i = 0; i < vibratorCount; i++) {
                    mInputDeviceVibrators.get(i).cancel();
                }
            } else {
                vibratorOff(); // 调用本地方法关闭马达震动
            }
        }
    }

    ........

    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                synchronized (mVibrations) {
                    // 当系统进入一个非交互式的状态,我们想取消应用程序的振动行为。
                    // 然而它可能是系统目前正在进行触觉反馈。所以我们不取消系统振动。
                    if (mCurrentVibration != null
                            && !mCurrentVibration.isSystemHapticFeedback()) {
                        doCancelVibrateLocked();
                    }

                    // 清除所有其他的震动
                    Iterator<Vibration> it = mVibrations.iterator();
                    while (it.hasNext()) {
                        Vibration vibration = it.next();
                        if (vibration != mCurrentVibration) {
                            unlinkVibration(vibration);
                            it.remove();
                        }
                    }
                }
            }
        }
    };

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        ........
        // 打印mPreviousVibrations保存的信息
        synchronized (mVibrations) {
            for (VibrationInfo info : mPreviousVibrations) {
                pw.print("  ");
                pw.println(info.toString());
            }
        }
    }
}

3.马达服务的JNI层实现 com_android_server_VibratorService.cpp
........
#include <hardware_legacy/vibrator.h> // 此处是直接调用hardware层代码来实现
#include <stdio.h>
static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{
    // 调用hardware层vibrator_exists
    return vibrator_exists() > 0 ? JNI_TRUE : JNI_FALSE;
}

static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{
    // 调用hardware层vibrator_on
    vibrator_on(timeout_ms);
}

static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{
    // 调用hardware层vibrator_off
    vibrator_off();
}


// 关联本地方法与JAVA方法

static JNINativeMethod method_table[] = {
    { "vibratorExists", "()Z", (void*)vibratorExists },
    { "vibratorOn", "(J)V", (void*)vibratorOn },
    { "vibratorOff", "()V", (void*)vibratorOff }
};
// 注册method_table,在加载库完成后会调用此方法
int register_android_server_VibratorService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
            method_table, NELEM(method_table));
}

};

4.马达服务的hardware层实现 
// vibrator.h
........
int vibrator_exists(); // 判断是否存在马达,返回1存在,0不存在
int vibrator_on(int timeout_ms); // 打开马达,返回0成功,-1失败
int vibrator_off(); // 关闭马达,返回0成功,-1失败
........

vibrator.c
........
// 写此文件表示使能指定的时间,读表示获取剩余的时间
#define THE_DEVICE "/sys/class/timed_output/vibrator/enable" 

int vibrator_exists()
{
    int fd;

#ifdef QEMU_HARDWARE //模拟器环境
    if (qemu_check()) {
        return 1;
    }
#endif

    fd = open(THE_DEVICE, O_RDWR); // 如果打开成功则表示有马达
    if(fd < 0)
        return 0;
    close(fd);
    return 1;
}

static int sendit(int timeout_ms) //往THE_DEVICE中写数据表示设置马达震动时长
{
    int nwr, ret, fd;
    char value[20];

#ifdef QEMU_HARDWARE
    if (qemu_check()) {
        return qemu_control_command( "vibrator:%d", timeout_ms );
    }
#endif

    fd = open(THE_DEVICE, O_RDWR); // 打开设备文件
    if(fd < 0)
        return errno;

    nwr = sprintf(value, "%d\n", timeout_ms);
    ret = write(fd, value, nwr); // 往设备文件中写震动时长

    close(fd);

    return (ret == nwr) ? 0 : -1;
}

int vibrator_on(int timeout_ms) // 打开马达,设置震动时长
{
    return sendit(timeout_ms);
}

int vibrator_off() //关闭马达
{
    return sendit(0);
}







0 0
原创粉丝点击