content: /*
   * Copyright (C) 2018 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.launcher3.states;
  
  import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
  import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
  import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
  import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
  
  import android.content.SharedPreferences;
  import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
  import android.content.res.Resources;
  import android.view.WindowManager;
  import android.view.WindowManager.LayoutParams;
  
  import com.android.launcher3.Launcher;
  import com.android.launcher3.R;
  import com.android.launcher3.Utilities;
  import com.android.launcher3.config.FeatureFlags;
  import com.android.launcher3.util.UiThreadHelper;
  
  /**
   * Utility class to manage launcher rotation
   */
  public class RotationHelper implements OnSharedPreferenceChangeListener {
  
      public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
  
      public static boolean getAllowRotationDefaultValue() {
          // If the device was scaled, used the original dimensions to determine if rotation
          // is allowed of not.
          Resources res = Resources.getSystem();
          int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
                  * res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
          return originalSmallestWidth >= 600;
      }
  
      public static final int REQUEST_NONE = 0;
      public static final int REQUEST_ROTATE = 1;
      public static final int REQUEST_LOCK = 2;
  
      private final Launcher mLauncher;
      private final SharedPreferences mPrefs;
  
      private boolean mIgnoreAutoRotateSettings;
      private boolean mAutoRotateEnabled;
  
      /**
       * Rotation request made by {@link InternalStateHandler}. This supersedes any other request.
       */
      private int mStateHandlerRequest = REQUEST_NONE;
      /**
       * Rotation request made by an app transition
       */
      private int mCurrentTransitionRequest = REQUEST_NONE;
      /**
       * Rotation request made by a Launcher State
       */
      private int mCurrentStateRequest = REQUEST_NONE;
  
      // This is used to defer setting rotation flags until the activity is being created
      private boolean mInitialized;
      private boolean mDestroyed;
      private boolean mRotationHasDifferentUI;
  
      private int mLastActivityFlags = -1;
  
      public RotationHelper(Launcher launcher) {
          mLauncher = launcher;
  
          // On large devices we do not handle auto-rotate differently.
          mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
          if (!mIgnoreAutoRotateSettings) {
              mPrefs = Utilities.getPrefs(mLauncher);
              mPrefs.registerOnSharedPreferenceChangeListener(this);
              mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
                      getAllowRotationDefaultValue());
          } else {
              mPrefs = null;
          }
      }
  
      public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) {
          mRotationHasDifferentUI = rotationHasDifferentUI;
      }
  
      public boolean homeScreenCanRotate() {
          return mRotationHasDifferentUI || mIgnoreAutoRotateSettings || mAutoRotateEnabled
                  || mStateHandlerRequest != REQUEST_NONE
                  || mLauncher.getDeviceProfile().isMultiWindowMode;
      }
  
      public void updateRotationAnimation() {
          if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
              WindowManager.LayoutParams lp = mLauncher.getWindow().getAttributes();
              int oldAnim = lp.rotationAnimation;
              lp.rotationAnimation = homeScreenCanRotate()
                      ? WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE
                      : WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
              if (oldAnim != lp.rotationAnimation) {
                  mLauncher.getWindow().setAttributes(lp);
              }
          }
      }
  
      @Override
      public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
          boolean wasRotationEnabled = mAutoRotateEnabled;
          mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
                  getAllowRotationDefaultValue());
          if (mAutoRotateEnabled != wasRotationEnabled) {
  
              notifyChange();
              updateRotationAnimation();
              mLauncher.reapplyUi();
          }
      }
  
      public void setStateHandlerRequest(int request) {
          if (mStateHandlerRequest != request) {
              mStateHandlerRequest = request;
              updateRotationAnimation();
              notifyChange();
          }
      }
  
      public void setCurrentTransitionRequest(int request) {
          if (mCurrentTransitionRequest != request) {
              mCurrentTransitionRequest = request;
              notifyChange();
          }
      }
  
      public void setCurrentStateRequest(int request) {
          if (mCurrentStateRequest != request) {
              mCurrentStateRequest = request;
              notifyChange();
          }
      }
  
      // Used by tests only.
      public void forceAllowRotationForTesting(boolean allowRotation) {
          mIgnoreAutoRotateSettings =
                  allowRotation || mLauncher.getResources().getBoolean(R.bool.allow_rotation);
          notifyChange();
      }
  
      public void initialize() {
          if (!mInitialized) {
              mInitialized = true;
              notifyChange();
              updateRotationAnimation();
          }
      }
  
      public void destroy() {
          if (!mDestroyed) {
              mDestroyed = true;
              if (mPrefs != null) {
                  mPrefs.unregisterOnSharedPreferenceChangeListener(this);
              }
          }
      }
  
      private void notifyChange() {
          if (!mInitialized || mDestroyed) {
              return;
          }
  
          final int activityFlags;
          if (mStateHandlerRequest != REQUEST_NONE) {
              activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
                      SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
          } else if (mCurrentTransitionRequest != REQUEST_NONE) {
              activityFlags = mCurrentTransitionRequest == REQUEST_LOCK ?
                      SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
          } else if (mCurrentStateRequest == REQUEST_LOCK) {
              activityFlags = SCREEN_ORIENTATION_LOCKED;
          } else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE
                  || mAutoRotateEnabled) {
              activityFlags = SCREEN_ORIENTATION_UNSPECIFIED;
          } else {
              // If auto rotation is off, allow rotation on the activity, in case the user is using
              // forced rotation.
              activityFlags = SCREEN_ORIENTATION_NOSENSOR;
          }
          if (activityFlags != mLastActivityFlags) {
              mLastActivityFlags = activityFlags;
              UiThreadHelper.setOrientationAsync(mLauncher, activityFlags);
          }
      }
  
      @Override
      public String toString() {
          return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
                  + " mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, mAutoRotateEnabled=%b]",
                  mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags,
                  mIgnoreAutoRotateSettings, mAutoRotateEnabled);
      }
  }
  