Android11系统强制APP横竖屏四个方向

实现步骤 

强制应用旋转功能可以让用户强制所有应用以横屏或竖屏的方式显示,无论应用本身是否支持旋转,包括 竖屏、横屏、反向竖屏和反向横屏。

修改代码

frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

updateOrientation()

       if (newOrientation != mCurrentAppOrientation) {
            mCurrentAppOrientation = newOrientation;
            String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");
            /**
             * 在rotationForOrientation()和updateOrientation()方法中,
             * 需要根据persist.sys.app.rotation的值来修改当前应用的方向,
             * 如果是force_landscape,则强制为横屏;
             * 如果是force_portrait,则强制为竖屏; 
			 * 如果是force_reverse_landscape,则强制为反向横屏;
             * 如果是force_reverse_portrait,则强制为反向竖屏;
             */
            Slog.d(TAG, "-----updateOrientation-----rot:" + rot);
            if (rot.equals("force_landscape")) {
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
            } else if (rot.equals("force_portrait")) {
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
            } else if (rot.equals("force_reverse_landscape")) {
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
            } else if (rot.equals("force_reverse_portrait")) {
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
            }
            if (rot.equals("force_land") && "box".equals(SystemProperties.get("ro.target.product")))
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
            if (isDefaultDisplay) {
            Slog.v(TAG, "asx force_land :" + mLandscapeRotation);
            return mLandscapeRotation;
        }
        

 rotationForOrientation()


        String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");
        if (rot.equals("force_land") && "box".equals(SystemProperties.get("ro.target.product"))) {
            Slog.v(TAG, "asx force_land :" + mLandscapeRotation);
            return mLandscapeRotation;
        }
        Slog.d(TAG, "----rotationForOrientation-------rot :" + rot);
        Slog.d(TAG, "----rotationForOrientation-------orientation :" + orientation);
        if (rot.equals("force_landscape")) {
            return mLandscapeRotation;
        } else if (rot.equals("force_portrait")) {
            return mPortraitRotation;
        } else if (rot.equals("force_reverse_landscape")) {
            return mSeascapeRotation;
        } else if (rot.equals("force_reverse_portrait")) {
            return mUpsideDownRotation;
        }
        Slog.d(TAG, "----rotationForOrientation-------back");
        switch (orientation) {
            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
                // Return portrait unless overridden.
                if (isAnyPortrait(preferredRotation)) {
                    return preferredRotation;

 packages/apps/Settings/res/values-zh-rCN/strings.xml

   <!--APP旋转 -->
   <string name="forceapp_rotate_summary"> <xliff:g id="forceapprotate_description">%1$s</xliff:g> </string>
    <string name="ctrl_forceapp_rotate" >"APP旋转"</string>

packages/apps/Settings/res/values/arrays.xml

     <!-- app 方向旋转-->
    <string-array name="forceapp_rotate_entries">
        <item>默认</item>
        <item>竖屏</item>
        <item>横屏</item>
        <item>反向竖屏</item>
        <item>反向横屏</item>
    </string-array>

    <!--app 方向旋转 translate. -->
    <string-array name="forceapp_rotate_values" translatable="false">
        <!-- 默认 -->
        <item>0</item>
        <!-- 竖屏 -->
        <item>1</item>
        <!-- 横屏-->
        <item>2</item>
        <!-- 反向竖屏 -->
        <item>3</item>
        <!-- 反向横屏-->
        <item>4</item>
    </string-array>

packages/apps/Settings/res/values/strings.xml

   <!--App旋转 -->
    <string name="forceapp_rotate_summary"> <xliff:g id="forceapprotate_description">%1$s</xliff:g> </string>
    <string name="ctrl_forceapp_rotate" >"Force App Rotate"</string>

packages/apps/Settings/res/xml/display_settings.xml

<com.android.settings.display.ForceAppRotateListPreference 
    android:key="forceapp_rotate"
    android:title="@string/ctrl_forceapp_rotate"
    android:summary="@string/summary_placeholder"
    android:entries="@array/forceapp_rotate_entries"
    android:entryValues="@array/forceapp_rotate_values"/>

packages/apps/Settings/src/com/android/settings/DisplaySettings.java

import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
 
import com.android.settings.display.ForceAppRotatePreferenceController;
import com.android.settings.display.ScreenRotatePreferenceController;
import java.util.ArrayList;
import java.util.List;
 
        controllers.add(new ThemePreferenceController(context));
        controllers.add(new BrightnessLevelPreferenceController(context, lifecycle));
        controllers.add(new HdmiSettingsPreferenceController(context, KET_HDMI_SETTINGS));
        controllers.add(new ForceAppRotatePreferenceController(context,"forceapp_rotate"));
        return controllers;
    }

packages/apps/Settings/src/com/android/settings/display/ForceAppRotateListPreference.java

package com.android.settings.display;

import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;

import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;

import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.core.AbstractPreferenceController;
import android.app.Dialog;
import java.util.ArrayList;
import android.view.View;
import androidx.appcompat.app.AlertDialog;

import android.util.AttributeSet;
import com.android.settings.R;
import com.android.settings.RestrictedListPreference;
import android.content.DialogInterface;
/**
 * 
 * 定义了强制应用旋转的列表偏好类,需要在其中实现以下功能:
  *  继承RestrictedListPreference类,并在构造方法中初始化初始的选项和值。
  *  重写onPrepareDialogBuilder()方法,在对话框中添加管理员限制的视图,如果有的话。
   * 重写onDialogCreated()方法,在对话框中添加管理员限制的点击事件,如果有的话。
  *  定义一个removeUnusableRotates()方法,用于移除不可用的选项,并根据管理员限制来禁用或启用偏好。
 */
public class ForceAppRotateListPreference extends RestrictedListPreference {
    private EnforcedAdmin mAdmin;
    private final CharSequence[] mInitialEntries;
    private final CharSequence[] mInitialValues;

    public ForceAppRotateListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        mInitialEntries = getEntries();
        mInitialValues = getEntryValues();
    }

    @Override
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
                                          DialogInterface.OnClickListener listener) {
        super.onPrepareDialogBuilder(builder, listener);
        if (mAdmin != null) {
            builder.setView(R.layout.admin_disabled_other_options_footer);
        } else {
            builder.setView(null);
        }
    }


    @Override
    protected void onDialogCreated(Dialog dialog) {
        super.onDialogCreated(dialog);
        dialog.create();
        if (mAdmin != null) {
            View footerView = dialog.findViewById(R.id.admin_disabled_other_options);
            footerView.findViewById(R.id.admin_more_details_link).setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                           // getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
                                    getContext(), mAdmin);
                        }
                    });
        }
    }

    public void removeUnusableRotates(long maxRotate, EnforcedAdmin admin) {
        final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
                Context.DEVICE_POLICY_SERVICE);
        if (dpm == null) {
            return;
        }

        if (admin == null && mAdmin == null && !isDisabledByAdmin()) {
            return;
        }
        if (admin == null) {
            maxRotate = Long.MAX_VALUE;
        }

        ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
        ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
        for (int i = 0; i < mInitialValues.length; ++i) {
            long rotate = Long.parseLong(mInitialValues[i].toString());
            if (rotate <= maxRotate) {
                revisedEntries.add(mInitialEntries[i]);
                revisedValues.add(mInitialValues[i]);
            }
        }

        // If there are no possible options for the user, then set this preference as disabled
        // by admin, otherwise remove the padlock in case it was set earlier.
        if (revisedValues.size() == 0) {
            setDisabledByAdmin(admin);
            return;
        } else {
            setDisabledByAdmin(null);
        }

        if (revisedEntries.size() != getEntries().length) {
            final int userPreference = Integer.parseInt(getValue());
            setEntries(revisedEntries.toArray(new CharSequence[0]));
            setEntryValues(revisedValues.toArray(new CharSequence[0]));
            mAdmin = admin;
            if (userPreference <= maxRotate) {
                setValue(String.valueOf(userPreference));
            } else if (revisedValues.size() > 0
                    && Long.parseLong(revisedValues.get(revisedValues.size() - 1).toString())
                            == maxRotate) {
                // If the last one happens to be the same as the max rotate, select that
                setValue(String.valueOf(maxRotate));
            } else {
                // There will be no highlighted selection since nothing in the list matches
                // maxRotate. The user can still select anything less than maxRotate.
                // TODO: maybe append maxRotate to the list and mark selected.
            }
        }
    }
}

