Merge "Fix build break" into pi-dev
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 88300db..4c7dc11 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1132,8 +1132,7 @@
if (mSaveTriggerId != null && mSaveTriggerId.equals(id)) {
if (sDebug) Log.d(TAG, "triggering commit by click of " + id);
commitLocked();
- mMetricsLogger.action(MetricsEvent.AUTOFILL_SAVE_EXPLICITLY_TRIGGERED,
- mContext.getPackageName());
+ mMetricsLogger.write(newLog(MetricsEvent.AUTOFILL_SAVE_EXPLICITLY_TRIGGERED));
}
}
}
@@ -1893,14 +1892,19 @@
}
}
- final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_DATASET_APPLIED)
- .setPackageName(mContext.getPackageName())
+ mMetricsLogger.write(newLog(MetricsEvent.AUTOFILL_DATASET_APPLIED)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount)
- .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied);
- mMetricsLogger.write(log);
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied));
}
}
+ private LogMaker newLog(int category) {
+ return new LogMaker(category)
+ .setPackageName(mContext.getPackageName())
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE,
+ isCompatibilityModeEnabledLocked() ? 1 : 0);
+ }
+
/**
* Set the tracked views.
*
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 30a17a1..f066e34 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -57,6 +57,7 @@
import androidx.slice.Slice;
import androidx.slice.SliceItem;
+import androidx.slice.SliceManager;
import androidx.slice.core.SliceQuery;
import androidx.slice.widget.ListContent;
import androidx.slice.widget.RowContent;
@@ -390,6 +391,11 @@
}
}
+ public void refresh() {
+ Slice slice = SliceManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
+ onChanged(slice);
+ }
+
public static class Row extends LinearLayout {
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 454528e..f6b5d69 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -287,7 +287,12 @@
}
}
- public void refreshTime() {
+ public void dozeTimeTick() {
+ refreshTime();
+ mKeyguardSlice.refresh();
+ }
+
+ private void refreshTime() {
mClockView.refresh();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index f867b34..c5e66f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -79,7 +79,6 @@
private DateFormat mDateFormat;
private String mLastText;
private boolean mRegistered;
- private boolean mRegisteredEveryMinute;
private String mNextAlarm;
private NextAlarmController mNextAlarmController;
protected AlarmManager mAlarmManager;
@@ -175,7 +174,7 @@
mZenModeController = new ZenModeControllerImpl(getContext(), mHandler);
mZenModeController.addCallback(this);
mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
- registerClockUpdate(false /* everyMinute */);
+ registerClockUpdate();
updateClock();
return true;
}
@@ -214,22 +213,13 @@
/**
* Registers a broadcast receiver for clock updates, include date, time zone and manually
* changing the date/time via the settings app.
- *
- * @param everyMinute {@code true} if you also want updates every minute.
*/
- protected void registerClockUpdate(boolean everyMinute) {
+ private void registerClockUpdate() {
if (mRegistered) {
- if (mRegisteredEveryMinute == everyMinute) {
- return;
- } else {
- unregisterClockUpdate();
- }
+ return;
}
IntentFilter filter = new IntentFilter();
- if (everyMinute) {
- filter.addAction(Intent.ACTION_TIME_TICK);
- }
filter.addAction(Intent.ACTION_DATE_CHANGED);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
@@ -237,15 +227,6 @@
getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
null /* scheduler */);
mRegistered = true;
- mRegisteredEveryMinute = everyMinute;
- }
-
- protected void unregisterClockUpdate() {
- if (!mRegistered) {
- return;
- }
- getContext().unregisterReceiver(mIntentReceiver);
- mRegistered = false;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 9fcb090..ee83250 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -212,7 +212,7 @@
}
public void hideClock(boolean animate) {
- animateHide(mClockView, animate);
+ animateHiddenState(mClockView, View.GONE, animate);
}
public void showClock(boolean animate) {
@@ -240,21 +240,29 @@
}
/**
- * Hides a view.
+ * Animate a view to INVISIBLE or GONE
*/
- private void animateHide(final View v, boolean animate) {
+ private void animateHiddenState(final View v, int state, boolean animate) {
v.animate().cancel();
if (!animate) {
v.setAlpha(0f);
- v.setVisibility(View.INVISIBLE);
+ v.setVisibility(state);
return;
}
+
v.animate()
.alpha(0f)
.setDuration(160)
.setStartDelay(0)
.setInterpolator(Interpolators.ALPHA_OUT)
- .withEndAction(() -> v.setVisibility(View.INVISIBLE));
+ .withEndAction(() -> v.setVisibility(state));
+ }
+
+ /**
+ * Hides a view.
+ */
+ private void animateHide(final View v, boolean animate) {
+ animateHiddenState(v, View.INVISIBLE, animate);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b650944..b475b64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2267,7 +2267,7 @@
}
public void onScreenTurningOn() {
- mKeyguardStatusView.refreshTime();
+ mKeyguardStatusView.dozeTimeTick();
}
@Override
@@ -2690,7 +2690,7 @@
}
public void dozeTimeTick() {
- mKeyguardStatusView.refreshTime();
+ mKeyguardStatusView.dozeTimeTick();
mKeyguardBottomArea.dozeTimeTick();
if (mDarkAmount > 0) {
positionClockAndNotifications();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 210764a..17a4fbc 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -90,6 +90,17 @@
}
@Test
+ public void refresh_replacesSliceContentAndNotifiesListener() {
+ AtomicBoolean notified = new AtomicBoolean();
+ mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
+ notified.set(true);
+ });
+ mKeyguardSliceView.refresh();
+ Assert.assertTrue("Listener should be notified about slice changes.",
+ notified.get());
+ }
+
+ @Test
public void getTextColor_whiteTextWhenAOD() {
// Set text color to red since the default is white and test would always pass
mKeyguardSliceView.setTextColor(Color.RED);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
new file mode 100644
index 0000000..1d8de2f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.Mockito.verify;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.widget.TextClock;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardStatusViewTest extends SysuiTestCase {
+
+ @Mock
+ KeyguardSliceView mKeyguardSlice;
+ @Mock
+ TextClock mClockView;
+ @InjectMocks
+ KeyguardStatusView mKeyguardStatusView;
+
+ @Before
+ public void setUp() {
+ LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+ mKeyguardStatusView =
+ (KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null);
+ org.mockito.MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void dozeTimeTick_updatesSlice() {
+ mKeyguardStatusView.dozeTimeTick();
+ verify(mKeyguardSlice).refresh();
+ }
+
+ @Test
+ public void dozeTimeTick_updatesClock() {
+ mKeyguardStatusView.dozeTimeTick();
+ verify(mClockView).refresh();
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index a45e690..46e2bfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -85,13 +85,6 @@
}
@Test
- public void unregisterClockUpdate() {
- mProvider.unregisterClockUpdate();
- Assert.assertFalse("Clock updates should have been unregistered.",
- mProvider.isRegistered());
- }
-
- @Test
public void returnsValidSlice() {
Slice slice = mProvider.onBindSlice(mProvider.getUri());
SliceItem text = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_TEXT,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 9e8fa22..231cdf5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -121,7 +121,7 @@
fragment.initNotificationIconArea(mMockNotificiationAreaController);
fragment.disable(StatusBarManager.DISABLE_CLOCK, 0, false);
- assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+ assertEquals(View.GONE, mFragment.getView().findViewById(R.id.clock).getVisibility());
fragment.disable(0, 0, false);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d61f228..1541231 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3967,6 +3967,7 @@
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// NOTE: starting on OS P, it also added the following field:
// Tag FIELD_FLAGS - Flags used to start the session
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SESSION_STARTED = 906;
// An autofill request was processed by a service
@@ -3980,6 +3981,7 @@
// Type TYPE_CLOSE: Service returned a null response.
// Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
// number of entries field ids in the request.
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_REQUEST = 907;
// Tag of a field for a package of an autofill service
@@ -3998,6 +4000,7 @@
// Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
// NOTE: starting on OS P, it also added the following field:
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_FILL_UI = 910;
// Tag of a field for the length of the filter text
@@ -4005,12 +4008,17 @@
// An autofill authentication succeeded
// Package: Package of app that was autofilled
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_AUTHENTICATED = 912;
// An activity was autofilled and all values could be applied
// Package: Package of app that is autofilled
// Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
// Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_DATASET_APPLIED = 913;
// Tag of a field for the number values to be filled in
@@ -4027,6 +4035,7 @@
// Tag FIELD_AUTOFILL_NUM_IDS: The number of ids that are saved
// NOTE: starting on OS P, it also added the following field:
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SAVE_UI = 916;
// Tag of a field for the number of saveable ids
@@ -4038,10 +4047,14 @@
// Type TYPE_FAILURE: The request failed
// Package: Package of app that was autofilled
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_DATA_SAVE_REQUEST = 918;
// An auto-fill session was finished
// Package: Package of app that was autofilled
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SESSION_FINISHED = 919;
// meta-event: a reader has checkpointed the log here.
@@ -4167,6 +4180,8 @@
// Package: Real package of the app being autofilled
// Tag FIELD_AUTOFILL_SERVICE: Package of the autofill service that processed the request
// TAG FIELD_AUTOFILL_FORGED_COMPONENT_NAME: Component name being forged
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_FORGED_COMPONENT_ATTEMPT = 948;
// FIELD - The component that an app tried tro forged.
@@ -4624,6 +4639,8 @@
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_PREVIOUS_LENGTH: the previous length of the value
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_VALUE_RESET = 1124;
// Tag of AUTOFILL_VALUE_RESET
@@ -4634,18 +4651,24 @@
// Package: Package of app that was autofilled
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_DATASET_AUTHENTICATED = 1126;
// An autofill service provided an invalid dataset authentication
// Package: Package of app that was autofilled
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127;
// An autofill service provided an invalid authentication extra
// Package: Package of app that was autofilled
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_INVALID_AUTHENTICATION = 1128;
// An autofill service used a custom description (using RemoteViews) in the autofill save UI
@@ -4653,6 +4676,8 @@
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SAVE_CUSTOM_DESCRIPTION = 1129;
// FIELD - Type of save object passed by the service when the Save UI is shown
@@ -4664,6 +4689,8 @@
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SAVE_CUSTOM_SUBTITLE = 1131;
// User tapped a link in the custom description of the autofill save UI provided by an autofill service
@@ -4674,6 +4701,8 @@
// Type TYPE_FAILURE: The link could not launc an activity
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SAVE_LINK_TAPPED = 1132;
// Result of the validation on save when an autofill service provided a validator
@@ -4684,6 +4713,8 @@
// Type TYPE_DISMISS: The validation failed
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SAVE_VALIDATION = 1133;
// Result of an operation in the autofill save UI after the user tapped a link in the custom description
@@ -4693,6 +4724,8 @@
// Type TYPE_OPEN: The autofill save UI was restored
// Type TYPE_DISMISS: The autofill save UI was destroyed
// Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
// Autofill service called API that disables itself
@@ -4705,6 +4738,8 @@
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Package: Package of the autofill service
// OS: O MR
+ // NOTE: starting on OS P, it also added the following field:
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_UI_LATENCY = 1136;
// Action: the snooze leave-behind was shown after the user clicked the snooze icon
@@ -4872,12 +4907,14 @@
// Package: Package of app that is autofilled
// OS: P
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION = 1228;
// The autofill context was commited when the user clicked a view explicitly marked by the
// service as committing it
// Package: Package of app that is autofilled
// OS: P
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SAVE_EXPLICITLY_TRIGGERED = 1229;
// OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
@@ -4890,6 +4927,7 @@
// OS: P
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SERVICE_DISABLED_APP = 1231;
// An autofill service asked to disable autofill for a given activity.
@@ -4898,6 +4936,7 @@
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_CLASS_NAME: Class name of the activity that is being disabled for autofill
// Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_SERVICE_DISABLED_ACTIVITY = 1232;
// ACTION: Stop an app and turn on background check
@@ -5109,6 +5148,7 @@
// OS: P
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// Tag FIELD_AUTOFILL_MATCH_SCORE: Average score of the matches, in the range of 0 to 100
+ // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
AUTOFILL_FIELD_CLASSIFICATION_MATCHES = 1273;
// Tag used to report autofill field classification scores
@@ -5775,6 +5815,9 @@
// OS: P
ACTION_STORAGE_MIGRATE_LATER = 1413;
+ // Tag used to report whether an activity is being autofilled on compatibility mode.
+ FIELD_AUTOFILL_COMPAT_MODE = 1414;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index e582daa..6ff9539 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -504,7 +504,7 @@
sessionId = sRandom.nextInt();
} while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
- assertCallerLocked(componentName);
+ assertCallerLocked(componentName, compatMode);
final Session newSession = new Session(this, mUi, mContext, mHandler, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
@@ -518,7 +518,7 @@
/**
* Asserts the component is owned by the caller.
*/
- private void assertCallerLocked(@NonNull ComponentName componentName) {
+ private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) {
final String packageName = componentName.getPackageName();
final PackageManager pm = mContext.getPackageManager();
final int callingUid = Binder.getCallingUid();
@@ -536,7 +536,7 @@
+ ") passed component (" + componentName + ") owned by UID " + packageUid);
mMetricsLogger.write(
Helper.newLogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT,
- callingPackage, getServicePackageName())
+ callingPackage, getServicePackageName(), compatMode)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
componentName == null ? "null" : componentName.flattenToShortString()));
@@ -774,10 +774,10 @@
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
@Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
- @NonNull String appPackageName) {
+ @NonNull String appPackageName, boolean compatMode) {
logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets,
changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
- manuallyFilledDatasetIds, null, null, appPackageName);
+ manuallyFilledDatasetIds, null, null, appPackageName, compatMode);
}
@GuardedBy("mLock")
@@ -790,7 +790,7 @@
@Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
@Nullable ArrayList<AutofillId> detectedFieldIdsList,
@Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
- @NonNull String appPackageName) {
+ @NonNull String appPackageName, boolean compatMode) {
if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
if (sVerbose) {
Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId
@@ -800,7 +800,8 @@
+ ", changedDatasetIds=" + changedDatasetIds
+ ", manuallyFilledFieldIds=" + manuallyFilledFieldIds
+ ", detectedFieldIds=" + detectedFieldIdsList
- + ", detectedFieldClassifications=" + detectedFieldClassificationsList);
+ + ", detectedFieldClassifications=" + detectedFieldClassificationsList
+ + ", compatMode=" + compatMode);
}
AutofillId[] detectedFieldsIds = null;
FieldClassification[] detectedFieldClassifications = null;
@@ -827,7 +828,7 @@
final int averageScore = (int) ((totalScore * 100) / totalSize);
mMetricsLogger.write(Helper
.newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
- appPackageName, getServicePackageName())
+ appPackageName, getServicePackageName(), compatMode)
.setCounterValue(numberFields)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE,
averageScore));
@@ -1122,7 +1123,7 @@
/**
* Called by {@link Session} when service asked to disable autofill for an app.
*/
- void disableAutofillForApp(@NonNull String packageName, long duration) {
+ void disableAutofillForApp(@NonNull String packageName, long duration, boolean compatMode) {
synchronized (mLock) {
if (mDisabledApps == null) {
mDisabledApps = new ArrayMap<>(1);
@@ -1135,7 +1136,7 @@
mDisabledApps.put(packageName, expiration);
int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
- packageName, getServicePackageName())
+ packageName, getServicePackageName(), compatMode)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
}
}
@@ -1143,7 +1144,8 @@
/**
* Called by {@link Session} when service asked to disable autofill an app.
*/
- void disableAutofillForActivity(@NonNull ComponentName componentName, long duration) {
+ void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
+ boolean compatMode) {
synchronized (mLock) {
if (mDisabledActivities == null) {
mDisabledActivities = new ArrayMap<>(1);
@@ -1160,7 +1162,8 @@
mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
.setComponentName(componentName)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
- .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0));
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 78526f5..5372d0c 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -21,7 +21,6 @@
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.metrics.LogMaker;
-import android.os.Bundle;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -35,10 +34,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.LinkedList;
-import java.util.Objects;
-import java.util.Set;
public final class Helper {
@@ -119,6 +115,13 @@
return log;
}
+ @NonNull
+ public static LogMaker newLogMaker(int category, String packageName,
+ String servicePackageName, boolean compatMode) {
+ return newLogMaker(category, packageName, servicePackageName)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0);
+ }
+
public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable CharSequence text) {
if (text == null) {
pw.println("null");
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c055060..88a679b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -644,9 +644,10 @@
Slog.d(TAG, message.toString());
}
if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) {
- mService.disableAutofillForActivity(mComponentName, disableDuration);
+ mService.disableAutofillForActivity(mComponentName, disableDuration, mCompatMode);
} else {
- mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration);
+ mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
+ mCompatMode);
}
sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE;
}
@@ -1251,7 +1252,7 @@
mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
ignoredDatasets, changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- mComponentName.getPackageName());
+ mComponentName.getPackageName(), mCompatMode);
}
}
@@ -1306,7 +1307,7 @@
mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
ignoredDatasets, changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- mComponentName.getPackageName());
+ mComponentName.getPackageName(), mCompatMode);
return;
}
final Scores scores = result.getParcelable(EXTRA_SCORES);
@@ -1371,7 +1372,7 @@
mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
- mComponentName.getPackageName());
+ mComponentName.getPackageName(), mCompatMode);
});
fcStrategy.getScores(callback, algorithm, algorithmArgs, currentValues, userValues);
@@ -1602,7 +1603,7 @@
getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
mService.getServicePackageName(), saveInfo, this,
mComponentName.getPackageName(), this,
- mPendingSaveUi);
+ mPendingSaveUi, mCompatMode);
if (client != null) {
try {
client.setSaveUiState(id, true);
@@ -2080,7 +2081,7 @@
getUiForShowing().showFillUi(filledId, response, filterText,
mService.getServicePackageName(), mComponentName.getPackageName(),
- mService.getServiceLabel(), mService.getServiceIcon(), this);
+ mService.getServiceLabel(), mService.getServiceIcon(), this, mCompatMode);
synchronized (mLock) {
if (mUiShownTime == 0) {
@@ -2717,7 +2718,8 @@
}
private LogMaker newLogMaker(int category, String servicePackageName) {
- return Helper.newLogMaker(category, mComponentName.getPackageName(), servicePackageName);
+ return Helper.newLogMaker(category, mComponentName.getPackageName(), servicePackageName,
+ mCompatMode);
}
private void writeLog(int category) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index ee18dc2..811d87be 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -170,13 +170,14 @@
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
@Nullable String filterText, @Nullable String servicePackageName,
@NonNull String packageName, @NonNull CharSequence serviceLabel,
- @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback) {
+ @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback, boolean compatMode) {
if (sDebug) {
final int size = filterText == null ? 0 : filterText.length();
Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars");
}
- final LogMaker log =
- Helper.newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, packageName, servicePackageName)
+ final LogMaker log = Helper
+ .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, packageName, servicePackageName,
+ compatMode)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
filterText == null ? 0 : filterText.length())
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
@@ -262,14 +263,16 @@
public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
@Nullable String servicePackageName, @NonNull SaveInfo info,
@NonNull ValueFinder valueFinder, @NonNull String packageName,
- @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi) {
+ @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi,
+ boolean compatMode) {
if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
int numIds = 0;
numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
- final LogMaker log =
- Helper.newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, packageName, servicePackageName)
+ final LogMaker log = Helper
+ .newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, packageName, servicePackageName,
+ compatMode)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
mHandler.post(() -> {
@@ -319,7 +322,7 @@
}
mMetricsLogger.write(log);
}
- });
+ }, compatMode);
});
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 80903c1..fa2a0d9 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -60,6 +60,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.UiThread;
+import com.android.server.autofill.Helper;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -134,6 +135,7 @@
private final PendingUi mPendingUi;
private final String mServicePackageName;
private final String mPackageName;
+ private final boolean mCompatMode;
private boolean mDestroyed;
@@ -141,12 +143,14 @@
@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
@Nullable String servicePackageName, @NonNull String packageName,
@NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
- @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener) {
+ @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener,
+ boolean compatMode) {
mPendingUi= pendingUi;
mListener = new OneTimeListener(listener);
mOverlayControl = overlayControl;
mServicePackageName = servicePackageName;
mPackageName = packageName;
+ mCompatMode = compatMode;
context = new ContextThemeWrapper(context, THEME_ID);
final LayoutInflater inflater = LayoutInflater.from(context);
@@ -409,14 +413,12 @@
}
private LogMaker newLogMaker(int category, int saveType) {
- return newLogMaker(category)
+ return Helper.newLogMaker(category, mPackageName, mServicePackageName, mCompatMode)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType);
}
private LogMaker newLogMaker(int category) {
- return new LogMaker(category)
- .setPackageName(mPackageName)
- .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, mServicePackageName);
+ return Helper.newLogMaker(category, mPackageName, mServicePackageName, mCompatMode);
}
private void writeLog(int category, int saveType) {
@@ -505,6 +507,7 @@
pw.print(prefix); pw.print("pendingUi: "); pw.println(mPendingUi);
pw.print(prefix); pw.print("service: "); pw.println(mServicePackageName);
pw.print(prefix); pw.print("app: "); pw.println(mPackageName);
+ pw.print(prefix); pw.print("compat mode: "); pw.println(mCompatMode);
final View view = mDialog.getWindow().getDecorView();
final int[] loc = view.getLocationOnScreen();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9621edd..c0dc750 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1510,6 +1510,10 @@
return (stack != null && stack.isVisible()) ? stack : null;
}
+ boolean hasSplitScreenPrimaryStack() {
+ return getSplitScreenPrimaryStack() != null;
+ }
+
/**
* Like {@link #getSplitScreenPrimaryStack}, but also returns the stack if it's currently
* not visible.
@@ -1613,6 +1617,18 @@
mService.mWindowsChanged = true;
}
+ /**
+ * In split-screen mode we process the IME containers above the docked divider
+ * rather than directly above their target.
+ */
+ private boolean skipTraverseChild(WindowContainer child) {
+ if (child == mImeWindowsContainers && mService.mInputMethodTarget != null
+ && !hasSplitScreenPrimaryStack()) {
+ return true;
+ }
+ return false;
+ }
+
@Override
boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
// Special handling so we can process IME windows with #forAllImeWindows above their IME
@@ -1620,11 +1636,10 @@
if (traverseTopToBottom) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayChildWindowContainer child = mChildren.get(i);
- if (child == mImeWindowsContainers && mService.mInputMethodTarget != null) {
- // In this case the Ime windows will be processed above their target so we skip
- // here.
+ if (skipTraverseChild(child)) {
continue;
}
+
if (child.forAllWindows(callback, traverseTopToBottom)) {
return true;
}
@@ -1633,11 +1648,10 @@
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
final DisplayChildWindowContainer child = mChildren.get(i);
- if (child == mImeWindowsContainers && mService.mInputMethodTarget != null) {
- // In this case the Ime windows will be processed above their target so we skip
- // here.
+ if (skipTraverseChild(child)) {
continue;
}
+
if (child.forAllWindows(callback, traverseTopToBottom)) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0de3c92..c710c97 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3997,32 +3997,33 @@
return false;
}
+ private boolean applyImeWindowsIfNeeded(ToBooleanFunction<WindowState> callback,
+ boolean traverseTopToBottom) {
+ // If this window is the current IME target, so we need to process the IME windows
+ // directly above it. The exception is if we are in split screen
+ // in which case we process the IME at the DisplayContent level to
+ // ensure it is above the docked divider.
+ if (isInputMethodTarget() && !inSplitScreenWindowingMode()) {
+ if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean applyInOrderWithImeWindows(ToBooleanFunction<WindowState> callback,
boolean traverseTopToBottom) {
if (traverseTopToBottom) {
- if (isInputMethodTarget()) {
- // This window is the current IME target, so we need to process the IME windows
- // directly above it.
- if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
- return true;
- }
- }
- if (callback.apply(this)) {
+ if (applyImeWindowsIfNeeded(callback, traverseTopToBottom)
+ || callback.apply(this)) {
return true;
}
} else {
- if (callback.apply(this)) {
+ if (callback.apply(this)
+ || applyImeWindowsIfNeeded(callback, traverseTopToBottom)) {
return true;
}
- if (isInputMethodTarget()) {
- // This window is the current IME target, so we need to process the IME windows
- // directly above it.
- if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
- return true;
- }
- }
}
-
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
new file mode 100644
index 0000000..e076399
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Matchers.eq;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.mockito.Mock;
+
+import java.util.function.Consumer;
+
+/**
+ * Tests for {@link WindowContainer#forAllWindows} and various implementations.
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowContainerTraversalTests extends WindowTestsBase {
+
+ @Test
+ public void testDockedDividerPosition() throws Exception {
+ final WindowState splitScreenWindow = createWindowOnStack(null,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
+ mDisplayContent, "splitScreenWindow");
+ final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
+ TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
+
+ sWm.mInputMethodTarget = splitScreenWindow;
+
+ Consumer<WindowState> c = mock(Consumer.class);
+ mDisplayContent.forAllWindows(c, false);
+
+ verify(c).accept(eq(mDockedDividerWindow));
+ verify(c).accept(eq(mImeWindow));
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index cd524a5..13e3069 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -46,6 +46,10 @@
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
+import android.media.AudioAttributes;
+import android.media.AudioFormat;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
import android.media.soundtrigger.ISoundTriggerDetectionService;
import android.media.soundtrigger.ISoundTriggerDetectionServiceClient;
import android.media.soundtrigger.SoundTriggerDetectionService;
@@ -654,8 +658,45 @@
}
}
- private interface Operation {
- void run(int opId, ISoundTriggerDetectionService service) throws RemoteException;
+ /**
+ * A single operation run in a {@link RemoteSoundTriggerDetectionService}.
+ *
+ * <p>Once the remote service is connected either setup + execute or setup + stop is executed.
+ */
+ private static class Operation {
+ private interface ExecuteOp {
+ void run(int opId, ISoundTriggerDetectionService service) throws RemoteException;
+ }
+
+ private final @Nullable Runnable mSetupOp;
+ private final @NonNull ExecuteOp mExecuteOp;
+ private final @Nullable Runnable mDropOp;
+
+ private Operation(@Nullable Runnable setupOp, @NonNull ExecuteOp executeOp,
+ @Nullable Runnable cancelOp) {
+ mSetupOp = setupOp;
+ mExecuteOp = executeOp;
+ mDropOp = cancelOp;
+ }
+
+ private void setup() {
+ if (mSetupOp != null) {
+ mSetupOp.run();
+ }
+ }
+
+ void run(int opId, @NonNull ISoundTriggerDetectionService service) throws RemoteException {
+ setup();
+ mExecuteOp.run(opId, service);
+ }
+
+ void drop() {
+ setup();
+
+ if (mDropOp != null) {
+ mDropOp.run();
+ }
+ }
}
/**
@@ -902,6 +943,10 @@
private void runOrAddOperation(Operation op) {
synchronized (mRemoteServiceLock) {
if (mIsDestroyed || mDestroyOnceRunningOpsDone) {
+ Slog.w(TAG, mPuuid + ": Dropped operation as already destroyed or marked for "
+ + "destruction");
+
+ op.drop();
return;
}
@@ -922,9 +967,15 @@
int opsAdded = mNumOps.getOpsAdded();
if (mNumOps.getOpsAdded() >= opsAllowed) {
- if (DEBUG || opsAllowed + 10 > opsAdded) {
- Slog.w(TAG, mPuuid + ": Dropped operation as too many operations were "
- + "run in last 24 hours");
+ try {
+ if (DEBUG || opsAllowed + 10 > opsAdded) {
+ Slog.w(TAG, mPuuid + ": Dropped operation as too many operations "
+ + "were run in last 24 hours");
+ }
+
+ op.drop();
+ } catch (Exception e) {
+ Slog.e(TAG, mPuuid + ": Could not drop operation", e);
}
} else {
mNumOps.addOp(currentTime);
@@ -972,34 +1023,87 @@
+ ")");
}
+ /**
+ * Create an AudioRecord enough for starting and releasing the data buffered for the event.
+ *
+ * @param event The event that was received
+ * @return The initialized AudioRecord
+ */
+ private @NonNull AudioRecord createAudioRecordForEvent(
+ @NonNull SoundTrigger.GenericRecognitionEvent event) {
+ AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder();
+ attributesBuilder.setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD);
+ AudioAttributes attributes = attributesBuilder.build();
+
+ // Use same AudioFormat processing as in RecognitionEvent.fromParcel
+ AudioFormat originalFormat = event.getCaptureFormat();
+ AudioFormat captureFormat = (new AudioFormat.Builder())
+ .setChannelMask(originalFormat.getChannelMask())
+ .setEncoding(originalFormat.getEncoding())
+ .setSampleRate(originalFormat.getSampleRate())
+ .build();
+
+ int bufferSize = AudioRecord.getMinBufferSize(
+ captureFormat.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
+ ? AudioFormat.SAMPLE_RATE_HZ_MAX
+ : captureFormat.getSampleRate(),
+ captureFormat.getChannelCount() == 2
+ ? AudioFormat.CHANNEL_IN_STEREO
+ : AudioFormat.CHANNEL_IN_MONO,
+ captureFormat.getEncoding());
+
+ return new AudioRecord(attributes, captureFormat, bufferSize,
+ event.getCaptureSession());
+ }
+
@Override
public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
if (DEBUG) Slog.v(TAG, mPuuid + ": Generic sound trigger event: " + event);
- runOrAddOperation((opId, service) -> {
- if (!mRecognitionConfig.allowMultipleTriggers) {
- synchronized (mCallbacksLock) {
- mCallbacks.remove(mPuuid.getUuid());
- }
- mDestroyOnceRunningOpsDone = true;
- }
+ runOrAddOperation(new Operation(
+ // always execute:
+ () -> {
+ if (!mRecognitionConfig.allowMultipleTriggers) {
+ // Unregister this remoteService once op is done
+ synchronized (mCallbacksLock) {
+ mCallbacks.remove(mPuuid.getUuid());
+ }
+ mDestroyOnceRunningOpsDone = true;
+ }
+ },
+ // execute if not throttled:
+ (opId, service) -> service.onGenericRecognitionEvent(mPuuid, opId, event),
+ // execute if throttled:
+ () -> {
+ if (event.isCaptureAvailable()) {
+ AudioRecord capturedData = createAudioRecordForEvent(event);
- service.onGenericRecognitionEvent(mPuuid, opId, event);
- });
+ // Currently we need to start and release the audio record to reset
+ // the DSP even if we don't want to process the event
+ capturedData.startRecording();
+ capturedData.release();
+ }
+ }));
}
@Override
public void onError(int status) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status);
- runOrAddOperation((opId, service) -> {
- synchronized (mCallbacksLock) {
- mCallbacks.remove(mPuuid.getUuid());
- }
- mDestroyOnceRunningOpsDone = true;
-
- service.onError(mPuuid, opId, status);
- });
+ runOrAddOperation(
+ new Operation(
+ // always execute:
+ () -> {
+ // Unregister this remoteService once op is done
+ synchronized (mCallbacksLock) {
+ mCallbacks.remove(mPuuid.getUuid());
+ }
+ mDestroyOnceRunningOpsDone = true;
+ },
+ // execute if not throttled:
+ (opId, service) -> service.onError(mPuuid, opId, status),
+ // nothing to do if throttled
+ null));
}
@Override