Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79578b29 authored by Svetoslav's avatar Svetoslav
Browse files

Remove Auto-rotate screen setting if a required feature is missing.

It is possible that a device running Android does not support rotation,
for example a Google TV box. The change adds a check to the rotation
policy to take this into account.

The SystemUI was not respecting the fact that the user has turned off
screen rotation, i.e. locked the rotation, from the accessibility
settings. In this case we should not show the affordance to toggle
screen rotation in the quick settings to minimize the risk of a blind
user accidentally turning screen rotation on. For a blind person
screen rotation adds 2X complexity since he/she should learn two
different layouts for the app.

bug:8051556

Change-Id: If1b3c092476932f91b0345fb9bfbbf6ed33d0df9
parent f1301d86
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -17,12 +17,13 @@
package com.android.internal.view;

import android.content.Context;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -39,6 +40,21 @@ public final class RotationPolicy {
    private RotationPolicy() {
    }

    /**
     * Gets whether the device supports rotation. In general such a
     * device has an accelerometer and has the portrait and landscape
     * features.
     *
     * @param context Context for accessing system resources.
     * @return Whether the device supports rotation.
     */
    public static boolean isRotationSupported(Context context) {
        PackageManager pm = context.getPackageManager();
        return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)
                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT)
                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE);
    }

    /**
     * Returns true if the device supports the rotation-lock toggle feature
     * in the system UI or system bar.
@@ -48,7 +64,8 @@ public final class RotationPolicy {
     * settings.
     */
    public static boolean isRotationLockToggleSupported(Context context) {
        return context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
        return isRotationSupported(context)
                && context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
    }

    /**
+0 −60
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.systemui.statusbar;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.CompoundButton;

import com.android.systemui.statusbar.policy.AutoRotateController;

public class RotationToggle extends CompoundButton
        implements AutoRotateController.RotationLockCallbacks {
    private AutoRotateController mRotater;

    public RotationToggle(Context context) {
        super(context);
    }

    public RotationToggle(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RotationToggle(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mRotater = new AutoRotateController(getContext(), this, this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mRotater != null) {
            mRotater.release();
            mRotater = null;
        }
    }

    @Override
    public void setRotationLockControlVisibility(boolean show) {
        setVisibility(show ? VISIBLE : GONE);
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.DateView;
@@ -157,6 +158,7 @@ public class PhoneStatusBar extends BaseStatusBar {
    BatteryController mBatteryController;
    LocationController mLocationController;
    NetworkController mNetworkController;
    RotationLockController mRotationLockController;

    int mNaturalBarHeight = -1;
    int mIconSize = -1;
@@ -501,6 +503,7 @@ public class PhoneStatusBar extends BaseStatusBar {
        mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
        mNetworkController = new NetworkController(mContext);
        mBluetoothController = new BluetoothController(mContext);
        mRotationLockController = new RotationLockController(mContext);
        final SignalClusterView signalCluster =
                (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);

@@ -589,7 +592,7 @@ public class PhoneStatusBar extends BaseStatusBar {
                mQS.setService(this);
                mQS.setBar(mStatusBarView);
                mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
                        mLocationController);
                        mLocationController, mRotationLockController);
            } else {
                mQS = null; // fly away, be free
            }
+27 −18
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.statusbar.phone;

import com.android.internal.view.RotationPolicy;
import com.android.systemui.R;

import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
@@ -28,6 +27,7 @@ import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RotationLockController;

import android.app.ActivityManagerNative;
import android.app.AlertDialog;
@@ -73,7 +73,6 @@ import android.widget.TextView;

import java.util.ArrayList;


/**
 *
 */
