竖屏横用:MTK_LCM_PHYSICL_ROTATION = 270或者纯横屏导致的问题。
(1)getCameraInfo方向问题
//frameworks/base/core/java/android/hardware/Camera.java
public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
//通过native的Jni来获取cameraInfo信息,可以在这里修改cameraInfo中的orientation信息
_getCameraInfo(cameraId, cameraInfo);
//(1)强制修改cameraInfo.orientation,修改Preview方向
+ if(ActivityThread.currentOpPackageName().equals("com.tencent.mm")){
+ if(cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK){
+ cameraInfo.orientation = 270;
+ }else{
+ cameraInfo.orientation = 90;
+ }
+ }
//(2)强制修改个别界面(二维码界面)的sensor orientation值
+ if(ActivityThread.currentActivityThread().currentActivityName().equals("com.tencent.mm.plugin.scanner.ui.BaseScanUI")){
+ cameraInfo.orientation = 180;
+ }
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
IAudioService audioService = IAudioService.Stub.asInterface(b);
try {
if (audioService.isCameraSoundForced()) {
// Only set this when sound is forced; otherwise let native code
cameraInfo.canDisableShutterSound = false;
}
} catch (RemoteException e) {
Log.e(TAG, "Audio service is unavailable for queries");
}
}
private native static void _getCameraInfo(int cameraId, CameraInfo cameraInfo);
public static class CameraInfo {
public static final int CAMERA_FACING_BACK = 0;
public static final int CAMERA_FACING_FRONT = 1;
/**
* The direction that the camera faces. It should be
* CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
*/
public int facing;
public int orientation;
/**
* <p>Whether the shutter sound can be disabled.</p>
*/
public boolean canDisableShutterSound;
};
//frameworks/base/core/java/android/app/ActivityThread.java
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
public String currentActivityName(){
String classname = null;
ActivityManager manager = (ActivityManager)getSystemContext().getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.RunningTaskInfo info = manager.getRunningTasks(1).get(0);
//String shortClassName = info.topActivity.getShortClassName();类名
classname = info.topActivity.getClassName();//完整类名
return classname;
}
public static String currentOpPackageName() {
ActivityThread am = currentActivityThread();
return (am != null && am.getApplication() != null)
? am.getApplication().getOpPackageName() : null;
}
public static String currentPackageName() {
ActivityThread am = currentActivityThread();
return (am != null && am.mBoundApplication != null)
? am.mBoundApplication.appInfo.packageName : null;
}
public static String currentProcessName() {
ActivityThread am = currentActivityThread();
return (am != null && am.mBoundApplication != null)
? am.mBoundApplication.processName : null;
}
public static Application currentApplication() {
ActivityThread am = currentActivityThread();
return am != null ? am.mInitialApplication : null;
}
public ApplicationThread getApplicationThread()
{
return mAppThread;
}
public Instrumentation getInstrumentation()
{
return mInstrumentation;
}
public Application getApplication() {
return mInitialApplication;
}
public String getProcessName() {
return mBoundApplication.processName;
}
public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
mSystemContext = ContextImpl.createSystemContext(this);
}
return mSystemContext;
}
}
(2)SystemSensorManager方向问题(拍照/预览)
拍照方向问题可通过修改gensor尝试,具体实现是对App的XY轴进行交换,在这个dispatchSensorEvent函数中可以对整个App的gsensor交换,也可以根据包名类名来单独更改某个界面。
//frameworks/base/core/java/android/hardware/SystemSensorManager.java
static final class SensorEventQueue extends BaseEventQueue
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
long timestamp) {
final Sensor sensor = mManager.mHandleToSensor.get(handle);
if (sensor == null) {
return;
}
//add start
//重力传感器
+ if(sensor.getType() == Sensor.TYPE_ACCELEROMETER && mManager.mContext.getBasePackageName().equalsIgnoreCase("com.tencent.mm")){
+ float tmp;
+ Log.d("debug_SensorEventQueue","x = " + values[0] + ",y = " + values[1] + ",z = " + values[2]);
+ tmp = values[0];
+ values[0] = values[1];
+ values[1] = -tmp;
+ }
//tmp = values[0];
//values[0] = -values[1];
//values[1] = tmp;
//修改带陀螺仪的应用问题,这里以腾讯游戏和平精英作为测试
if(ActivityThread.currentOpPackageName().contains("com.tencent.tmgp")){
if(sensor.getType() == Sensor.TYPE_GYROSCOPE){
Log.d("wdd222_SensorEventQueue_gyro","x = " + values[0] + ",y = " + values[1] + ",z = " + values[2]);
tmp_gyro = values[0];
values[0] = values[1];
values[1] = -tmp_gyro;
}
}
//add end
SensorEvent t = null;
synchronized (mSensorsEvents) {
t = mSensorsEvents.get(handle);
}
if (t == null) {
return;
}
// Copy from the values array.
System.arraycopy(values, 0, t.values, 0, t.values.length);
t.timestamp = timestamp;
t.accuracy = inAccuracy;
t.sensor = sensor;
}
//frameworks/base/core/java/android/app/ContextImpl.java
@Override
public String getPackageName() {
if (mPackageInfo != null) {
return mPackageInfo.getPackageName();
}
// No mPackageInfo means this is a Context for the system itself,
// and this here is its name.
return "android";
}
/** @hide */
@Override
public String getBasePackageName() {
return mBasePackageName != null ? mBasePackageName : getPackageName();
}
/** @hide */
@Override
public String getOpPackageName() {
return mOpPackageName != null ? mOpPackageName : getBasePackageName();
}
@Override
public ApplicationInfo getApplicationInfo() {
if (mPackageInfo != null) {
return mPackageInfo.getApplicationInfo();
}
throw new RuntimeException("Not supported in system context");
}
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
(3)QQ视频通话画面旋转90(对方画面)
//frameworks/base/core/java/android/view/OrientationEventListener.java
+ import android.app.ActivityThread;
public abstract class OrientationEventListener {
private int mOrientation = ORIENTATION_UNKNOWN;
private SensorManager mSensorManager;
private Sensor mSensor;
private SensorEventListener mSensorEventListener;
if (mOldListener != null) {
mOldListener.onSensorChanged(Sensor.TYPE_ACCELEROMETER, event.values);
}
if (orientation != mOrientation) {
mOrientation = orientation;
+ if(ActivityThread.currentOpPackageName().equals("com.tencent.mobileqq")){
+ orientation += 90;
+ }
onOrientationChanged(orientation);
}
}
//or
//QQ视频通话图像方向颠倒
//ro.qq.camera.sensor = 3;
(4)强制修改横/竖屏,防止屏幕旋转(9.0)
竖屏横用,微信视频通话显示角度异常。
(1)App设置:
xml配置:android:screenOrientation="portrait"
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
一旦锁住屏幕,当orientation方向改变的时候就不会触发onConfigurationChanged。
//frameworks/base/core/java/android/content/pm/ActivityInfo.java
public int launchMode;
//standard
public static final int LAUNCH_MULTIPLE = 0;
public static final int LAUNCH_SINGLE_TOP = 1;
public static final int LAUNCH_SINGLE_TASK = 2;
public static final int LAUNCH_SINGLE_INSTANCE = 3;
public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
public static final int SCREEN_ORIENTATION_UNSET = -2;
public static final int SCREEN_ORIENTATION_UNSPECIFIED = -1;//默认值,由系统决定
public static final int SCREEN_ORIENTATION_LANDSCAPE = 0;//强制横屏
public static final int SCREEN_ORIENTATION_PORTRAIT = 1;//强制竖屏
public static final int SCREEN_ORIENTATION_USER = 2;//用户当前的首选方向
public static final int SCREEN_ORIENTATION_BEHIND = 3;//与前一个activity方向相同
public static final int SCREEN_ORIENTATION_SENSOR = 4;//根据物理传感器方向转动,用户90度、180度、270度旋转手机方向,activity都更着变化
public static final int SCREEN_ORIENTATION_NOSENSOR = 5;//旋转设备时候,界面不会跟着旋转。初始化界面方向由系统控制
public static final int SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6;//(横屏的旋转,不会出现竖屏的现象)根据传感器定位方向,旋转手机180度界面旋转。一般横屏游戏会是这个属性。
public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7;//(竖屏的旋转,不会出现横屏的现象)根据传感器定位方向,旋转手机180度界面会旋转。
public static final int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
public static final int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10;
public static final int SCREEN_ORIENTATION_USER_LANDSCAPE = 11;
public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12;
public static final int SCREEN_ORIENTATION_FULL_USER = 13;
public static final int SCREEN_ORIENTATION_LOCKED = 14;
设置屏幕方向的示例代码:
requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置成全屏模式
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE););//强制为横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏
//动态更改屏幕方向
if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
else if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
(2)在framework层设置req,即固定屏幕方向:
(A)Android 9
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
boolean updateOrientationFromAppTokensLocked(int displayId, boolean forceUpdate) {
long ident = Binder.clearCallingIdentity();
try {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
- final int req = dc.getOrientation();
+ int req = dc.getOrientation();
+ for(WindowState win1 : mWindowMap.values()){
+ if(win1.getWindowTag().toString().contains("xxxx") && win1.isVisibleNow() && win1.isOnScreen()){
+ req = 0;
+ break;
+ }
+ }
if (req != dc.getLastOrientation() || forceUpdate) {
dc.setLastOrientation(req);
if (dc.isDefaultDisplay) {
mPolicy.setCurrentOrientationLw(req);
}
return dc.updateRotationUnchecked(forceUpdate);
}
return false;
} finally {
Binder.restoreCallingIdentity(ident);
}
}
(B)Android 10
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
+ public WindowHashMap getWindowHashMap(){
+ return mWindowMap;
+ }
//frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
//(1)
private boolean mUpdateImeTarget;
private boolean mTmpInitial;
private int mMaxUiWidth;
+ private WindowHashMap mWindowMap = new WindowHashMap();
//(2)
DisplayContent(Display display, WindowManagerService service,
WallpaperController wallpaperController, DisplayWindowController controller) {
super(service);
setController(controller);
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
+ " new=" + display);
}
+ mWindowMap = service.getWindowHashMap();
mDisplay = display;
mDisplayId = display.getDisplayId();
mWallpaperController = wallpaperController;
display.getDisplayInfo(mDisplayInfo);
//(3)
private boolean updateOrientationFromAppTokens(boolean forceUpdate) {
- final int req = dc.getOrientation();
+ int req = dc.getOrientation();
+ if(mWindowMap != null){
+ for(WindowState win1 : mWindowMap.values()){
+ if(win1.getWindowTag().toString().contains("com.whatsapp") && win1.isVisibleNow() && win1.isOnScreen()){
+ req = 0;
+ break;
+ }
+ }
+ }
if (req != dc.getLastOrientation() || forceUpdate)
}
(C)Android 11
可通过修改updateOrientation(boolean forceUpdate)来固定方向
//frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
private boolean updateOrientation(boolean forceUpdate){
final int orientation = getOrientation();
//可以通过包名和类名来修改此处的orientation值,从而达到固定横竖屏的作用
return mDisplayRotation.updateOrientation(orientation, forceUpdate);
}
//或者
//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
int rotationForOrientation(@ScreenOrientation int orientation,
@Surface.Rotation int lastRotation) {
switch (orientation) {
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
// Return portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
//add start
if (SystemProperties.getBoolean("ro.camera.spin", false)) {
if(ActivityThread.currentActivityThread().currentActivityName().contains("com.android.incallui.InCallActivity")){
mPortraitRotation = 0;
} else {
mPortraitRotation = 3;
}
}
//add end
return mPortraitRotation;
}
以上修改可通过获取当前应用 包名和类名来进行。