这是今年五月份时出于好奇研究了一翻.具体原理我也不解释了.直接贴代码.
附件中有所有用到的文件

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));

加入知识星球即可获取附件
image-20211028134257609