packages/apps/Settings/src/com/android/settings/display/ForceAppRotatePreferenceController.java

package com.android.settings.display;

import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import android.content.Intent;
import android.util.Log;
import com.android.settings.R;
import android.os.SystemProperties;

/**
 * 定义了强制应用旋转的偏好控制器类,需要在其中实现以下功能:
 * 继承AbstractPreferenceController类,并实现Preference.OnPreferenceChangeListener接口,用于处理偏好变化的事件。
 * 在构造方法中初始化键值和上下文。
 * 在isAvailable()方法中返回true,表示该控制器可用。
 * 在getPreferenceKey()方法中返回键值。
 * 在updateState()方法中根据系统属性persist.sys.app.rotation的值来更新偏好的选项和摘要。
 * 在onPreferenceChange()方法中根据用户选择的值来修改系统属性persist.sys.app.rotation,并更新偏好的摘要。
 * 定义一个getRotateDescription()方法,用于根据当前的值和选项列表来获取对应的描述。
 */
public class ForceAppRotatePreferenceController extends AbstractPreferenceController implements
        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {

    private static final String TAG = "ForceAppRotatePrefContr";

    /** If there is no setting in the provider, use this. */
    public static final int FALLBACK_FORCE_APP_ROTATE_VALUE = 0;

    private final String mForceAppRotateKey;

    public ForceAppRotatePreferenceController(Context context, String key) {
        super(context);
        mForceAppRotateKey = key;
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public String getPreferenceKey() {
        return mForceAppRotateKey;
    }

    @Override
    public void updateState(Preference preference) {
        final ForceAppRotateListPreference forceAppRotateListPreference = (ForceAppRotateListPreference) preference;
        String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");
        Log.d(TAG, "--------updateState------------rot:" + rot);
        long currentRotate = 0;
        if (rot.equals("force_landscape")) {
            currentRotate = 2;
        } else if (rot.equals("force_portrait")) {
            currentRotate = 1;
        } else if (rot.equals("force_reverse_portrait")) {
            currentRotate = 3;
        } else if (rot.equals("force_reverse_landscape")) {
            currentRotate = 4;
        } else {
            currentRotate = 0;
        }
        Log.d(TAG, "--------updateState------------currentRotate:" + currentRotate);
        forceAppRotateListPreference.setValue(String.valueOf(currentRotate));
        updateRotatePreferenceDescription(forceAppRotateListPreference, currentRotate);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        try {
            int value = Integer.parseInt((String) newValue);
            if (value == 0) {
                SystemProperties.set("persist.sys.app.rotation", "");
            } else if (value == 1) {
                SystemProperties.set("persist.sys.app.rotation", "force_portrait");
            } else if (value == 2) {
                SystemProperties.set("persist.sys.app.rotation", "force_landscape");
            } else if (value == 3) {
                SystemProperties.set("persist.sys.app.rotation", "force_reverse_portrait");
            } else if (value == 4) {
                SystemProperties.set("persist.sys.app.rotation", "force_reverse_landscape");
            }
            Log.d(TAG, "--------onPreferenceChange------------value:" + String.valueOf(value));
            // Settings.System.putInt(mContext.getContentResolver(), "FORCE_APP_ROTATION",
            // value);
            updateRotatePreferenceDescription((ForceAppRotateListPreference) preference, value);
        } catch (NumberFormatException e) {
            Log.e(TAG, "could not persist force app rotate setting", e);
        }
        return true;
    }

    public static CharSequence getRotateDescription(
            long currentRotate, CharSequence[] entries, CharSequence[] values) {
        if (currentRotate < 0 || entries == null || values == null
                || values.length != entries.length) {
            return null;
        }

        for (int i = 0; i < values.length; i++) {
            long rotate = Long.parseLong(values[i].toString());
            if (currentRotate == rotate) {
                return entries[i];
            }
        }
        return null;
    }

    private void updateRotatePreferenceDescription(ForceAppRotateListPreference preference,
            long currentRotate) {
        final CharSequence[] entries = preference.getEntries();
        final CharSequence[] values = preference.getEntryValues();
        final String summary;

        if (preference.isDisabledByAdmin()) {
            summary = mContext.getString(com.android.settings.R.string.disabled_by_policy_title);
        } else {
            final CharSequence rotateDescription = getRotateDescription(
                    currentRotate, entries, values);
            summary = rotateDescription == null
                    ? ""
                    : mContext.getString(R.string.forceapp_rotate_summary, rotateDescription);
        }
        Log.d(TAG, "--------updateRotatePreferenceDescription------------summary:" + summary);
        preference.setSummary(summary);
    }
}

 效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值