Android系统 添加动态控制屏幕方向、强制APP横竖屏方向

简介: Android系统 添加动态控制屏幕方向、强制APP横竖屏方向

实现步骤

  • 屏幕旋转功能可以让用户选择屏幕的默认方向,包括0度(竖屏)、90度(横屏)、180度(反向竖屏)和270度(反向横屏)。
  • 强制应用旋转功能可以让用户强制所有应用以横屏或竖屏的方式显示,无论应用本身是否支持旋转。
  • 修改都支持重启后保存哦,强制APP旋转优先级>系统方向优先级。

修改示例

DisplayRotation模块

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

这个模块负责处理屏幕旋转的逻辑,需要在其中添加1个系统属性:persist.sys.app.rotation,分别用于控制强制应用旋转和屏幕旋转的设置。

在rotationForOrientation()和updateOrientation()方法中,需要根据persist.sys.app.rotation的值来修改当前应用的方向,如果是force_landscape,则强制为横屏;如果是force_portrait,则强制为竖屏;否则按照应用本身的方向设置。

+++ b/frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -380,6 +380,12 @@ public class DisplayRotation {
         if (newOrientation != mCurrentAppOrientation) {
             mCurrentAppOrientation = newOrientation;
             String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");
+            if (rot.equals("force_landscape")){
+                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+            }else if (rot.equals("force_portrait")){
+                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+                
+            }
             if (rot.equals("force_land") && "box".equals(SystemProperties.get("ro.target.product")))
                 mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
             if (isDefaultDisplay) {
@@ -1204,6 +1210,13 @@ public class DisplayRotation {
             Slog.v(TAG, "asx force_land :" + mLandscapeRotation);
             return mLandscapeRotation;
         }
+        
+        if (rot.equals("force_landscape")){
+            return mLandscapeRotation;
+        }else if (rot.equals("force_portrait")){
+            return mPortraitRotation;
+        }
+        
         switch (orientation) {
             case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
                 // Return portrait unless overridden.

Settings模块

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

这个文件定义了屏幕旋转和强制应用旋转的选项列表,需要在其中添加两个数组:screen_rotate_entries和screen_rotate_values,以及forceapp_rotate_entries和forceapp_rotate_values。

screen_rotate_entries和screen_rotate_values分别表示屏幕旋转的显示名称和对应的值,包括0度、90度、180度和270度。

  • forceapp_rotate_entries和forceapp_rotate_values分别表示强制应用旋转的显示名称和对应的值,包括默认、横屏和竖屏。
+++ b/packages/apps/Settings/res/values-zh-rCN/arrays.xml
@@ -20,6 +20,45 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    
+ 
+    <string-array name="screen_totate_entries">
+        <item>0 Degree</item>
+        <item>90 Degree</item>
+        <item>180 Degree</item>
+        <item>270 Degree</item>
+    </string-array>
+
+    <!-- Do not translate. -->
+    <string-array name="screen_rotate_values" translatable="false">
+        <!-- Do not translate. -->
+        <item>0</item>
+        <!-- Do not translate. -->
+        <item>1</item>
+        <!-- Do not translate. -->
+        <item>2</item>
+        <!-- Do not translate. -->
+        <item>3</item>
+    </string-array>
+    
+         <string-array name="forceapp_rotate_entries">
+        <item>default</item>
+        <item>portrait</item>
+        <item>landscape</item>
+
+  
+    </string-array>
+
+    <!-- Do not translate. -->
+    <string-array name="forceapp_rotate_values" translatable="false">
+        <!-- Do not translate. -->
+        <item>0</item>
+        <!-- Do not translate. -->
+        <item>1</item>
+        <!-- Do not translate. -->
+        <item>2</item>
+
+    </string-array>
packages/apps/Settings/res/values/strings.xml

这个文件定义了英文版的字符串资源,需要在其中添加屏幕旋转和强制应用旋转的标题和摘要,以及对应的格式化字符串

+++ b/packages/apps/Settings/res/values/strings.xml
@@ -14,6 +14,10 @@
      limitations under the License.
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="forceapp_rotate_summary"> <xliff:g id="forceapprotate_description">%1$s</xliff:g> </string>
+    <string name="screen_rotate_summary"> <xliff:g id="screenrotate_description">%1$s</xliff:g> </string>
+    <string name="ctrl_forceapp_rotate" >"Force App Rotate"</string>
+    <string name="ctrl_screen_rotate">"Screen Rotate"</string>
     <string name="ctrl_statusbar">StatusBar</string>
     <string name="ctrl_explan">ExPlan</string>
     <string name="ctrl_navigationbar">NavigationBar</string>
packages/apps/Settings/res/values-zh-rCN/strings.xml

这个文件定义了中文版的字符串资源,需要在其中添加屏幕旋转和强制应用旋转的标题和摘要,以及对应的格式化字符串。

+++ b/packages/apps/Settings/res/values-zh-rCN/strings.xml
@@ -16,6 +16,10 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="forceapp_rotate_summary"> <xliff:g id="forceapprotate_description">%1$s</xliff:g> </string>
+    <string name="screen_rotate_summary"> <xliff:g id="screenrotate_description">%1$s</xliff:g> </string>
+    <string name="ctrl_forceapp_rotate" >"APP旋转"</string>
+    <string name="ctrl_screen_rotate">"屏幕旋转"</string>
     <string name="ctrl_statusbar">状态栏</string>
     <string name="ctrl_explan">下拉菜单</string>
     <string name="ctrl_navigationbar">导航栏</string>
packages/apps/Settings/res/xml/display_settings.xml

这个文件定义了显示设置的界面布局,添加屏幕旋转和强制应用旋转的列表偏好,以及对应的键值、标题、摘要和选项。

我们使用自定义的ScreenRotateListPreference和ForceAppRotateListPreference类来实现列表偏好的功能,这两个类继承了RestrictedListPreference类,并重写了一些方法来处理管理员限制和对话框显示。

+++ b/packages/apps/Settings/res/xml/display_settings.xml
@@ -31,7 +31,18 @@
    <SwitchPreference
        android:key="ctrl_explan"
        android:title="@string/ctrl_explan"/>
-       
+   <com.android.settings.display.ScreenRotateListPreference
+        android:key="screen_rotate"
+        android:title="@string/ctrl_screen_rotate"
+        android:summary="@string/summary_placeholder"
+        android:entries="@array/screen_rotate_entries"
+        android:entryValues="@array/screen_rotate_values"/>
+   <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"/>
     <com.android.settingslib.RestrictedPreference
         android:key="brightness"
         android:title="@string/brightness"
packages/apps/Settings/src/com/android/settings/DisplaySettings.java

这个文件定义了显示设置的控制器,我们需要在其中添加屏幕旋转和强制应用旋转的偏好控制器,以及对应的键值和上下文。

使用自定义的ScreenRotatePreferenceController和ForceAppRotatePreferenceController类来实现偏好控制器的功能,这两个类继承了AbstractPreferenceController类,并实现了Preference.OnPreferenceChangeListener接口,用于处理偏好变化的事件。

+++ b/packages/apps/Settings/src/com/android/settings/DisplaySettings.java
@@ -40,6 +40,8 @@ import com.android.settingslib.search.SearchIndexable;
 import com.android.settings.display.StatusBarPreferenceController;
 import com.android.settings.display.NavigationBarPreferenceController;
 import com.android.settings.display.ExPlanPreferenceController;
+import com.android.settings.display.ForceAppRotatePreferenceController;
+import com.android.settings.display.ScreenRotatePreferenceController;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -98,6 +100,8 @@ public class DisplaySettings extends DashboardFragment {
         controllers.add(new StatusBarPreferenceController(context));
         controllers.add(new NavigationBarPreferenceController(context));
         controllers.add(new ExPlanPreferenceController(context));
+        controllers.add(new ForceAppRotatePreferenceController(context,"forceapp_rotate"));
+        controllers.add(new ScreenRotatePreferenceController(context,"screen_rotate"));
         return controllers;
     }
packages/apps/Settings/src/com/android/settings/display/ScreenRotateListPreference.java
  • 这个文件定义了屏幕旋转的列表偏好类,需要在其中实现以下功能:
  • 继承RestrictedListPreference类,并在构造方法中初始化初始的选项和值。
  • 重写onPrepareDialogBuilder()方法,在对话框中添加管理员限制的视图,如果有的话。
  • 重写onDialogCreated()方法,在对话框中添加管理员限制的点击事件,如果有的话。
  • 定义一个removeUnusableRotates()方法,用于移除不可用的选项,并根据管理员限制来禁用或启用偏好。
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;
public class ScreenRotatePreferenceController extends AbstractPreferenceController implements
        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
    private static final String TAG = "ScreenRotatePrefContr";
    /** If there is no setting in the provider, use this. */
    public static final int FALLBACK_SCREEN_ROTATE_VALUE = 0;
    private final String mScreenRotateKey;
    public ScreenRotatePreferenceController(Context context, String key) {
        super(context);
        mScreenRotateKey = key;
    }
    @Override
    public boolean isAvailable() {
        return true;
    }
    @Override
    public String getPreferenceKey() {
        return mScreenRotateKey;
    }
    @Override
    public void updateState(Preference preference) {
        final ScreenRotateListPreference screenRotateListPreference = (ScreenRotateListPreference) preference;
        long currentRotate = Settings.System.getLong(mContext.getContentResolver(),
                Settings.System.USER_ROTATION, FALLBACK_SCREEN_ROTATE_VALUE);
        screenRotateListPreference.setValue(String.valueOf(currentRotate));
        updateRotatePreferenceDescription(screenRotateListPreference, currentRotate);
    }
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        try {
            int value = Integer.parseInt((String) newValue);
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, value);
            updateRotatePreferenceDescription((ScreenRotateListPreference) preference, value);
        } catch (NumberFormatException e) {
            Log.e(TAG, "could not persist screen 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(ScreenRotateListPreference 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.screen_rotate_summary, rotateDescription);
        }
        preference.setSummary(summary);
    }
}
packages/apps/Settings/src/com/android/settings/display/ForceAppRotateListPreference.java
  • 这个文件定义了强制应用旋转的列表偏好类,需要在其中实现以下功能:
  • 继承RestrictedListPreference类,并在构造方法中初始化初始的选项和值。
  • 重写onPrepareDialogBuilder()方法,在对话框中添加管理员限制的视图,如果有的话。
  • 重写onDialogCreated()方法,在对话框中添加管理员限制的点击事件,如果有的话。
  • 定义一个removeUnusableRotates()方法,用于移除不可用的选项,并根据管理员限制来禁用或启用偏好。
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;
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
  • 这个文件定义了强制应用旋转的偏好控制器类,需要在其中实现以下功能:
  • 继承AbstractPreferenceController类,并实现Preference.OnPreferenceChangeListener接口,用于处理偏好变化的事件。
  • 在构造方法中初始化键值和上下文。
  • 在isAvailable()方法中返回true,表示该控制器可用。
  • 在getPreferenceKey()方法中返回键值。
  • 在updateState()方法中根据系统属性persist.sys.app.rotation的值来更新偏好的选项和摘要。
  • 在onPreferenceChange()方法中根据用户选择的值来修改系统属性persist.sys.app.rotation,并更新偏好的摘要。
  • 定义一个getRotateDescription()方法,用于根据当前的值和选项列表来获取对应的描述。
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;
public class ScreenRotatePreferenceController extends AbstractPreferenceController implements
        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
    private static final String TAG = "ScreenRotatePrefContr";
    /** If there is no setting in the provider, use this. */
    public static final int FALLBACK_SCREEN_ROTATE_VALUE = 0;
    private final String mScreenRotateKey;
    public ScreenRotatePreferenceController(Context context, String key) {
        super(context);
        mScreenRotateKey = key;
    }
    @Override
    public boolean isAvailable() {
        return true;
    }
    @Override
    public String getPreferenceKey() {
        return mScreenRotateKey;
    }
    @Override
    public void updateState(Preference preference) {
        final ScreenRotateListPreference screenRotateListPreference = (ScreenRotateListPreference) preference;
        long currentRotate = Settings.System.getLong(mContext.getContentResolver(),
                Settings.System.USER_ROTATION, FALLBACK_SCREEN_ROTATE_VALUE);
        screenRotateListPreference.setValue(String.valueOf(currentRotate));
        updateRotatePreferenceDescription(screenRotateListPreference, currentRotate);
    }
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        try {
            int value = Integer.parseInt((String) newValue);
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, value);
            updateRotatePreferenceDescription((ScreenRotateListPreference) preference, value);
        } catch (NumberFormatException e) {
            Log.e(TAG, "could not persist screen 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(ScreenRotateListPreference 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.screen_rotate_summary, rotateDescription);
        }
        preference.setSummary(summary);
    }
}
packages/apps/Settings/src/com/android/settings/display/ScreenRotateListPreference.java
  • 这个文件定义了屏幕旋转的列表偏好类,需要在其中实现以下功能:
  • 继承RestrictedListPreference类,并在构造方法中初始化初始的选项和值。
  • 重写onPrepareDialogBuilder()方法,在对话框中添加管理员限制的视图,如果有的话。
  • 重写onDialogCreated()方法,在对话框中添加管理员限制的点击事件,如果有的话。
  • 定义一个removeUnusableRotates()方法,用于移除不可用的选项,并根据管理员限制来禁用或启用偏好。
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;
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;
        long currentRotate = 0;
        String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");
        if (rot.equals("force_landscape")){
            currentRotate = 1;
        }else if (rot.equals("force_portrait")){
            currentRotate = 2;
        }else{
            currentRotate = 0;
        }
        
        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");
            }
            //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);
        }
        preference.setSummary(summary);
    }
}

