diff options
7 files changed, 156 insertions, 17 deletions
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java index 77072890a1eb..856bde870bcf 100644 --- a/core/java/android/content/ContentCaptureOptions.java +++ b/core/java/android/content/ContentCaptureOptions.java @@ -70,6 +70,12 @@ public final class ContentCaptureOptions implements Parcelable { public final int logHistorySize; /** + * Disable flush when receiving a VIEW_TREE_APPEARING event. + * @hide + */ + public final boolean disableFlushForViewTreeAppearing; + + /** * List of activities explicitly allowlisted for content capture (or {@code null} if allowlisted * for all acitivites in the package). */ @@ -90,7 +96,8 @@ public final class ContentCaptureOptions implements Parcelable { public ContentCaptureOptions(int loggingLevel) { this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0, /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0, - /* logHistorySize= */ 0, /* whitelistedComponents= */ null); + /* logHistorySize= */ 0, /* disableFlushForViewTreeAppearing= */ false, + /* whitelistedComponents= */ null); } /** @@ -98,10 +105,23 @@ public final class ContentCaptureOptions implements Parcelable { */ public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, - @SuppressLint("NullableCollection") + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable ArraySet<ComponentName> whitelistedComponents) { + this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs, + textChangeFlushingFrequencyMs, logHistorySize, + ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING, + whitelistedComponents); + } + + /** @hide */ + public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, + int textChangeFlushingFrequencyMs, int logHistorySize, + boolean disableFlushForViewTreeAppearing, + @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable ArraySet<ComponentName> whitelistedComponents) { this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs, - textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents); + textChangeFlushingFrequencyMs, logHistorySize, disableFlushForViewTreeAppearing, + whitelistedComponents); } /** @hide */ @@ -111,11 +131,14 @@ public final class ContentCaptureOptions implements Parcelable { ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE, ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS, ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS, - ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, whitelistedComponents); + ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, + ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING, + whitelistedComponents); } private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, + boolean disableFlushForViewTreeAppearing, @Nullable ArraySet<ComponentName> whitelistedComponents) { this.lite = lite; this.loggingLevel = loggingLevel; @@ -123,6 +146,7 @@ public final class ContentCaptureOptions implements Parcelable { this.idleFlushingFrequencyMs = idleFlushingFrequencyMs; this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs; this.logHistorySize = logHistorySize; + this.disableFlushForViewTreeAppearing = disableFlushForViewTreeAppearing; this.whitelistedComponents = whitelistedComponents; } @@ -171,7 +195,8 @@ public final class ContentCaptureOptions implements Parcelable { .append(", maxBufferSize=").append(maxBufferSize) .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs) .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs) - .append(", logHistorySize=").append(logHistorySize); + .append(", logHistorySize=").append(logHistorySize) + .append(", disableFlushForViewTreeAppearing=").append(disableFlushForViewTreeAppearing); if (whitelistedComponents != null) { string.append(", whitelisted=").append(whitelistedComponents); } @@ -189,6 +214,7 @@ public final class ContentCaptureOptions implements Parcelable { pw.print(", idle="); pw.print(idleFlushingFrequencyMs); pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs); pw.print(", logSize="); pw.print(logHistorySize); + pw.print(", disableFlushForViewTreeAppearing="); pw.print(disableFlushForViewTreeAppearing); if (whitelistedComponents != null) { pw.print(", whitelisted="); pw.print(whitelistedComponents); } @@ -209,6 +235,7 @@ public final class ContentCaptureOptions implements Parcelable { parcel.writeInt(idleFlushingFrequencyMs); parcel.writeInt(textChangeFlushingFrequencyMs); parcel.writeInt(logHistorySize); + parcel.writeBoolean(disableFlushForViewTreeAppearing); parcel.writeArraySet(whitelistedComponents); } @@ -226,12 +253,13 @@ public final class ContentCaptureOptions implements Parcelable { final int idleFlushingFrequencyMs = parcel.readInt(); final int textChangeFlushingFrequencyMs = parcel.readInt(); final int logHistorySize = parcel.readInt(); + final boolean disableFlushForViewTreeAppearing = parcel.readBoolean(); @SuppressWarnings("unchecked") final ArraySet<ComponentName> whitelistedComponents = (ArraySet<ComponentName>) parcel.readArraySet(null); return new ContentCaptureOptions(loggingLevel, maxBufferSize, idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize, - whitelistedComponents); + disableFlushForViewTreeAppearing, whitelistedComponents); } @Override diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 59b5286f6fc5..34c7b8b9889f 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -82,11 +82,19 @@ public final class ContentCaptureContext implements Parcelable { @SystemApi public static final int FLAG_RECONNECTED = 0x4; + /** + * Flag used to disable flush when receiving a VIEW_TREE_APPEARING event. + * + * @hide + */ + public static final int FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING = 1 << 3; + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DISABLED_BY_APP, FLAG_DISABLED_BY_FLAG_SECURE, - FLAG_RECONNECTED + FLAG_RECONNECTED, + FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING }) @Retention(RetentionPolicy.SOURCE) @interface ContextCreationFlags{} @@ -252,7 +260,8 @@ public final class ContentCaptureContext implements Parcelable { * Gets the flags associated with this context. * * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE}, - * {@link #FLAG_DISABLED_BY_APP} and {@link #FLAG_RECONNECTED}. + * {@link #FLAG_DISABLED_BY_APP}, {@link #FLAG_RECONNECTED} and {@link + * #FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING}. * * @hide */ diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 497f0668107f..668351b949c1 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -51,6 +51,7 @@ import android.view.WindowManager; import android.view.contentcapture.ContentCaptureSession.FlushReason; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.SyncResultReceiver; import java.io.PrintWriter; @@ -343,6 +344,14 @@ public final class ContentCaptureManager { */ public static final String DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT = "idle_unbind_timeout"; + /** + * Sets to disable flush when receiving a VIEW_TREE_APPEARING event. + * + * @hide + */ + public static final String DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = + "disable_flush_for_view_tree_appearing"; + /** @hide */ @TestApi public static final int LOGGING_LEVEL_OFF = 0; @@ -373,6 +382,8 @@ public final class ContentCaptureManager { public static final int DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS = 1_000; /** @hide */ public static final int DEFAULT_LOG_HISTORY_SIZE = 10; + /** @hide */ + public static final boolean DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = false; private final Object mLock = new Object(); @@ -448,6 +459,7 @@ public final class ContentCaptureManager { mOptions = Objects.requireNonNull(options, "options cannot be null"); ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel); + setFlushViewTreeAppearingEventDisabled(mOptions.disableFlushForViewTreeAppearing); if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName()); @@ -687,6 +699,38 @@ public final class ContentCaptureManager { } /** + * Explicitly sets enable or disable flush for view tree appearing event. + * + * @hide + */ + @VisibleForTesting + public void setFlushViewTreeAppearingEventDisabled(boolean disabled) { + if (sDebug) { + Log.d(TAG, "setFlushViewTreeAppearingEventDisabled(): setting to " + disabled); + } + + synchronized (mLock) { + if (disabled) { + mFlags |= ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING; + } else { + mFlags &= ~ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING; + } + } + } + + /** + * Gets whether content capture is needed to flush for view tree appearing event. + * + * @hide + */ + public boolean getFlushViewTreeAppearingEventDisabled() { + synchronized (mLock) { + return (mFlags & ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING) + != 0; + } + } + + /** * Gets whether content capture is enabled for the given user. * * <p>This method is typically used by the content capture service settings page, so it can diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 2134d819943e..bdec1970eda9 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -170,6 +170,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { public static final int FLUSH_REASON_TEXT_CHANGE_TIMEOUT = 6; /** @hide */ public static final int FLUSH_REASON_SESSION_CONNECTED = 7; + /** @hide */ + public static final int FLUSH_REASON_FORCE_FLUSH = 8; + /** @hide */ + public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9; + /** @hide */ + public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10; /** @hide */ @IntDef(prefix = { "FLUSH_REASON_" }, value = { @@ -179,7 +185,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { FLUSH_REASON_SESSION_FINISHED, FLUSH_REASON_IDLE_TIMEOUT, FLUSH_REASON_TEXT_CHANGE_TIMEOUT, - FLUSH_REASON_SESSION_CONNECTED + FLUSH_REASON_SESSION_CONNECTED, + FLUSH_REASON_FORCE_FLUSH, + FLUSH_REASON_VIEW_TREE_APPEARING, + FLUSH_REASON_VIEW_TREE_APPEARED }) @Retention(RetentionPolicy.SOURCE) public @interface FlushReason{} @@ -614,6 +623,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { return "TEXT_CHANGE"; case FLUSH_REASON_SESSION_CONNECTED: return "CONNECTED"; + case FLUSH_REASON_FORCE_FLUSH: + return "FORCE_FLUSH"; + case FLUSH_REASON_VIEW_TREE_APPEARING: + return "VIEW_TREE_APPEARING"; + case FLUSH_REASON_VIEW_TREE_APPEARED: + return "VIEW_TREE_APPEARED"; default: return "UNKOWN-" + reason; } diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 1f5e462d71fd..9848acd8dfcc 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -458,6 +458,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { case ContentCaptureEvent.TYPE_SESSION_FINISHED: flushReason = FLUSH_REASON_SESSION_FINISHED; break; + case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING: + flushReason = FLUSH_REASON_VIEW_TREE_APPEARING; + break; + case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED: + flushReason = FLUSH_REASON_VIEW_TREE_APPEARED; + break; default: flushReason = FLUSH_REASON_FULL; } @@ -764,7 +770,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { /** Public because is also used by ViewRootImpl */ public void notifyViewTreeEvent(int sessionId, boolean started) { final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED; - mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH)); + final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled(); + + mHandler.post(() -> sendEvent( + new ContentCaptureEvent(sessionId, type), + disableFlush ? !started : FORCE_FLUSH)); } void notifySessionResumed(int sessionId) { diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java index eae1bbc930d4..17ed4c478350 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java @@ -15,6 +15,8 @@ */ package android.view.contentcapture; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.testng.Assert.assertThrows; @@ -54,4 +56,19 @@ public class ContentCaptureManagerTest { assertThrows(NullPointerException.class, () -> manager.removeData(null)); } + + @Test + @SuppressWarnings("GuardedBy") + public void testFlushViewTreeAppearingEventDisabled_setAndGet() { + final IContentCaptureManager mockService = mock(IContentCaptureManager.class); + final ContentCaptureOptions options = new ContentCaptureOptions(null); + final ContentCaptureManager manager = + new ContentCaptureManager(mMockContext, mockService, options); + + assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse(); + manager.setFlushViewTreeAppearingEventDisabled(true); + assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isTrue(); + manager.setFlushViewTreeAppearingEventDisabled(false); + assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse(); + } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index ff1a495edcbb..802574828d15 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -168,6 +168,7 @@ public final class ContentCaptureManagerService extends @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs; @GuardedBy("mLock") int mDevCfgLogHistorySize; @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs; + @GuardedBy("mLock") boolean mDevCfgDisableFlushForViewTreeAppearing; private final Executor mDataShareExecutor = Executors.newCachedThreadPool(); private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -358,6 +359,8 @@ public final class ContentCaptureManagerService extends case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE: case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY: case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT: + case ContentCaptureManager + .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING: setFineTuneParamsFromDeviceConfig(); return; default: @@ -387,13 +390,20 @@ public final class ContentCaptureManagerService extends DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT, (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS); + mDevCfgDisableFlushForViewTreeAppearing = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + ContentCaptureManager + .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING, + false); if (verbose) { Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): " + "bufferSize=" + mDevCfgMaxBufferSize + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs + ", logHistory=" + mDevCfgLogHistorySize - + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs); + + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs + + ", disableFlushForViewTreeAppearing=" + + mDevCfgDisableFlushForViewTreeAppearing); } } } @@ -628,6 +638,7 @@ public final class ContentCaptureManagerService extends } @Override // from AbstractMasterSystemService + @GuardedBy("mLock") protected void dumpLocked(String prefix, PrintWriter pw) { super.dumpLocked(prefix, pw); @@ -645,6 +656,8 @@ public final class ContentCaptureManagerService extends pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize); pw.print(prefix2); pw.print("idleUnbindTimeoutMs: "); pw.println(mDevCfgIdleUnbindTimeoutMs); + pw.print(prefix2); pw.print("disableFlushForViewTreeAppearing: "); + pw.println(mDevCfgDisableFlushForViewTreeAppearing); pw.print(prefix); pw.println("Global Options:"); mGlobalContentCaptureOptions.dump(prefix2, pw); } @@ -1003,12 +1016,15 @@ public final class ContentCaptureManagerService extends return null; } - final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel, - mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs, - mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, - whitelistedComponents); - if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); - return options; + synchronized (mLock) { + final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel, + mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs, + mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, + mDevCfgDisableFlushForViewTreeAppearing, + whitelistedComponents); + if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); + return options; + } } @Override |