赞
踩
这个模块负责处理屏幕旋转的逻辑,需要在其中添加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.
这个文件定义了屏幕旋转和强制应用旋转的选项列表,需要在其中添加两个数组:screen_rotate_entries和screen_rotate_values,以及forceapp_rotate_entries和forceapp_rotate_values。
screen_rotate_entries和screen_rotate_values分别表示屏幕旋转的显示名称和对应的值,包括0度、90度、180度和270度。
+++ 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>
这个文件定义了英文版的字符串资源,需要在其中添加屏幕旋转和强制应用旋转的标题和摘要,以及对应的格式化字符串。
+++ 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>
这个文件定义了中文版的字符串资源,需要在其中添加屏幕旋转和强制应用旋转的标题和摘要,以及对应的格式化字符串。
+++ 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>
这个文件定义了显示设置的界面布局,添加屏幕旋转和强制应用旋转的列表偏好,以及对应的键值、标题、摘要和选项。
我们使用自定义的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"
这个文件定义了显示设置的控制器,我们需要在其中添加屏幕旋转和强制应用旋转的偏好控制器,以及对应的键值和上下文。
使用自定义的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;
}
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);
}
}
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.
}
}
}
}
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);
}
}
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 到这里就全部添加完成 没有难度~
其他记录:
androidx.appcompat.app.AlertDialog;
不能用早期版本的 , 如果同时导入2个包 会一直编译报错 只需保留一个就可以。
不管应用是否支持竖屏 , 都会被强制竖屏。
本文介绍了如何在Android系统Settings中添加屏幕旋转和强制App应用旋转的功能,以便客户可以根据项目需求调整屏幕方向。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。