Add minimal post processing flag in Settings.Secure

Minimal post processing might not be very well supported on all TV
displays (e.g.the switch to/out of the low latency mode might be too
slow or there might be flickering on the screen or some color
interference, etc). This depends on the vendor implementation of minimal
post processing. In such cases, we want to give the user an option to
disable this feature in the settings menu. This means that any calls to
the API (Window.setMinimalPostProcessing) will be ignored and no signals
will be sent to the display.

This CL adds the necessary flag to Settings.Secure. The value is read
from DisplayManagerService, which combines it with the information from
the WindowManager and the display capabilities to request the right low
latency mode on the display.

Bug: 144356279

Test: m && ./vendor/google/tools/flashall
      1. adb shell settings put secure minimal_post_processing_allowed 1
      2. Open Activity that prefers minimal post processing
      3. adb shell settings put secure minimal_post_processing_allowed 0
         -> this should turn ALLM off
      4. adb shell settings put secure minimal_post_processing_allowed 1
         -> this should turn ALLM back on
      5. Exit Activity
         -> this should turn ALLM off

Change-Id: I2d24a9a004d4939b0439d466ef2ca279803fd67f
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e39d6d5..34bb4b3 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -39,6 +39,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.database.ContentObserver;
 import android.graphics.ColorSpace;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -60,6 +61,7 @@
 import android.hardware.input.InputManagerInternal;
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionManager;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -77,6 +79,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.IntArray;
 import android.util.Pair;
@@ -304,6 +307,13 @@
 
     private SensorManager mSensorManager;
 
+    // Whether minimal post processing is allowed by the user.
+    @GuardedBy("mSyncRoot")
+    private boolean mMinimalPostProcessingAllowed;
+
+    // Receives notifications about changes to Settings.
+    private SettingsObserver mSettingsObserver;
+
     public DisplayManagerService(Context context) {
         this(context, new Injector());
     }
@@ -403,6 +413,7 @@
                 BrightnessConfiguration config =
                         mPersistentDataStore.getBrightnessConfiguration(userSerial);
                 mDisplayPowerController.setBrightnessConfiguration(config);
+                handleSettingsChange();
             }
             mDisplayPowerController.onSwitchUser(newUserId);
         }
@@ -428,6 +439,8 @@
             // Just in case the top inset changed before the system was ready. At this point, any
             // relevant configuration should be in place.
             recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
+
+            updateSettingsLocked();
         }
 
         mDisplayModeDirector.setDesiredDisplayModeSpecsListener(
@@ -435,6 +448,8 @@
         mDisplayModeDirector.start(mSensorManager);
 
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
+
+        mSettingsObserver = new SettingsObserver();
     }
 
     @VisibleForTesting
@@ -569,6 +584,33 @@
         }
     }
 
+    private class SettingsObserver extends ContentObserver {
+        SettingsObserver() {
+            super(mHandler);
+
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Secure.getUriFor(
+                        Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            handleSettingsChange();
+        }
+    }
+
+    private void handleSettingsChange() {
+        synchronized (mSyncRoot) {
+            updateSettingsLocked();
+            scheduleTraversalLocked(false);
+        }
+    }
+
+    private void updateSettingsLocked() {
+        mMinimalPostProcessingAllowed = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED, 1, UserHandle.USER_CURRENT) != 0;
+    }
+
     private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplays.get(displayId);
@@ -1192,7 +1234,7 @@
     }
 
     private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
-            float requestedRefreshRate, int requestedModeId, boolean requestedMinimalPostProcessing,
+            float requestedRefreshRate, int requestedModeId, boolean preferMinimalPostProcessing,
             boolean inTraversal) {
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplays.get(displayId);
@@ -1220,14 +1262,13 @@
             mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode(
                     displayId, requestedModeId);
 
+            if (display.getDisplayInfoLocked().minimalPostProcessingSupported) {
+                boolean mppRequest = mMinimalPostProcessingAllowed && preferMinimalPostProcessing;
 
-            if (display.getDisplayInfoLocked().minimalPostProcessingSupported
-                    && (display.getRequestedMinimalPostProcessingLocked()
-                    != requestedMinimalPostProcessing)) {
-
-                display.setRequestedMinimalPostProcessingLocked(requestedMinimalPostProcessing);
-
-                shouldScheduleTraversal = true;
+                if (display.getRequestedMinimalPostProcessingLocked() != mppRequest) {
+                    display.setRequestedMinimalPostProcessingLocked(mppRequest);
+                    shouldScheduleTraversal = true;
+                }
             }
 
             if (shouldScheduleTraversal) {