| /* |
| * 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.incallui; |
| |
| import android.content.Context; |
| import android.hardware.Sensor; |
| import android.hardware.SensorEvent; |
| import android.hardware.SensorEventListener; |
| import android.hardware.SensorManager; |
| import android.os.Handler; |
| import android.os.Message; |
| import com.android.dialer.common.LogUtil; |
| |
| /** |
| * This class is used to listen to the accelerometer to monitor the orientation of the phone. The |
| * client of this class is notified when the orientation changes between horizontal and vertical. |
| */ |
| public class AccelerometerListener { |
| |
| // Device orientation |
| public static final int ORIENTATION_UNKNOWN = 0; |
| public static final int ORIENTATION_VERTICAL = 1; |
| public static final int ORIENTATION_HORIZONTAL = 2; |
| private static final String TAG = "AccelerometerListener"; |
| private static final boolean DEBUG = true; |
| private static final boolean VDEBUG = false; |
| private static final int ORIENTATION_CHANGED = 1234; |
| private static final int VERTICAL_DEBOUNCE = 100; |
| private static final int HORIZONTAL_DEBOUNCE = 500; |
| private static final double VERTICAL_ANGLE = 50.0; |
| private SensorManager sensorManager; |
| private Sensor sensor; |
| // mOrientation is the orientation value most recently reported to the client. |
| private int orientation; |
| // mPendingOrientation is the latest orientation computed based on the sensor value. |
| // This is sent to the client after a rebounce delay, at which point it is copied to |
| // mOrientation. |
| private int pendingOrientation; |
| private OrientationListener listener; |
| Handler handler = |
| new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case ORIENTATION_CHANGED: |
| synchronized (this) { |
| orientation = pendingOrientation; |
| if (DEBUG) { |
| LogUtil.d( |
| TAG, |
| "orientation: " |
| + (orientation == ORIENTATION_HORIZONTAL |
| ? "horizontal" |
| : (orientation == ORIENTATION_VERTICAL ? "vertical" : "unknown"))); |
| } |
| if (listener != null) { |
| listener.orientationChanged(orientation); |
| } |
| } |
| break; |
| } |
| } |
| }; |
| SensorEventListener sensorListener = |
| new SensorEventListener() { |
| @Override |
| public void onSensorChanged(SensorEvent event) { |
| onSensorEvent(event.values[0], event.values[1], event.values[2]); |
| } |
| |
| @Override |
| public void onAccuracyChanged(Sensor sensor, int accuracy) { |
| // ignore |
| } |
| }; |
| |
| public AccelerometerListener(Context context) { |
| sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); |
| sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); |
| } |
| |
| public void setListener(OrientationListener listener) { |
| this.listener = listener; |
| } |
| |
| public void enable(boolean enable) { |
| if (DEBUG) { |
| LogUtil.d(TAG, "enable(" + enable + ")"); |
| } |
| synchronized (this) { |
| if (enable) { |
| orientation = ORIENTATION_UNKNOWN; |
| pendingOrientation = ORIENTATION_UNKNOWN; |
| sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); |
| } else { |
| sensorManager.unregisterListener(sensorListener); |
| handler.removeMessages(ORIENTATION_CHANGED); |
| } |
| } |
| } |
| |
| private void setOrientation(int orientation) { |
| synchronized (this) { |
| if (pendingOrientation == orientation) { |
| // Pending orientation has not changed, so do nothing. |
| return; |
| } |
| |
| // Cancel any pending messages. |
| // We will either start a new timer or cancel alltogether |
| // if the orientation has not changed. |
| handler.removeMessages(ORIENTATION_CHANGED); |
| |
| if (this.orientation != orientation) { |
| // Set timer to send an event if the orientation has changed since its |
| // previously reported value. |
| pendingOrientation = orientation; |
| final Message m = handler.obtainMessage(ORIENTATION_CHANGED); |
| // set delay to our debounce timeout |
| int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE : HORIZONTAL_DEBOUNCE); |
| handler.sendMessageDelayed(m, delay); |
| } else { |
| // no message is pending |
| pendingOrientation = ORIENTATION_UNKNOWN; |
| } |
| } |
| } |
| |
| private void onSensorEvent(double x, double y, double z) { |
| if (VDEBUG) { |
| LogUtil.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")"); |
| } |
| |
| // If some values are exactly zero, then likely the sensor is not powered up yet. |
| // ignore these events to avoid false horizontal positives. |
| if (x == 0.0 || y == 0.0 || z == 0.0) { |
| return; |
| } |
| |
| // magnitude of the acceleration vector projected onto XY plane |
| final double xy = Math.hypot(x, y); |
| // compute the vertical angle |
| double angle = Math.atan2(xy, z); |
| // convert to degrees |
| angle = angle * 180.0 / Math.PI; |
| final int orientation = |
| (angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL); |
| if (VDEBUG) { |
| LogUtil.d(TAG, "angle: " + angle + " orientation: " + orientation); |
| } |
| setOrientation(orientation); |
| } |
| |
| public interface OrientationListener { |
| |
| void orientationChanged(int orientation); |
| } |
| } |