Home | History | Annotate | Download | only in incallui
      1 /*
      2  * Copyright (C) 2015 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.incallui;
     18 
     19 import android.content.Context;
     20 import android.content.pm.ActivityInfo;
     21 import android.support.annotation.IntDef;
     22 import android.view.OrientationEventListener;
     23 import com.android.dialer.common.LogUtil;
     24 import java.lang.annotation.Retention;
     25 import java.lang.annotation.RetentionPolicy;
     26 
     27 /**
     28  * This class listens to Orientation events and overrides onOrientationChanged which gets invoked
     29  * when an orientation change occurs. When that happens, we notify InCallUI registrants of the
     30  * change.
     31  */
     32 public class InCallOrientationEventListener extends OrientationEventListener {
     33 
     34   public static final int SCREEN_ORIENTATION_0 = 0;
     35   public static final int SCREEN_ORIENTATION_90 = 90;
     36   public static final int SCREEN_ORIENTATION_180 = 180;
     37   public static final int SCREEN_ORIENTATION_270 = 270;
     38   public static final int SCREEN_ORIENTATION_360 = 360;
     39 
     40   /** Screen orientation angles one of 0, 90, 180, 270, 360 in degrees. */
     41   @Retention(RetentionPolicy.SOURCE)
     42   @IntDef({
     43     SCREEN_ORIENTATION_0,
     44     SCREEN_ORIENTATION_90,
     45     SCREEN_ORIENTATION_180,
     46     SCREEN_ORIENTATION_270,
     47     SCREEN_ORIENTATION_360,
     48     SCREEN_ORIENTATION_UNKNOWN
     49   })
     50   public @interface ScreenOrientation {}
     51 
     52   // We use SCREEN_ORIENTATION_USER so that reverse-portrait is not allowed.
     53   public static final int ACTIVITY_PREFERENCE_ALLOW_ROTATION = ActivityInfo.SCREEN_ORIENTATION_USER;
     54 
     55   public static final int ACTIVITY_PREFERENCE_DISALLOW_ROTATION =
     56       ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
     57 
     58   /**
     59    * This is to identify dead zones where we won't notify others of orientation changed. Say for e.g
     60    * our threshold is x degrees. We will only notify UI when our current rotation is within x
     61    * degrees right or left of the screen orientation angles. If it's not within those ranges, we
     62    * return SCREEN_ORIENTATION_UNKNOWN and ignore it.
     63    */
     64   public static final int SCREEN_ORIENTATION_UNKNOWN = -1;
     65 
     66   // Rotation threshold is 10 degrees. So if the rotation angle is within 10 degrees of any of
     67   // the above angles, we will notify orientation changed.
     68   private static final int ROTATION_THRESHOLD = 10;
     69 
     70   /** Cache the current rotation of the device. */
     71   @ScreenOrientation private static int sCurrentOrientation = SCREEN_ORIENTATION_0;
     72 
     73   private boolean mEnabled = false;
     74 
     75   public InCallOrientationEventListener(Context context) {
     76     super(context);
     77   }
     78 
     79   private static boolean isWithinRange(int value, int begin, int end) {
     80     return value >= begin && value < end;
     81   }
     82 
     83   private static boolean isWithinThreshold(int value, int center, int threshold) {
     84     return isWithinRange(value, center - threshold, center + threshold);
     85   }
     86 
     87   private static boolean isInLeftRange(int value, int center, int threshold) {
     88     return isWithinRange(value, center - threshold, center);
     89   }
     90 
     91   private static boolean isInRightRange(int value, int center, int threshold) {
     92     return isWithinRange(value, center, center + threshold);
     93   }
     94 
     95   @ScreenOrientation
     96   public static int getCurrentOrientation() {
     97     return sCurrentOrientation;
     98   }
     99 
    100   /**
    101    * Handles changes in device orientation. Notifies InCallPresenter of orientation changes.
    102    *
    103    * <p>Note that this API receives sensor rotation in degrees as a param and we convert that to one
    104    * of our screen orientation constants - (one of: {@link #SCREEN_ORIENTATION_0}, {@link
    105    * #SCREEN_ORIENTATION_90}, {@link #SCREEN_ORIENTATION_180}, {@link #SCREEN_ORIENTATION_270}).
    106    *
    107    * @param rotation The new device sensor rotation in degrees
    108    */
    109   @Override
    110   public void onOrientationChanged(int rotation) {
    111     if (rotation == OrientationEventListener.ORIENTATION_UNKNOWN) {
    112       return;
    113     }
    114 
    115     final int orientation = toScreenOrientation(rotation);
    116 
    117     if (orientation != SCREEN_ORIENTATION_UNKNOWN && sCurrentOrientation != orientation) {
    118       LogUtil.i(
    119           "InCallOrientationEventListener.onOrientationChanged",
    120           "orientation: %d -> %d",
    121           sCurrentOrientation,
    122           orientation);
    123       sCurrentOrientation = orientation;
    124       InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation);
    125     }
    126   }
    127 
    128   /**
    129    * Enables the OrientationEventListener and notifies listeners of current orientation if notify
    130    * flag is true
    131    *
    132    * @param notify true or false. Notify device orientation changed if true.
    133    */
    134   public void enable(boolean notify) {
    135     if (mEnabled) {
    136       Log.v(this, "enable: Orientation listener is already enabled. Ignoring...");
    137       return;
    138     }
    139 
    140     super.enable();
    141     mEnabled = true;
    142     if (notify) {
    143       InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation);
    144     }
    145   }
    146 
    147   /** Enables the OrientationEventListener with notify flag defaulting to false. */
    148   @Override
    149   public void enable() {
    150     enable(false);
    151   }
    152 
    153   /** Disables the OrientationEventListener. */
    154   @Override
    155   public void disable() {
    156     if (!mEnabled) {
    157       Log.v(this, "enable: Orientation listener is already disabled. Ignoring...");
    158       return;
    159     }
    160 
    161     mEnabled = false;
    162     super.disable();
    163   }
    164 
    165   /** Returns true the OrientationEventListener is enabled, false otherwise. */
    166   public boolean isEnabled() {
    167     return mEnabled;
    168   }
    169 
    170   /**
    171    * Converts sensor rotation in degrees to screen orientation constants.
    172    *
    173    * @param rotation sensor rotation angle in degrees
    174    * @return Screen orientation angle in degrees (0, 90, 180, 270). Returns -1 for degrees not
    175    *     within threshold to identify zones where orientation change should not be trigerred.
    176    */
    177   @ScreenOrientation
    178   private int toScreenOrientation(int rotation) {
    179     // Sensor orientation 90 is equivalent to screen orientation 270 and vice versa. This
    180     // function returns the screen orientation. So we convert sensor rotation 90 to 270 and
    181     // vice versa here.
    182     if (isInLeftRange(rotation, SCREEN_ORIENTATION_360, ROTATION_THRESHOLD)
    183         || isInRightRange(rotation, SCREEN_ORIENTATION_0, ROTATION_THRESHOLD)) {
    184       return SCREEN_ORIENTATION_0;
    185     } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_90, ROTATION_THRESHOLD)) {
    186       return SCREEN_ORIENTATION_270;
    187     } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_180, ROTATION_THRESHOLD)) {
    188       return SCREEN_ORIENTATION_180;
    189     } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_270, ROTATION_THRESHOLD)) {
    190       return SCREEN_ORIENTATION_90;
    191     }
    192     return SCREEN_ORIENTATION_UNKNOWN;
    193   }
    194 }
    195