/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.phone; import android.content.Context; import android.content.ContentResolver; import android.content.res.Resources; import android.os.Vibrator; import android.util.Log; import android.provider.Settings; import android.provider.Settings.System; /** * Handles the haptic feedback: a light buzz happening when the user * presses a soft key (UI button or capacitive key). The haptic * feedback is controlled by: * - a system resource for the pattern * The pattern used is tuned per device and stored in an internal * resource (config_virtualKeyVibePattern.) * - a system setting HAPTIC_FEEDBACK_ENABLED. * HAPTIC_FEEDBACK_ENABLED can be changed by the user using the * system Settings activity. It must be rechecked each time the * activity comes in the foreground (onResume). * * This class is not thread safe. It assumes it'll be called from the * UI thead. * * Typical usage: * -------------- * static private final boolean HAPTIC_ENABLED = true; * private HapticFeedback mHaptic = new HapticFeedback(); * * protected void onCreate(Bundle icicle) { * mHaptic.init((Context)this, HAPTIC_ENABLED); * } * * protected void onResume() { * // Refresh the system setting. * mHaptic.checkSystemSetting(); * } * * public void foo() { * mHaptic.vibrate(); * } * */ public class HapticFeedback { private static final int VIBRATION_PATTERN_ID = com.android.internal.R.array.config_virtualKeyVibePattern; /** If no pattern was found, vibrate for a small amount of time. */ private static final long DURATION = 10; // millisec. /** Play the haptic pattern only once. */ private static final int NO_REPEAT = -1; private static final String TAG = "HapticFeedback"; private Context mContext; private long[] mHapticPattern; private Vibrator mVibrator; private boolean mEnabled; private Settings.System mSystemSettings; private ContentResolver mContentResolver; private boolean mSettingEnabled; /** * Initialize this instance using the app and system * configs. Since these don't change, init is typically called * once in 'onCreate'. * checkSettings is not called during init. * @param context To look up the resources and system settings. * @param enabled If false, vibrate will be a no-op regardless of * the system settings. */ public void init(Context context, boolean enabled) { mEnabled = enabled; if (enabled) { mVibrator = new Vibrator(); if (!loadHapticSystemPattern(context.getResources())) { mHapticPattern = new long[] {0, DURATION, 2 * DURATION, 3 * DURATION}; } mSystemSettings = new Settings.System(); mContentResolver = context.getContentResolver(); } } /** * Reload the system settings to check if the user enabled the * haptic feedback. */ public void checkSystemSetting() { if (!mEnabled) { return; } try { int val = mSystemSettings.getInt(mContentResolver, System.HAPTIC_FEEDBACK_ENABLED, 0); mSettingEnabled = val != 0; } catch (Resources.NotFoundException nfe) { Log.e(TAG, "Could not retrieve system setting.", nfe); mSettingEnabled = false; } } /** * Generate the haptic feedback vibration. Only one thread can * request it. If the phone is already in a middle of an haptic * feedback sequence, the request is ignored. */ public void vibrate() { if (!mEnabled || !mSettingEnabled) { return; } mVibrator.vibrate(mHapticPattern, NO_REPEAT); } /** * @return true If the system haptic pattern was found. */ private boolean loadHapticSystemPattern(Resources r) { int[] pattern; mHapticPattern = null; try { pattern = r.getIntArray(VIBRATION_PATTERN_ID); } catch (Resources.NotFoundException nfe) { Log.e(TAG, "Vibrate pattern missing.", nfe); return false; } if (null == pattern || pattern.length == 0) { Log.e(TAG, "Haptic pattern is null or empty."); return false; } // int[] to long[] conversion. mHapticPattern = new long[pattern.length]; for (int i = 0; i < pattern.length; i++) { mHapticPattern[i] = pattern[i]; } return true; } }