@@ -97,6 +96,7 @@ class QuickSettings {
    private WifiManager mWifiManager;

    private BluetoothController mBluetoothController;
    private RotationLockController mRotationLockController;

    private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;

@@ -113,14 +113,6 @@ class QuickSettings {
    private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
            new ArrayList<QuickSettingsTileView>();

    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
            new RotationPolicy.RotationPolicyListener() {
        @Override
        public void onChange() {
            mModel.onRotationLockChanged();
        }
    };

    public QuickSettings(Context context, QuickSettingsContainerView container) {
        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
        mContext = context;
@@ -170,8 +162,10 @@ class QuickSettings {
    }

    void setup(NetworkController networkController, BluetoothController bluetoothController,
            BatteryController batteryController, LocationController locationController) {
            BatteryController batteryController, LocationController locationController,
            RotationLockController rotationLockController) {
        mBluetoothController = bluetoothController;
        mRotationLockController = rotationLockController;

        setupQuickSettings();
        updateWifiDisplayStatus();
@@ -181,8 +175,7 @@ class QuickSettings {
        bluetoothController.addStateChangedCallback(mModel);
        batteryController.addStateChangedCallback(mModel);
        locationController.addStateChangedCallback(mModel);
        RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
                UserHandle.USER_ALL);
        rotationLockController.addRotationLockControllerCallback(mModel);
    }

    private void queryForUserInformation() {
@@ -471,13 +464,29 @@ class QuickSettings {
                    = new QuickSettingsBasicTile(mContext);
            rotationLockTile.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    boolean locked = RotationPolicy.isRotationLocked(mContext);
                    RotationPolicy.setRotationLock(mContext, !locked);
                public void onClick(View view) {
                    final boolean locked = mRotationLockController.isRotationLocked();
                    mRotationLockController.setRotationLocked(!locked);
                }
            });
            mModel.addRotationLockTile(rotationLockTile, mRotationLockController,
                    new QuickSettingsModel.RefreshCallback() {
                        @Override
                        public void refreshView(QuickSettingsTileView view, State state) {
                            QuickSettingsModel.RotationLockState rotationLockState =
                                    (QuickSettingsModel.RotationLockState) state;
                            view.setVisibility(rotationLockState.visible
                                    ? View.VISIBLE : View.GONE);
                            if (state.iconId != 0) {
                                // needed to flush any cached IDs
                                rotationLockTile.setImageDrawable(null);
                                rotationLockTile.setImageResource(state.iconId);
                            }
                            if (state.label != null) {
                                rotationLockTile.setText(state.label);
                            }
                        }
                    });
            mModel.addRotationLockTile(rotationLockTile,
                    new QuickSettingsModel.BasicRefreshCallback(rotationLockTile));
            parent.addView(rotationLockTile);
        }

+24 −14
Original line number Diff line number Diff line
@@ -39,22 +39,23 @@ import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;

import com.android.internal.view.RotationPolicy;
import com.android.systemui.R;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;

import java.util.List;


class QuickSettingsModel implements BluetoothStateChangeCallback,
        NetworkSignalChangedCallback,
        BatteryStateChangeCallback,
        LocationGpsStateChangeCallback,
        BrightnessStateChangeCallback {
        BrightnessStateChangeCallback,
        RotationLockControllerCallback {

    // Sett InputMethoManagerService
    private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
@@ -89,6 +90,9 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
        boolean connected = false;
        String stateContentDescription;
    }
    public static class RotationLockState extends State {
        boolean visible = false;
    }

    /** The callback to update a given tile. */
    interface RefreshCallback {
@@ -245,7 +249,7 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,

    private QuickSettingsTileView mRotationLockTile;
    private RefreshCallback mRotationLockCallback;
    private State mRotationLockState = new State();
    private RotationLockState mRotationLockState = new RotationLockState();

    private QuickSettingsTileView mBrightnessTile;
    private RefreshCallback mBrightnessCallback;
@@ -259,6 +263,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
    private RefreshCallback mSettingsCallback;
    private State mSettingsState = new State();

    private RotationLockController mRotationLockController;

    public QuickSettingsModel(Context context) {
        mContext = context;
        mHandler = new Handler();
@@ -681,26 +687,30 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
    }

    // Rotation lock
    void addRotationLockTile(QuickSettingsTileView view, RefreshCallback cb) {
    void addRotationLockTile(QuickSettingsTileView view,
            RotationLockController rotationLockController,
            RefreshCallback cb) {
        mRotationLockTile = view;
        mRotationLockCallback = cb;
        mRotationLockController = rotationLockController;
        onRotationLockChanged();
    }
    void onRotationLockChanged() {
        boolean locked = RotationPolicy.isRotationLocked(mContext);
        mRotationLockState.enabled = locked;
        mRotationLockState.iconId = locked
        onRotationLockStateChanged(mRotationLockController.isRotationLocked(),
                mRotationLockController.isRotationLockAffordanceVisible());
    }
    @Override
    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
        mRotationLockState.visible = affordanceVisible;
        mRotationLockState.enabled = rotationLocked;
        mRotationLockState.iconId = rotationLocked
                ? R.drawable.ic_qs_rotation_locked
                : R.drawable.ic_qs_auto_rotate;
        mRotationLockState.label = locked
        mRotationLockState.label = rotationLocked
                ? mContext.getString(R.string.quick_settings_rotation_locked_label)
                : mContext.getString(R.string.quick_settings_rotation_unlocked_label);

        // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
        if (mRotationLockTile != null && mRotationLockCallback != null) {
        mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
    }
    }
    void refreshRotationLockTile() {
        if (mRotationLockTile != null) {
            onRotationLockChanged();
Loading