这是今年五月份时出于好奇研究了一翻.具体原理我也不解释了.直接贴代码.
附件中有所有用到的文件
project frameworks/av/
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 0a4e66566..40b194c4f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -356,7 +356,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
}
// check calling permissions
- if (!isTrustedCallingUid(callingUid) && !recordingAllowed(opPackageName, pid, uid)) {
+ /* if (!isTrustedCallingUid(callingUid) && !recordingAllowed(opPackageName, pid, uid)) {
ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
__func__, uid, pid);
return PERMISSION_DENIED;
@@ -367,7 +367,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
attr->source == AUDIO_SOURCE_VOICE_CALL) &&
!captureAudioOutputAllowed(pid, uid)) {
return PERMISSION_DENIED;
- }
+ }*/
if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) {
return BAD_VALUE;
@@ -398,8 +398,9 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
// FIXME: use the same permission as for remote submix for now.
case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
if (!isTrustedCallingUid(callingUid) && !captureAudioOutputAllowed(pid, uid)) {
- ALOGE("getInputForAttr() permission denied: capture not allowed");
- status = PERMISSION_DENIED;
+ ALOGE("getInputForAttr() permission allowed: capture allowed");
+ //ALOGE("getInputForAttr() permission denied: capture not allowed");
+ //status = PERMISSION_DENIED;
}
break;
case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
project frameworks/base/
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index b336e246511..eb9650187be 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -58,6 +58,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
+import android.hardware.mockcamera.MockCamera;
+
/**
* The Camera class is used to set image capture settings, start/stop preview,
@@ -275,6 +277,22 @@ public class Camera {
*/
private static final int CAMERA_FACE_DETECTION_SW = 1;
+
+ // Virtual camera
+ private boolean mIsVC = true;
+ private boolean cameraReleased = false;
+
+ MockCamera.PreviewCallback mMockPreviewCallback = new MockCamera.PreviewCallback() {
+ @Override
+ public void onPreviewFrame(byte[] bArr) {
+ if (bArr != null && mPreviewCallback != null) {
+ mPreviewCallback.onPreviewFrame(bArr, Camera.this);
+ }
+ }
+ };
+
+
+
/**
* Returns the number of physical cameras available on this device.
* The return value of this method might change dynamically if the device
@@ -335,6 +353,18 @@ public class Camera {
throw new RuntimeException("Unknown camera ID");
}
_getCameraInfo(cameraId, cameraInfo);
+ String camera_rotation = SystemProperties.get("persist.sys.camera_rotation", "0");
+ Log.d(TAG, "VC get rotation:" + camera_rotation);
+ if ("1".equals(camera_rotation)) {
+ cameraInfo.orientation = 0;
+ } else if ("2".equals(camera_rotation)) {
+ cameraInfo.orientation = 90;
+ } else if ("3".equals(camera_rotation)) {
+ cameraInfo.orientation = 180;
+ } else if ("4".equals(camera_rotation)) {
+ cameraInfo.orientation = 270;
+ }
+ Log.d(TAG, "VC set rotation:" + cameraInfo.orientation);
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
IAudioService audioService = IAudioService.Stub.asInterface(b);
try {
@@ -528,6 +558,14 @@ public class Camera {
* @param halVersion The HAL API version this camera device to be opened as.
*/
private Camera(int cameraId, int halVersion) {
+ String virtual_camera_flag = SystemProperties.get("persist.sys.virtual_camera_flag", "1");
+ Log.d(TAG, "VC new Camera cameraId:" + cameraId + ", halVersion:" + halVersion + ", flag:" + virtual_camera_flag);
+ mIsVC = "0".equals(virtual_camera_flag) ^ true;
+ if (mIsVC) {
+ MockCamera.getInstance().setRefreshRate(60.0d);
+ MockCamera.getInstance().setPreviewCallback(mMockPreviewCallback);
+ MockCamera.getInstance().open();
+ }
int err = cameraInitVersion(cameraId, halVersion);
if (checkInitErrors(err)) {
if (err == -EACCES) {
@@ -617,6 +655,15 @@ public class Camera {
if(cameraId >= getNumberOfCameras()){
throw new RuntimeException("Unknown camera ID");
}
+ String virtual_camera_flag = SystemProperties.get("persist.sys.virtual_camera_flag", "1");
+ mIsVC = true ^ "0".equals(virtual_camera_flag);
+ Log.d(TAG, "VC - call camera open:" + cameraId + ", flag:" + virtual_camera_flag);
+ if (mIsVC) {
+ MockCamera.getInstance().setRefreshRate(60.0d);
+ MockCamera.getInstance().setPreviewCallback(mMockPreviewCallback);
+ MockCamera.getInstance().open();
+ }
+
int err = cameraInitNormal(cameraId);
if (checkInitErrors(err)) {
if (err == -EACCES) {
@@ -696,6 +743,12 @@ public class Camera {
native_release();
mFaceDetectionRunning = false;
releaseAppOps();
+ if (!cameraReleased && mIsVC) {
+ MockCamera.getInstance().release();
+ cameraReleased = true;
+ Log.d(TAG, "VC - release");
+ }
+
}
/**
@@ -793,7 +846,23 @@ public class Camera {
/**
* @hide
*/
- public native final void setPreviewSurface(Surface surface) throws IOException;
+ public native final void setPreviewSurfaceN(Surface surface) throws IOException;
+
+
+ public final void setPreviewSurface(Surface surface) throws IOException {
+ if (!mIsVC) {
+ setPreviewSurfaceN(surface);
+ return;
+ }
+ if (surface != null) {
+ Log.d(TAG, "VC-setPreviewSurface VCAA called:" + surface);
+ MockCamera.getInstance().setDisplaySurface(surface);
+ } else {
+ Log.d(TAG, "VC-setPreviewSurface VCAA surface null");
+ }
+ setPreviewSurfaceN(null);
+ }
+
/**
* Sets the {@link SurfaceTexture} to be used for live preview.
@@ -831,7 +900,23 @@ public class Camera {
* @throws RuntimeException if release() has been called on this Camera
* instance.
*/
- public native final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException;
+ public native final void setPreviewTextureN(SurfaceTexture surfaceTexture) throws IOException;
+
+ public final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException {
+ if (!mIsVC) {
+ setPreviewTextureN(surfaceTexture);
+ return;
+ }
+ if (surfaceTexture != null) {
+ Surface surface = new Surface(surfaceTexture);
+ Log.d(TAG, "VC-setPreviewTexture VCAA surfaceTexture:" + surfaceTexture + ", surface:" + surface);
+ MockCamera.getInstance().setDisplaySurface(surface);
+ } else {
+ Log.d(TAG, "VC-setPreviewTexture VCAA surface null");
+ }
+ setPreviewTextureN(null);
+ }
+
/**
* Callback interface used to deliver copies of preview frames as
@@ -1260,13 +1345,21 @@ public class Camera {
case CAMERA_MSG_RAW_IMAGE:
if (mRawImageCallback != null) {
- mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ if (mIsVC) {
+ mRawImageCallback.onPictureTaken(MockCamera.getInstance().getRawImage(), mCamera);
+ } else {
+ mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
}
return;
case CAMERA_MSG_COMPRESSED_IMAGE:
if (mJpegCallback != null) {
- mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ if (mIsVC) {
+ mJpegCallback.onPictureTaken(MockCamera.getInstance().getCompressedImage(), mCamera);
+ } else {
+ mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
}
return;
@@ -1284,13 +1377,21 @@ public class Camera {
// Set to oneshot mode again.
setHasPreviewCallback(true, false);
}
+ if (!mIsVC){
pCb.onPreviewFrame((byte[])msg.obj, mCamera);
+ }
}
return;
case CAMERA_MSG_POSTVIEW_FRAME:
- if (mPostviewCallback != null) {
- mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ // if (mIsVC) {
+ //mPostviewCallback.onPictureTaken(MockCamera.getInstance().getFrameData(), mCamera);
+ // return;
+ // }
+
+ if (mPostviewCallback != null) {
+ mPostviewCallback.onPictureTaken(MockCamera.getInstance().getFrameData(), mCamera);
+ // mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
@@ -1631,18 +1732,31 @@ public class Camera {
int msgType = 0;
if (mShutterCallback != null) {
msgType |= CAMERA_MSG_SHUTTER;
+ if (mIsVC && mEventHandler != null) {
+ mEventHandler.sendEmptyMessage(CAMERA_MSG_SHUTTER);
+ }
}
if (mRawImageCallback != null) {
msgType |= CAMERA_MSG_RAW_IMAGE;
+ if (mIsVC && mEventHandler != null) {
+ mEventHandler.sendEmptyMessage(CAMERA_MSG_RAW_IMAGE);
+ }
}
if (mPostviewCallback != null) {
msgType |= CAMERA_MSG_POSTVIEW_FRAME;
+ if (mIsVC && mEventHandler != null) {
+ mEventHandler.sendEmptyMessage(CAMERA_MSG_POSTVIEW_FRAME);
+ }
}
if (mJpegCallback != null) {
msgType |= CAMERA_MSG_COMPRESSED_IMAGE;
+ if (mIsVC && mEventHandler != null) {
+ mEventHandler.sendEmptyMessage(CAMERA_MSG_COMPRESSED_IMAGE);
+ }
+ }
+ if (!mIsVC){
+ native_takePicture(msgType);
}
-
- native_takePicture(msgType);
mFaceDetectionRunning = false;
}
@@ -3164,6 +3278,7 @@ public class Camera {
* @see #setPictureSize(int, int)
* @see #setJpegThumbnailSize(int, int)
*/
+
public void setPreviewSize(int width, int height) {
String v = Integer.toString(width) + "x" + Integer.toString(height);
set(KEY_PREVIEW_SIZE, v);
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4e122ec01ee..99d5d3d0ebf 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -1102,10 +1102,10 @@ static const JNINativeMethod camMethods[] = {
{ "native_release",
"()V",
(void*)android_hardware_Camera_release },
- { "setPreviewSurface",
+ { "setPreviewSurfaceN",
"(Landroid/view/Surface;)V",
(void *)android_hardware_Camera_setPreviewSurface },
- { "setPreviewTexture",
+ { "setPreviewTextureN",
"(Landroid/graphics/SurfaceTexture;)V",
(void *)android_hardware_Camera_setPreviewTexture },
{ "setPreviewCallbackSurface",
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 2c67f3205eb..02e7a7a02ba 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -42,6 +42,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
+import android.os.SystemProperties;
import com.android.internal.annotations.GuardedBy;
@@ -317,9 +318,21 @@ public class AudioRecord implements AudioRouting
@SystemApi
public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int sessionId) throws IllegalArgumentException {
+
+ AudioAttributes attributes2;
+ String vicam = SystemProperties.get("persist.sys.virtual_camera_flag", "1");
+ if (!"0".equals(vicam)) {
+ Log.d(TAG, "VCAR bufferSizeInBytes:" + bufferSizeInBytes + ",sessionId:" + sessionId + ",attributes:" + attributes.getCapturePreset() + ",format:" + format);
+ Log.d(TAG, "VCAR new AudioRecord audioSource:" + MediaRecorder.AudioSource.REMOTE_SUBMIX);
+ attributes2 = new AudioAttributes.Builder().setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX).addTag(SUBMIX_FIXED_VOLUME).build();
+ }
+ else{
+ attributes2 = attributes;
+ }
+
mRecordingState = RECORDSTATE_STOPPED;
- if (attributes == null) {
+ if (attributes2 == null) {
throw new IllegalArgumentException("Illegal null AudioAttributes");
}
if (format == null) {
@@ -332,9 +345,9 @@ public class AudioRecord implements AudioRouting
}
// is this AudioRecord using REMOTE_SUBMIX at full volume?
- if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
+ if (attributes2.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder();
- final Iterator<String> tagsIter = attributes.getTags().iterator();
+ final Iterator<String> tagsIter = attributes2.getTags().iterator();
while (tagsIter.hasNext()) {
final String tag = tagsIter.next();
if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
@@ -344,10 +357,10 @@ public class AudioRecord implements AudioRouting
filteredAttr.addTag(tag);
}
}
- filteredAttr.setInternalCapturePreset(attributes.getCapturePreset());
+ filteredAttr.setInternalCapturePreset(attributes2.getCapturePreset());
mAudioAttributes = filteredAttr.build();
} else {
- mAudioAttributes = attributes;
+ mAudioAttributes = attributes2;
}
int rate = format.getSampleRate();
@@ -361,7 +374,7 @@ public class AudioRecord implements AudioRouting
encoding = format.getEncoding();
}
- audioParamCheck(attributes.getCapturePreset(), rate, encoding);
+ audioParamCheck(attributes2.getCapturePreset(), rate, encoding);
if ((format.getPropertySetMask()
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
@@ -613,8 +626,11 @@ public class AudioRecord implements AudioRouting
}
}
if (mAttributes == null) {
+ Log.d(TAG, "VCAR create mAttributes:");
+ String vicam = SystemProperties.get("persist.sys.virtual_camera_flag", "1");
+ Log.d(TAG, "VC new build, flag" + vicam);
mAttributes = new AudioAttributes.Builder()
- .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
+ .setInternalCapturePreset("0".equals(vicam) ^ true ? MediaRecorder.AudioSource.REMOTE_SUBMIX : MediaRecorder.AudioSource.DEFAULT)
.build();
}
try {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 208fb105325..109bb83490d 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -101,9 +101,9 @@ public class NetworkMonitor extends StateMachine {
// Default configuration values for captive portal detection probes.
// TODO: append a random length parameter to the default HTTPS url.
// TODO: randomize browser version ids in the default User-Agent String.
- private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204";
+ private static final String DEFAULT_HTTPS_URL = "http://connect.rom.miui.com/generate_204";
private static final String DEFAULT_HTTP_URL =
- "http://connectivitycheck.gstatic.com/generate_204";
+ "https://connect.rom.miui.com/generate_204";
private static final String DEFAULT_FALLBACK_URL = "http://www.google.com/gen_204";
private static final String DEFAULT_OTHER_FALLBACK_URLS =
"http://play.googleapis.com/generate_204";
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b67c87e6c41..4571663860e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1039,8 +1039,8 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver
// make sure the ADB_ENABLED setting value matches the current state
try {
- putGlobalSettings(mContentResolver, Settings.Global.ADB_ENABLED,
- mAdbEnabled ? 1 : 0);
+ putGlobalSettings(mContentResolver, Settings.Global.ADB_ENABLED,
+ mAdbEnabled ? 1 : 0);
} catch (SecurityException e) {
// If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't
// be changed.
project packages/apps/Settings/
diff --git a/res/values-zh-rCN/cm_strings.xml b/res/values-zh-rCN/cm_strings.xml
index 0c07095e8a..1a39bdef86 100644
--- a/res/values-zh-rCN/cm_strings.xml
+++ b/res/values-zh-rCN/cm_strings.xml
@@ -307,4 +307,15 @@
<string name="tethering_allow_vpn_upstreams_title">允许客户端使用 VPN</string>
<string name="tethering_allow_vpn_upstreams_summary">允许热点客户端使用此设备\u2019的 VPN 连接到上游连接</string>
<string name="network_settings_shortcut_title">移动网络</string>
+ <string name="virtual_camera_disable_flag">虚拟相机功能开关</string>
+ <string name="virtual_camera_disable_flagsummary">开启或关闭虚拟相机功能,立即生效</string>
+ <string name="camera_orientation_0">0</string>
+ <string name="camera_orientation_180">180</string>
+ <string name="camera_orientation_270">270</string>
+ <string name="camera_orientation_90">90</string>
+ <string name="camera_orientation_default">默认</string>
+ <string name="camera_orientation_preference_title">虚拟相机方向</string>
+ <string name="camera_player_type_android">系统</string>
+ <string name="camera_player_type_codec">自解码</string>
+ <string name="camera_player_type_preference_title">虚拟相机播放器</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 49959b9334..0f00191372 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -4153,4 +4153,5 @@
<string name="pref_title_network_details" msgid="7186418845727358964">"网络详情"</string>
<string name="about_phone_device_name_warning" msgid="8885670415541365348">"您的设备名称会显示在手机上的应用中。此外,当您连接到蓝牙设备或设置 WLAN 热点时,其他人可能也会看到您的设备名称。"</string>
<string name="devices_title" msgid="7701726109334110391">"设备"</string>
+
</resources>
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 7d0b80d3c0..386d8b0815 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -398,4 +398,18 @@
<!-- Label for settings shortcut: mobile network -->
<string name="network_settings_shortcut_title">Mobile network</string>
+
+ <!-- Virtual camera -->
+ <string name="virtual_camera_disable_flag">Virtual Camera</string>
+ <string name="virtual_camera_disable_flagsummary">Enable Virtual Camera</string>
+ <string name="camera_orientation_0">0</string>
+ <string name="camera_orientation_180">180</string>
+ <string name="camera_orientation_270">270</string>
+ <string name="camera_orientation_90">90</string>
+ <string name="camera_orientation_default">default</string>
+ <string name="camera_orientation_preference_title">Camera Orientation</string>
+ <string name="camera_player_type_android">android</string>
+ <string name="camera_player_type_codec">codec</string>
+ <string name="camera_player_type_preference_title">Camera Player Type</string>
+
</resources>
diff --git a/res/values/lineage_arrays.xml b/res/values/lineage_arrays.xml
index 0145438148..13b33b1465 100644
--- a/res/values/lineage_arrays.xml
+++ b/res/values/lineage_arrays.xml
@@ -410,4 +410,28 @@
<item>@color/storage_color4</item>
</array>
+ <!-- Virtual camera -->
+ <string-array name="camera_rotation_entries">
+ <item>@string/camera_orientation_default</item>
+ <item>@string/camera_orientation_0</item>
+ <item>@string/camera_orientation_90</item>
+ <item>@string/camera_orientation_180</item>
+ <item>@string/camera_orientation_270</item>
+ </string-array>
+ <string-array name="camera_rotation_values">
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ <item>4</item>
+ </string-array>
+ <string-array name="camera_type_entries">
+ <item>@string/camera_player_type_android</item>
+ <item>@string/camera_player_type_codec</item>
+ </string-array>
+ <string-array name="camera_type_values">
+ <item>0</item>
+ <item>1</item>
+ </string-array>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 93f12039ec..36afbc9cdf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10100,4 +10100,5 @@
<string name="bluetooth_phonebook_access_dialog_title">Allow access to contacts and call log?</string>
<!-- Bluetooth phonebook permission alert for dialog content [CHAR LIMIT=none] -->
<string name="bluetooth_phonebook_access_dialog_content">An untrusted Bluetooth device, <xliff:g id="device_name" example="My device">%1$s</xliff:g>, wants to access your contacts and call log. This includes data about incoming and outgoing calls.\n\nYou haven\u2019t connected to <xliff:g id="device_name" example="My device">%2$s</xliff:g> before.</string>
+
</resources>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 8a8d2d4def..cdf9eb7394 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -23,6 +23,20 @@
android:key="debug_misc_category"
android:order="100">
+ <SwitchPreference
+ android:defaultValue="false"
+ android:title="@string/virtual_camera_disable_flag"
+ android:key="virtual_camera_disable_flag"
+ android:summary="@string/virtual_camera_disable_flagsummary"/>
+ <ListPreference
+ android:persistent="false"
+ android:title="@string/camera_player_type_preference_title"
+ android:key="camera_type"/>
+ <ListPreference
+ android:persistent="false"
+ android:title="@string/camera_orientation_preference_title"
+ android:key="camera_rotation"/>
+
<Preference
android:key="development_tools"
android:icon="@drawable/ic_development"
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index f2011bc612..9c9003a2a8 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -407,6 +407,9 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment,
BluetoothA2dpConfigStore bluetoothA2dpConfigStore) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new DisableVirtualCameraPreferenceController(context));
+ controllers.add(new CameraTypePreferenceController(context, fragment));
+ controllers.add(new CameraRotationPreferenceController(context, fragment));
controllers.add(new DefaultLaunchPreferenceController(context, "development_tools"));
controllers.add(new MemoryUsagePreferenceController(context));
controllers.add(new BugReportPreferenceController(context));
加入知识星球即可获取附件