以旋转30度为例,从app 开始修改:
java层:
1.添加30度变量
路径:frameworks\base\core\java\android\view\Surface.java
/** @hide */
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
/**
* Rotation constant: 0 degree rotation (natural orientation)
*/
public static final int ROTATION_0 = 0;
/**
* Rotation constant: 90 degree rotation.
*/
public static final int ROTATION_90 = 1;
/**
* Rotation constant: 180 degree rotation.
*/
public static final int ROTATION_180 = 2;
/**
* Rotation constant: 270 degree rotation.
*/
public static final int ROTATION_270 = 3;
/**
* Rotation constant: any degree rotation.
*/
/* navy */
public static final int ROTATION_30 = 8;
/**
* Returns a human readable representation of a rotation.
*
* @param rotation The rotation.
* @return The rotation symbolic name.
*
* @hide
*/
public static String rotationToString(int rotation) {
switch (rotation) {
case Surface.ROTATION_0: {
return "ROTATION_0";
}
case Surface.ROTATION_90: {
return "ROATATION_90";
}
case Surface.ROTATION_180: {
return "ROATATION_180";
}
case Surface.ROTATION_270: {
return "ROATATION_270";
/* navy */
}case Surface.ROTATION_30: {
return "ROATATION_30";
}
default: {
throw new IllegalArgumentException("Invalid rotation: " + rotation);
}
}
}
2.添加30度菜单选项
UI:Settings->Display->HDMI->HDMI Rotation
1)路径:packages\apps\Settings\res\values\arrays.xml
<string-array name="hdmi_rotation_entries">
<item>0</item>
<!-- navy-->
<item>30</item>
<item>90</item>
<item>180</item>
<item>270</item>
</string-array>
<string-array name="hdmi_rotation_values">
<item>0</item>
<!-- navy-->
<item>30</item>
<item>90</item>
<item>180</item>
<item>270</item>
</string-array>
2)路径:packages\apps\Settings\src\com\android\settings\HdmiSettings.java
@Override
public boolean onPreferenceChange(Preference preference, Object obj) {
Log.i(TAG, "onPreferenceChange:" + obj);
String key = preference.getKey();
Log.d(TAG, key);
if(preference == mHdmiResolution) {
if (KEY_HDMI_RESOLUTION.equals(key)) {
if (obj.equals(mOldResolution))
return true;
int index = mHdmiResolution.findIndexOfValue((String) obj);
Log.i(TAG, "onPreferenceChange: index= " + index);
mDisplayInfo = getDisplayInfo();
if (mDisplayInfo != null) {
DrmDisplaySetting.setDisplayModeTemp(mDisplayInfo, index);
showConfirmSetModeDialog();
}
}
} else if (preference == mHdmiRotation) {
if (KEY_HDMI_ROTATION.equals(key)) {
try {
int value = Integer.parseInt((String) obj);
android.os.SystemProperties.set("persist.sys.orientation", (String) obj);
Log.d(TAG,"freezeRotation~~~value:"+(String) obj);
if(value == 0)
wm.freezeRotation(Surface.ROTATION_0);
else if(value == 90)
wm.freezeRotation(Surface.ROTATION_90);
else if(value == 180)
wm.freezeRotation(Surface.ROTATION_180);
else if(value == 270)
wm.freezeRotation(Surface.ROTATION_270);
/* navy */
else if(value == 30){
Log.d(TAG,"freezeRotation~~~Surface.ROTATION_30:"+ Surface.ROTATION_30);
wm.freezeRotation(Surface.ROTATION_30);
}
else
return true;
//android.os.SystemProperties.set("sys.boot_completed", "1");
} catch (Exception e) {
Log.e(TAG, "freezeRotation error");
}
}
} else if (preference == mHdmiDualScreen) {
android.provider.Settings.System.putInt(getActivity().getContentResolver(),DOUBLE_SCREEN_CONFIG,(Boolean)obj?1:0);
SystemProperties.set("persist.orientation.vhinit", "0");
SystemProperties.set("persist.orientation.vhshow", "false");
mHdmiDualScreenVH.setEnabled((Boolean)obj);
mHdmiDualScreenVH.setChecked(false);
mHdmiDualScreenList.setEnabled(false);
this.finish();
} else if (preference == mHdmiDualScreenVH) {
if((Boolean)obj) {
SystemProperties.set("persist.orientation.vhshow", "true");
mHdmiDualScreenList.setEnabled(true);
} else {
SystemProperties.set("persist.orientation.vhshow", "false");
mHdmiDualScreenList.setEnabled(false);
SystemProperties.set("persist.orientation.vhinit", "0");
}
SystemProperties.set("persist.orientation.vhinit", "0");
} else if (preference == mHdmiDualScreenList) {
if("0".equals(obj.toString())) {
SystemProperties.set("persist.orientation.vhinit", "0");
} else if ("1".equals(obj.toString())) {
SystemProperties.set("persist.orientation.vhinit", "1");
}
}
return true;
}
3)设定30度
路径:packages\apps\Settings\src\com\android\settings\HdmiSettings.java
private void init() {
mIsUseDisplayd = SystemProperties.getBoolean("ro.rk.displayd.enable", false);
//init hdmi rotation
try {
wm = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
int rotation = wm.getRotation();
switch (rotation) {
case Surface.ROTATION_0:
mHdmiRotation.setValue("0");
break;
case Surface.ROTATION_90:
mHdmiRotation.setValue("90");
break;
case Surface.ROTATION_180:
mHdmiRotation.setValue("180");
break;
case Surface.ROTATION_270:
mHdmiRotation.setValue("270");
break;
/* navy */
case Surface.ROTATION_30:
mHdmiRotation.setValue("30");
break;
default:
mHdmiRotation.setValue("0");
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
3.修改WindowManagerService.java 中相关code
路径:frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
@Override
public void freezeRotation(int rotation) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"freezeRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
/* navy */
if (rotation < -1 || rotation > Surface.ROTATION_30) {
throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
+ "rotation constant.");
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "freezeRotation: mRotation=" + mRotation);
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "freezeRotation: rotation=" + rotation);
long origId = Binder.clearCallingIdentity();
try {
mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
rotation == -1 ? mRotation : rotation);
} finally {
Binder.restoreCallingIdentity(origId);
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "freezeRotation: mRotation1111111=" + mRotation);
updateRotationUnchecked(false, false);
}
@Override
public int getPreferredOptionsPanelGravity() {
synchronized (mWindowMap) {
final int rotation = getRotation();
// TODO(multidisplay): Assume that such devices physical keys are on the main screen.
final DisplayContent displayContent = getDefaultDisplayContentLocked();
if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
// On devices with a natural orientation of portrait
switch (rotation) {
default:
case Surface.ROTATION_0:
/* navy */
case Surface.ROTATION_30:
return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
case Surface.ROTATION_90:
return Gravity.RIGHT | Gravity.BOTTOM;
case Surface.ROTATION_180:
return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
case Surface.ROTATION_270:
return Gravity.START | Gravity.BOTTOM;
}
}
// On devices with a natural orientation of landscape
switch (rotation) {
default:
case Surface.ROTATION_0:
/* navy */
case Surface.ROTATION_30:
return Gravity.RIGHT | Gravity.BOTTOM;
case Surface.ROTATION_90:
return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
case Surface.ROTATION_180:
return Gravity.START | Gravity.BOTTOM;
case Surface.ROTATION_270:
return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
}
}
}
private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
int uiMode, int dw, int dh, float density, Configuration outConfig) {
// TODO: Multidisplay: for now only use with default display.
// We need to determine the smallest width that will occur under normal
// operation. To this, start with the base screen size and compute the
// width under the different possible rotations. We need to un-rotate
// the current screen dimensions before doing this.
int unrotDw, unrotDh;
if (rotated) {
unrotDw = dh;
unrotDh = dw;
} else {
unrotDw = dw;
unrotDh = dh;
}
displayInfo.smallestNominalAppWidth = 1<<30;
displayInfo.smallestNominalAppHeight = 1<<30;
displayInfo.largestNominalAppWidth = 0;
displayInfo.largestNominalAppHeight = 0;
adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh);
/* navy */
adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_30, uiMode, unrotDw, unrotDh);
adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw);
adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh);
adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw);
int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode);
/* navy */
sl = reduceConfigLayout(sl, Surface.ROTATION_30, density, unrotDw, unrotDh, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode);
outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
outConfig.screenLayout = sl;
}
private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
DisplayMetrics dm, int dw, int dh) {
// TODO: Multidisplay: for now only use with default display.
dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode);
dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode);
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
if (curSize == 0 || size < curSize) {
curSize = size;
}
return curSize;
}
private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw, int dh) {
// TODO: Multidisplay: for now only use with default display.
mTmpDisplayMetrics.setTo(dm);
final DisplayMetrics tmpDm = mTmpDisplayMetrics;
final int unrotDw, unrotDh;
if (rotated) {
unrotDw = dh;
unrotDh = dw;
} else {
unrotDw = dw;
unrotDh = dh;
}
int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh);
/* navy */
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_30, uiMode, tmpDm, unrotDh, unrotDw);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw);
return sw;
}
4.修改PhoneWindowManager.java 中相关code
路径:frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
/* navy :扩展数组长度*/
int[] mNavigationBarHeightForRotationDefault = new int[10];
int[] mNavigationBarWidthForRotationDefault = new int[10];
int[] mNavigationBarHeightForRotationInCarMode = new int[10];
int[] mNavigationBarWidthForRotationInCarMode = new int[10];
int mLandscapeRotation = 0; // default landscape rotation
int mSeascapeRotation = 0; // "other" landscape rotation, 180 degrees from mLandscapeRotation
int mPortraitRotation = 0; // default portrait rotation
int mUpsideDownRotation = 0; // "other" portrait rotation
/* navy */
int mAnyRotation = 0; // "other" portrait rotation
@Override
public void onConfigurationChanged() {
final Resources res = mContext.getResources();
mStatusBarHeight =
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
// Height of the navigation bar when presented horizontally at bottom
mNavigationBarHeightForRotationDefault[mPortraitRotation] =
mNavigationBarHeightForRotationDefault[mUpsideDownRotation] =
res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
mNavigationBarHeightForRotationDefault[mLandscapeRotation] =
mNavigationBarHeightForRotationDefault[mSeascapeRotation] =
mNavigationBarHeightForRotationDefault[mAnyRotation] =
res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height_landscape);
// Width of the navigation bar when presented vertically along one side
mNavigationBarWidthForRotationDefault[mPortraitRotation] =
mNavigationBarWidthForRotationDefault[mUpsideDownRotation] =
mNavigationBarWidthForRotationDefault[mLandscapeRotation] =
mNavigationBarWidthForRotationDefault[mSeascapeRotation] =
mNavigationBarWidthForRotationDefault[mAnyRotation] =
res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
if (ALTERNATE_CAR_MODE_NAV_SIZE) {
// Height of the navigation bar when presented horizontally at bottom
mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height_car_mode);
mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] =
mNavigationBarHeightForRotationInCarMode[mAnyRotation] =
res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
// Width of the navigation bar when presented vertically along one side
mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
mNavigationBarWidthForRotationInCarMode[mAnyRotation] =
res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width_car_mode);
}
}
// If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
// need to provide information to the clients that want to pretend that you can draw there.
// We only want to apply outsets to certain types of windows. For example, we never want to
// apply the outsets to floating dialogs, because they wouldn't make sense there.
final boolean useOutsets = shouldUseOutsets(attrs, fl);
if (isDefaultDisplay && useOutsets) {
osf = mTmpOutsetFrame;
osf.set(cf.left, cf.top, cf.right, cf.bottom);
int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
if (outset > 0) {
int rotation = mDisplayRotation;
//if (rotation == Surface.ROTATION_0) {
/* navy */
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_30) {
osf.bottom += outset;
} else if (rotation == Surface.ROTATION_90) {
osf.right += outset;
} else if (rotation == Surface.ROTATION_180) {
osf.top -= outset;