OK 到这里就全部添加完成 没有难度~

其他记录:

  1. 比如ForceAppRotateListPreference文件为什么要新建这个东西? 早期版本没这么麻烦
  2. 有个坑xxxListPreference里面的AlertDialog11+版本要用androidx.appcompat.app.AlertDialog; 不能用早期版本的 , 如果同时导入2个包 会一直编译报错 只需保留一个就可以。

测试效果:

不管应用是否支持竖屏 , 都会被强制竖屏。

总结:

本文介绍了如何在Android系统Settings中添加屏幕旋转和强制App应用旋转的功能,以便客户可以根据项目需求调整屏幕方向

相关文章
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
60 15
Android 系统缓存扫描与清理方法分析
|
24天前
|
算法 JavaScript Android开发
|
26天前
|
安全 搜索推荐 Android开发
揭秘安卓与iOS系统的差异:技术深度对比
【10月更文挑战第27天】 本文深入探讨了安卓(Android)与iOS两大移动操作系统的技术特点和用户体验差异。通过对比两者的系统架构、应用生态、用户界面、安全性等方面,揭示了为何这两种系统能够在市场中各占一席之地,并为用户提供不同的选择。文章旨在为读者提供一个全面的视角,理解两种系统的优势与局限,从而更好地根据自己的需求做出选择。
68 2
|
28天前
|
小程序 数据挖掘 UED
开发1个上门家政小程序APP系统,都有哪些功能?
在快节奏的现代生活中,家政服务已成为许多家庭的必需品。针对传统家政服务存在的问题,如服务质量不稳定、价格不透明等,我们历时两年开发了一套全新的上门家政系统。该系统通过完善信用体系、提供奖励机制、优化复购体验、多渠道推广和多样化盈利模式,解决了私单、复购、推广和盈利四大痛点,全面提升了服务质量和用户体验,旨在成为家政行业的领导者。
|
2月前
|
安全 搜索推荐 Android开发
深入探索安卓与iOS系统的差异及其对用户体验的影响
在当今的智能手机市场中,安卓和iOS是两大主流操作系统。它们各自拥有独特的特性和优势,为用户提供了不同的使用体验。本文将深入探讨安卓与iOS系统之间的主要差异,包括它们的设计理念、用户界面、应用生态以及安全性等方面,并分析这些差异如何影响用户的使用体验。
|
2月前
|
安全 搜索推荐 Android开发
揭秘iOS与Android系统的差异:一场技术与哲学的较量
在当今数字化时代,智能手机操作系统的选择成为了用户个性化表达和技术偏好的重要标志。iOS和Android,作为市场上两大主流操作系统,它们之间的竞争不仅仅是技术的比拼,更是设计理念、用户体验和生态系统构建的全面较量。本文将深入探讨iOS与Android在系统架构、应用生态、用户界面及安全性等方面的本质区别,揭示这两种系统背后的哲学思想和市场策略,帮助读者更全面地理解两者的优劣,从而做出更适合自己的选择。
|
25天前
|
机器人
布谷直播App系统源码开发之后台管理功能详解
直播系统开发搭建管理后台功能详解!
|
25天前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
25天前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
27天前
|
安全 Android开发 iOS开发
安卓系统与iOS系统的比较####
【10月更文挑战第26天】 本文将深入探讨安卓(Android)和iOS这两大主流移动操作系统的各自特点、优势与不足。通过对比分析,帮助读者更好地理解两者在用户体验、应用生态、系统安全等方面的差异,从而为消费者在选择智能手机时提供参考依据。无论你是技术爱好者还是普通用户,这篇文章都将为你揭示两大系统背后的故事和技术细节。 ####
42 0