(1)修改Preview方向
//设置应用包名
//frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
//createStream
binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId) {
int32_t transform = 0;
err = getRotationTransformLocked(&transform);
}
status_t CameraDeviceClient::getRotationTransformLocked(int32_t* transform) {
ALOGV("%s: begin", __FUNCTION__);
//add start
char value[PROPERTY_VALUE_MAX] = {'\0'};
property_set("sys.packageName.display", String8(mClientPackageName).string());
ALOGV("%s: mClientPackageName: %s", __FUNCTION__, String8(mClientPackageName).string());
//add end
const CameraMetadata& staticInfo = mDevice->info();
return CameraUtils::getRotationTransform(staticInfo, transform);
}
//获取应用包名修改orientation值
//frameworks/av/camera/CameraUtils.cpp
status_t CameraUtils::getRotationTransform(const CameraMetadata& staticInfo,
/*out*/int32_t* transform) {
ALOGV("%s", __FUNCTION__);
if (transform == NULL) {
ALOGW("%s: null transform", __FUNCTION__);
return BAD_VALUE;
}
*transform = 0;
//获取sensor方向
camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_SENSOR_ORIENTATION);
if (entry.count == 0) {
ALOGE("%s: Can't find android.sensor.orientation in static metadata!", __FUNCTION__);
return INVALID_OPERATION;
}
//获取facing信息
camera_metadata_ro_entry_t entryFacing = staticInfo.find(ANDROID_LENS_FACING);
if (entryFacing.count == 0) {
ALOGE("%s: Can't find android.lens.facing in static metadata!", __FUNCTION__);
return INVALID_OPERATION;
}
int32_t& flags = *transform;
//前摄具有mirror效果
bool mirror = (entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT);
//sensor方向
int orientation = entry.data.i32[0];
char value[PROPERTY_VALUE_MAX] = {'\0'};
//获取系统应用包名
//add start
if (property_get("sys.packageName.display", value, NULL)) {
if (strcmp(value,"com.skype.raider") == 0) {
if (!mirror) {
orientation = 90;
} else {
orientation = 270;
}
}
}
//add end
if (!mirror) {
//表示没有mirror,一般后摄
switch (orientation) {
case 0:
flags = 0;
break;
case 90:
flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
break;
case 180:
flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
break;
case 270:
flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
break;
default:
ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
__FUNCTION__, orientation);
return INVALID_OPERATION;
}
} else {
// Front camera needs to be horizontally flipped for mirror-like behavior.
// Note: Flips are applied before rotates; using XOR here as some of these flags are
// composed in terms of other flip/rotation flags, and are not bitwise-ORable.
switch (orientation) {
case 0:
flags = NATIVE_WINDOW_TRANSFORM_FLIP_H;
break;
case 90:
flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
NATIVE_WINDOW_TRANSFORM_ROT_270;
break;
case 180:
flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
NATIVE_WINDOW_TRANSFORM_ROT_180;
break;
case 270:
flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
NATIVE_WINDOW_TRANSFORM_ROT_90;
break;
default:
ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
__FUNCTION__, orientation);
return INVALID_OPERATION;
}
}
/**
* This magic flag makes surfaceflinger un-rotate the buffers
* to counter the extra global device UI rotation whenever the user
* physically rotates the device.
*
* By doing this, the camera buffer always ends up aligned
* with the physical camera for a "see through" effect.
*
* In essence, the buffer only gets rotated during preview use-cases.
* The user is still responsible to re-create streams of the proper
* aspect ratio, or the preview will end up looking non-uniformly
* stretched.
*/
flags |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
ALOGV("%s: final transform = 0x%x", __FUNCTION__, flags);
return OK;
}
(2)拦截JPEG_ORIENTATION,修改拍照方向
//通过拦截request当中的JPEG_ORIENTATION参数来进行定制修改
//frameworks/base/core/java/android/hardware/camera2/CaptureRequest
public <T> void set(@NonNull Key<T> key, T value) {
//新增如下判断,这里以com.whatsapp为例
if(key != null && JPEG_ORIENTATION.equals(key)){
Log.d("request set", "key = " + key + ", value = " + value);
if(mPackageName != null && mPackageName.equals("com.whatsapp")) {
String cameraId = CameraManager.getCameraId();
if(cameraId != null && "0".equals(cameraId)){
value = (T)(Object)90;
}else{
value = (T)(Object)270;
}
}
}
mRequest.mLogicalCameraSettings.set(key, value);
}
//frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
int clientUid)
throws CameraAccessException {
if (cameraId == null) {
throw new IllegalArgumentException("cameraId was null");
} else if (callback == null) {
throw new IllegalArgumentException("callback was null");
}
if (CameraManagerGlobal.sCameraServiceDisabled) {
throw new IllegalArgumentException("No cameras available on device");
}
++ mCameraId = cameraId;
++ Log.d(TAG, "openCameraForUid cameraId = " + cameraId);
openCameraDeviceUserAsync(cameraId, callback, executor, clientUid);
}
++ private static volatile String mCameraId;
/**
* @hide
*/
@Nullable
++ public static String getCameraId() {
return mCameraId;
}
/**
* @hide
*/
++ public static void setCameraId(@Nullable String cameraId) {
mCameraId = cameraId;
}
(3)修改App拿到的SENSOR_ORIENTATION方向
//frameworks/base/core/java/android/hardware/camera2/CameraCharacteristics.java
@PublicKey
@NonNull
public static final Key<Integer> SENSOR_ORIENTATION =
new Key<Integer>("android.sensor.orientation", int.class);
@Nullable
public <T> T get(Key<T> key) {
Log.d("request get", "Activity: " + ActivityThread.currentActivityThread().currentActivityName() + " ,key = " + key);
if(key != null && SENSOR_ORIENTATION.equals(key)){
//这里以whatsapp为例
if(ActivityThread.currentOpPackageName().contains("com.whatsapp")){
String cameraId = CameraManager.getCameraId();
if(cameraId != null && "0".equals(cameraId)){
T value = (T)(Object)90;
Log.d("request get 0", "value = " + value + " ,ori = " + mProperties.get(key));
return value;
}else{
T value = (T)(Object)270;
Log.d("request get 1", "value = " + value + " ,ori = " + mProperties.get(key));
return value;
}
}
}
return mProperties.get(key);
}
(4)拦截App拿到的Perview Size和Picture Size列表
//frameworks/base/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
//获取preview size列表(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
public <T> Size[] getOutputSizes(Class<T> klass) {
if (isOutputSupportedFor(klass) == false) {
return null;
}
Size[] sizes = getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
HAL_DATASPACE_UNKNOWN,/*output*/true, /*highRes*/false);
if(ActivityThread.currentOpPackageName().contains("com.whatsapp")){
if(sizes != null){
Size[] temp = new Size[sizes.length];
int index = 0;
for(int i = 0; i < sizes.length; i++){
//只留下1:1比例的size
if((sizes[i].getWidth() / (sizes[i].getHeight() * 1.0)) - 1 < 0.02){
temp[index++] = sizes[i];
Log.i("getOutputSizes preview","index = " + index);
}
}
if (index <= 0) {
sizes = new Size[0];
} else {
sizes = Arrays.copyOf(temp, index);
}
for(int i = 0; i < sizes.length; i++){
Log.i("getOutputSizes preview","size = " + sizes[i].toString());
}
}
}
return sizes;
}
//获取其他Size列表
//ImageFormat.JPEG = 256
//ImageFormat.YUV_420_888 = 35
public Size[] getOutputSizes(int format) {
return getPublicFormatSizes(format, /*output*/true, /*highRes*/ false);
}
(5)Display影响Preview方向
在Display.java相关位置针对横屏进行修改,达到类似于横屏竖用的状态。
//frameworks/base/core/java/android/view/Display.java
public int getRotation() {
synchronized (this) {
updateDisplayInfoLocked();
//add start
if (SystemProperties.getBoolean("ro.rotation.display", false)) {
int mRotation = (mMayAdjustByFixedRotation
? getDisplayAdjustments().getRotation(mDisplayInfo.rotation)
: mDisplayInfo.rotation);
return (mRotation + 1 ) % 4;
}
//and end
return mMayAdjustByFixedRotation
? getDisplayAdjustments().getRotation(mDisplayInfo.rotation)
: mDisplayInfo.rotation;
}
}
(6)SystemSensorManager影响拍照角度
在SystemSensorManager.java中来拦截Gsensor的值,并对非系统应用(android包名)进行xy值对调,此处存在三方应用包名包含android字段的风险,导致拍照图片方向异常。
//frameworks/base/core/java/android/hardware/SystemSensorManager.java
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
long timestamp) {
final Sensor sensor = mManager.mHandleToSensor.get(handle);
if (sensor == null) {
// sensor disconnected
return;
}
//add start
if (SystemProperties.getBoolean("ro.rotation.display", false)) {
if(!ActivityThread.currentOpPackageName().contains("android")
|| (ActivityThread.currentOpPackageName().contains("jp.naver.line.android"))){ //特例应用
if(sensor.getType() == Sensor.TYPE_ACCELEROMETER ){
Log.d("wdd111_SensorEventQueue","x = " + values[0] + ",y = " + values[1] + ",z = " + values[2]);
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float 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
}
(7)拦截系统的OrientationEventListener,修改App拿到的Orientation值
//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);
}
}
(8)强制应用横竖屏
//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;
}
以上修改可通过获取当前应用包名和类名来进行。