diff options
88 files changed, 1555 insertions, 1550 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 07a99084e9d5..2aa2275cc67b 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -2182,17 +2182,18 @@ public class JobSchedulerService extends com.android.server.SystemService } final boolean jobExists = mJobs.containsJob(job); - final boolean userStarted = areUsersStartedLocked(job); + final boolean backingUp = mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0; if (DEBUG) { Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString() - + " exists=" + jobExists + " userStarted=" + userStarted); + + " exists=" + jobExists + " userStarted=" + userStarted + + " backingUp=" + backingUp); } // These are also fairly cheap to check, though they typically will not // be conditions we fail. - if (!jobExists || !userStarted) { + if (!jobExists || !userStarted || backingUp) { return false; } @@ -2265,15 +2266,17 @@ public class JobSchedulerService extends com.android.server.SystemService final boolean jobExists = mJobs.containsJob(job); final boolean userStarted = areUsersStartedLocked(job); + final boolean backingUp = mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0; if (DEBUG) { Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString() - + " exists=" + jobExists + " userStarted=" + userStarted); + + " exists=" + jobExists + " userStarted=" + userStarted + + " backingUp=" + backingUp); } // These are also fairly cheap to check, though they typically will not // be conditions we fail. - if (!jobExists || !userStarted) { + if (!jobExists || !userStarted || backingUp) { return false; } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 6e8ceb7cb367..b4519b769b7c 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -291,7 +291,14 @@ cc_binary { cc_test { name: "statsd_test", defaults: ["statsd_defaults"], - test_suites: ["device-tests"], + test_suites: ["device-tests", "mts"], + + //TODO(b/153588990): Remove when the build system properly separates + //32bit and 64bit architectures. + multilib: { + lib32: { suffix: "32", }, + lib64: { suffix: "64", }, + }, cflags: [ "-Wall", diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index d79b6a21c19f..e3945334aeca 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -38,20 +38,27 @@ using std::make_shared; shared_ptr<StatsService> gStatsService = nullptr; -void sigHandler(int sig) { - if (gStatsService != nullptr) { - gStatsService->Terminate(); +void signalHandler(int sig) { + if (sig == SIGPIPE) { + // ShellSubscriber uses SIGPIPE as a signal to detect the end of the + // client process. Don't prematurely exit(1) here. Instead, ignore the + // signal and allow the write call to return EPIPE. + ALOGI("statsd received SIGPIPE. Ignoring signal."); + return; } + + if (gStatsService != nullptr) gStatsService->Terminate(); ALOGW("statsd terminated on receiving signal %d.", sig); exit(1); } -void registerSigHandler() +void registerSignalHandlers() { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; - sa.sa_handler = sigHandler; + sa.sa_handler = signalHandler; + sigaction(SIGPIPE, &sa, nullptr); sigaction(SIGHUP, &sa, nullptr); sigaction(SIGINT, &sa, nullptr); sigaction(SIGQUIT, &sa, nullptr); @@ -79,7 +86,7 @@ int main(int /*argc*/, char** /*argv*/) { return -1; } - registerSigHandler(); + registerSignalHandlers(); gStatsService->sayHiToStatsCompanion(); diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index f216db6fc717..29a98faf5cd1 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -980,16 +980,10 @@ public final class BluetoothAdapter { @Override protected Integer recompute(Void query) { try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getState(); - } + return mService.getState(); } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); + throw e.rethrowFromSystemServer(); } - return BluetoothAdapter.STATE_OFF; } }; @@ -1004,6 +998,30 @@ public final class BluetoothAdapter { } /** + * Fetch the current bluetooth state. If the service is down, return + * OFF. + */ + @AdapterState + private int getStateInternal() { + int state = BluetoothAdapter.STATE_OFF; + try { + mServiceLock.readLock().lock(); + if (mService != null) { + state = mBluetoothGetStateCache.query(null); + } + } catch (RuntimeException e) { + if (e.getCause() instanceof RemoteException) { + Log.e(TAG, "", e.getCause()); + } else { + throw e; + } + } finally { + mServiceLock.readLock().unlock(); + } + return state; + } + + /** * Get the current state of the local Bluetooth adapter. * <p>Possible return values are * {@link #STATE_OFF}, @@ -1016,7 +1034,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { - int state = mBluetoothGetStateCache.query(null); + int state = getStateInternal(); // Consider all internal states as OFF if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON @@ -1054,7 +1072,7 @@ public final class BluetoothAdapter { @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " + "whether you can use BLE & BT classic.") public int getLeState() { - int state = mBluetoothGetStateCache.query(null); + int state = getStateInternal(); if (VDBG) { Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index d6d9fc628ac9..dbbe4b61c81c 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -123,7 +123,7 @@ public final class ImeFocusController { } // Update mNextServedView when focusedView changed. final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; - onViewFocusChanged(viewForWindowFocus, viewForWindowFocus.hasFocus()); + onViewFocusChanged(viewForWindowFocus, true); immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus, windowAttribute.softInputMode, windowAttribute.flags, forceFocus); diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java index b81e47303a9d..b1e356d258ee 100644 --- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java @@ -300,30 +300,26 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { } private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) { - UserHandle listUserHandle = activeListAdapter.getUserHandle(); - - if (UserHandle.myUserId() != listUserHandle.getIdentifier()) { - if (!mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(), - UserHandle.myUserId(), listUserHandle.getIdentifier())) { - if (listUserHandle.equals(mPersonalProfileUserHandle)) { - DevicePolicyEventLogger.createEvent( - DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL) - .setStrings(getMetricsCategory()) - .write(); - showNoWorkToPersonalIntentsEmptyState(activeListAdapter); - } else { - DevicePolicyEventLogger.createEvent( - DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK) - .setStrings(getMetricsCategory()) - .write(); - showNoPersonalToWorkIntentsEmptyState(activeListAdapter); - } - return false; - } + if (shouldShowNoCrossProfileIntentsEmptyState(activeListAdapter)) { + activeListAdapter.postListReadyRunnable(doPostProcessing); + return false; } return activeListAdapter.rebuildList(doPostProcessing); } + private boolean shouldShowNoCrossProfileIntentsEmptyState( + ResolverListAdapter activeListAdapter) { + UserHandle listUserHandle = activeListAdapter.getUserHandle(); + return UserHandle.myUserId() != listUserHandle.getIdentifier() + && allowShowNoCrossProfileIntentsEmptyState() + && !mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(), + UserHandle.myUserId(), listUserHandle.getIdentifier()); + } + + boolean allowShowNoCrossProfileIntentsEmptyState() { + return true; + } + protected abstract void showWorkProfileOffEmptyState( ResolverListAdapter activeListAdapter, View.OnClickListener listener); @@ -353,12 +349,35 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { * anyway. */ void showEmptyResolverListEmptyState(ResolverListAdapter listAdapter) { + if (maybeShowNoCrossProfileIntentsEmptyState(listAdapter)) { + return; + } if (maybeShowWorkProfileOffEmptyState(listAdapter)) { return; } maybeShowNoAppsAvailableEmptyState(listAdapter); } + private boolean maybeShowNoCrossProfileIntentsEmptyState(ResolverListAdapter listAdapter) { + if (!shouldShowNoCrossProfileIntentsEmptyState(listAdapter)) { + return false; + } + if (listAdapter.getUserHandle().equals(mPersonalProfileUserHandle)) { + DevicePolicyEventLogger.createEvent( + DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL) + .setStrings(getMetricsCategory()) + .write(); + showNoWorkToPersonalIntentsEmptyState(listAdapter); + } else { + DevicePolicyEventLogger.createEvent( + DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK) + .setStrings(getMetricsCategory()) + .write(); + showNoPersonalToWorkIntentsEmptyState(listAdapter); + } + return true; + } + /** * Returns {@code true} if the work profile off empty state screen is shown. */ diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 3e7f24b034ac..d851a099d0e1 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -2171,7 +2171,7 @@ public class ChooserActivity extends ResolverActivity implements mChooserMultiProfilePagerAdapter.getActiveListAdapter(); if (currentListAdapter != null) { currentListAdapter.updateModel(info.getResolvedComponentName()); - currentListAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(), + currentListAdapter.updateChooserCounts(ri.activityInfo.packageName, targetIntent.getAction()); } if (DEBUG) { diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index dd3a6603f46a..1bc982cdb42b 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -179,6 +179,7 @@ public class ResolverActivity extends Activity implements public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device"; private BroadcastReceiver mWorkProfileStateReceiver; + private boolean mIsHeaderCreated; /** * Get the string resource to be used as a label for the link to the resolver activity for an @@ -479,13 +480,42 @@ public class ResolverActivity extends Activity implements == workProfileUserHandle.getIdentifier()), mUseLayoutForBrowsables, /* userHandle */ workProfileUserHandle); + // In the edge case when we have 0 apps in the current profile and >1 apps in the other, + // the intent resolver is started in the other profile. Since this is the only case when + // this happens, we check for it here and set the current profile's tab. + int selectedProfile = getCurrentProfile(); + UserHandle intentUser = UserHandle.of(getLaunchingUserId()); + if (!getUser().equals(intentUser)) { + if (getPersonalProfileUserHandle().equals(intentUser)) { + selectedProfile = PROFILE_PERSONAL; + } else if (getWorkProfileUserHandle().equals(intentUser)) { + selectedProfile = PROFILE_WORK; + } + } return new ResolverMultiProfilePagerAdapter( /* context */ this, personalAdapter, workAdapter, - /* defaultProfile */ getCurrentProfile(), + selectedProfile, getPersonalProfileUserHandle(), - getWorkProfileUserHandle()); + getWorkProfileUserHandle(), + /* shouldShowNoCrossProfileIntentsEmptyState= */ getUser().equals(intentUser)); + } + + /** + * Returns the user id of the user that the starting intent originated from. + * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()}, + * as there are edge cases when the intent resolver is launched in the other profile. + * For example, when we have 0 resolved apps in current profile and multiple resolved apps + * in the other profile, opening a link from the current profile launches the intent resolver + * in the other one. b/148536209 for more info. + */ + private int getLaunchingUserId() { + int contentUserHint = getIntent().getContentUserHint(); + if (contentUserHint == UserHandle.USER_CURRENT) { + return UserHandle.myUserId(); + } + return contentUserHint; } protected @Profile int getCurrentProfile() { @@ -856,7 +886,7 @@ public class ResolverActivity extends Activity implements private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos, boolean filtered) { - if (mMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) { + if (!mMultiProfilePagerAdapter.getCurrentUserHandle().equals(getUser())) { // Never allow the inactive profile to always open an app. mAlwaysButton.setEnabled(false); return; @@ -995,10 +1025,7 @@ public class ResolverActivity extends Activity implements mMultiProfilePagerAdapter.showListView(listAdapter); } if (doPostProcessing) { - if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() - == UserHandle.myUserId()) { - setHeader(); - } + maybeCreateHeader(listAdapter); resetButtonBar(); onListRebuilt(listAdapter); } @@ -1679,10 +1706,15 @@ public class ResolverActivity extends Activity implements /** * Configure the area above the app selection list (title, content preview, etc). + * <p>The header is created once when first launching the activity and whenever a package is + * installed or uninstalled. */ - public void setHeader() { - if (mMultiProfilePagerAdapter.getActiveListAdapter().getCount() == 0 - && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0) { + private void maybeCreateHeader(ResolverListAdapter listAdapter) { + if (mIsHeaderCreated) { + return; + } + if (!shouldShowTabs() + && listAdapter.getCount() == 0 && listAdapter.getPlaceholderCount() == 0) { final TextView titleView = findViewById(R.id.title); if (titleView != null) { titleView.setVisibility(View.GONE); @@ -1703,8 +1735,9 @@ public class ResolverActivity extends Activity implements final ImageView iconView = findViewById(R.id.icon); if (iconView != null) { - mMultiProfilePagerAdapter.getActiveListAdapter().loadFilteredItemIconTaskAsync(iconView); + listAdapter.loadFilteredItemIconTaskAsync(iconView); } + mIsHeaderCreated = true; } protected void resetButtonBar() { @@ -1804,6 +1837,7 @@ public class ResolverActivity extends Activity implements // turning on. return; } + mIsHeaderCreated = false; boolean listRebuilt = mMultiProfilePagerAdapter.rebuildActiveTab(true); if (listRebuilt) { ResolverListAdapter activeListAdapter = diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index 579abeecad13..73109c5c1fbc 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -165,8 +165,9 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListController.updateModel(componentName); } - public void updateChooserCounts(String packageName, int userId, String action) { - mResolverListController.updateChooserCounts(packageName, userId, action); + public void updateChooserCounts(String packageName, String action) { + mResolverListController.updateChooserCounts( + packageName, getUserHandle().getIdentifier(), action); } List<ResolvedComponentInfo> getUnfilteredResolveList() { diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java index b690a18f2d0e..ad31d8b2e49a 100644 --- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java @@ -35,6 +35,7 @@ import com.android.internal.widget.PagerAdapter; public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter { private final ResolverProfileDescriptor[] mItems; + private final boolean mShouldShowNoCrossProfileIntentsEmptyState; ResolverMultiProfilePagerAdapter(Context context, ResolverListAdapter adapter, @@ -44,6 +45,7 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA mItems = new ResolverProfileDescriptor[] { createProfileDescriptor(adapter) }; + mShouldShowNoCrossProfileIntentsEmptyState = true; } ResolverMultiProfilePagerAdapter(Context context, @@ -51,13 +53,15 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA ResolverListAdapter workAdapter, @Profile int defaultProfile, UserHandle personalProfileUserHandle, - UserHandle workProfileUserHandle) { + UserHandle workProfileUserHandle, + boolean shouldShowNoCrossProfileIntentsEmptyState) { super(context, /* currentPage */ defaultProfile, personalProfileUserHandle, workProfileUserHandle); mItems = new ResolverProfileDescriptor[] { createProfileDescriptor(personalAdapter), createProfileDescriptor(workAdapter) }; + mShouldShowNoCrossProfileIntentsEmptyState = shouldShowNoCrossProfileIntentsEmptyState; } private ResolverProfileDescriptor createProfileDescriptor( @@ -163,6 +167,11 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA } @Override + boolean allowShowNoCrossProfileIntentsEmptyState() { + return mShouldShowNoCrossProfileIntentsEmptyState; + } + + @Override protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter, View.OnClickListener listener) { showEmptyState(activeListAdapter, diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java index ea41618a982f..9bdbdc70d74d 100644 --- a/core/java/com/android/internal/app/procstats/DumpUtils.java +++ b/core/java/com/android/internal/app/procstats/DumpUtils.java @@ -534,9 +534,31 @@ public final class DumpUtils { int procStateIndex = curState % STATE_COUNT; // Remap process state per array above. - procStateIndex = PROCESS_STATS_STATE_TO_AGGREGATED_STATE[procStateIndex]; + try { + procStateIndex = PROCESS_STATS_STATE_TO_AGGREGATED_STATE[procStateIndex]; + } catch (IndexOutOfBoundsException e) { + procStateIndex = ProcessStatsEnums.AGGREGATED_PROCESS_STATE_UNKNOWN; + } // Pack screen & process state using bit shifting - return (procStateIndex << 8) | screenStateIndex; + return (procStateIndex << 0xf) | screenStateIndex; + } + + /** Print aggregated tags generated via {@code #aggregateCurrentProcessState}. */ + public static void printAggregatedProcStateTagProto(ProtoOutputStream proto, long screenId, + long stateId, int state) { + // screen state is in lowest 0xf bits, process state is in next 0xf bits up + + try { + proto.write(stateId, STATE_PROTO_ENUMS[state >> 0xf]); + } catch (IndexOutOfBoundsException e) { + proto.write(stateId, ProcessStatsEnums.PROCESS_STATE_UNKNOWN); + } + + try { + proto.write(screenId, ADJ_SCREEN_PROTO_ENUMS[state & 0xf]); + } catch (IndexOutOfBoundsException e) { + proto.write(screenId, ProcessStatsEnums.SCREEN_STATE_UNKNOWN); + } } } diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java index a6bed5bdfedc..79ff5948f32b 100644 --- a/core/java/com/android/internal/app/procstats/ProcessState.java +++ b/core/java/com/android/internal/app/procstats/ProcessState.java @@ -16,22 +16,6 @@ package com.android.internal.app.procstats; -import android.os.Parcel; -import android.os.SystemClock; -import android.os.UserHandle; -import android.service.procstats.ProcessStatsProto; -import android.service.procstats.ProcessStatsStateProto; -import android.util.ArrayMap; -import android.util.DebugUtils; -import android.util.Log; -import android.util.LongSparseArray; -import android.util.Slog; -import android.util.SparseLongArray; -import android.util.TimeUtils; -import android.util.proto.ProtoOutputStream; -import android.util.proto.ProtoUtils; - - import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; @@ -60,6 +44,21 @@ import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE; import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING; import static com.android.internal.app.procstats.ProcessStats.STATE_TOP; +import android.os.Parcel; +import android.os.SystemClock; +import android.os.UserHandle; +import android.service.procstats.ProcessStatsProto; +import android.service.procstats.ProcessStatsStateProto; +import android.util.ArrayMap; +import android.util.DebugUtils; +import android.util.Log; +import android.util.LongSparseArray; +import android.util.Slog; +import android.util.SparseLongArray; +import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; +import android.util.proto.ProtoUtils; + import com.android.internal.app.procstats.ProcessStats.PackageState; import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder; import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection; @@ -1418,4 +1417,109 @@ public final class ProcessState { proto.end(token); } + + /** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */ + public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId, + String procName, int uid, long now) { + // Group proc stats by aggregated type (only screen state + process state) + SparseLongArray durationByState = new SparseLongArray(); + boolean didCurState = false; + for (int i = 0; i < mDurations.getKeyCount(); i++) { + final int key = mDurations.getKeyAt(i); + final int type = SparseMappingTable.getIdFromKey(key); + final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type); + + long time = mDurations.getValue(key); + if (mCurCombinedState == type) { + didCurState = true; + time += now - mStartTime; + } + int index = durationByState.indexOfKey(aggregatedType); + if (index >= 0) { + durationByState.put(aggregatedType, time + durationByState.valueAt(index)); + } else { + durationByState.put(aggregatedType, time); + } + } + if (!didCurState && mCurCombinedState != STATE_NOTHING) { + final int aggregatedType = DumpUtils.aggregateCurrentProcessState(mCurCombinedState); + int index = durationByState.indexOfKey(aggregatedType); + if (index >= 0) { + durationByState.put(aggregatedType, + (now - mStartTime) + durationByState.valueAt(index)); + } else { + durationByState.put(aggregatedType, now - mStartTime); + } + } + + // Now we have total durations, aggregate the RSS values + SparseLongArray meanRssByState = new SparseLongArray(); + SparseLongArray maxRssByState = new SparseLongArray(); + // compute weighted averages and max-of-max + for (int i = 0; i < mPssTable.getKeyCount(); i++) { + final int key = mPssTable.getKeyAt(i); + final int type = SparseMappingTable.getIdFromKey(key); + if (durationByState.indexOfKey(type) < 0) { + // state without duration should not have stats! + continue; + } + final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type); + + long[] rssMeanAndMax = mPssTable.getRssMeanAndMax(key); + + // compute mean * duration, then store sum of that in meanRssByState + long meanTimesDuration = rssMeanAndMax[0] * mDurations.getValue(key); + if (meanRssByState.indexOfKey(aggregatedType) >= 0) { + meanRssByState.put(aggregatedType, + meanTimesDuration + meanRssByState.get(aggregatedType)); + } else { + meanRssByState.put(aggregatedType, meanTimesDuration); + } + + // accumulate max-of-maxes in maxRssByState + if (maxRssByState.indexOfKey(aggregatedType) >= 0 + && maxRssByState.get(aggregatedType) < rssMeanAndMax[1]) { + maxRssByState.put(aggregatedType, rssMeanAndMax[1]); + } else if (maxRssByState.indexOfKey(aggregatedType) < 0) { + maxRssByState.put(aggregatedType, rssMeanAndMax[1]); + } + } + + // divide the means by the durations to get the weighted mean-of-means + for (int i = 0; i < durationByState.size(); i++) { + int aggregatedKey = durationByState.keyAt(i); + if (meanRssByState.indexOfKey(aggregatedKey) < 0) { + // these data structures should be consistent + continue; + } + meanRssByState.put(aggregatedKey, + meanRssByState.get(aggregatedKey) / durationByState.get(aggregatedKey)); + } + + // build the output + final long token = proto.start(fieldId); + proto.write(ProcessStatsProto.PROCESS, procName); + proto.write(ProcessStatsProto.UID, uid); + + for (int i = 0; i < durationByState.size(); i++) { + final long stateToken = proto.start(ProcessStatsProto.STATES); + + final int aggregatedKey = durationByState.keyAt(i); + + DumpUtils.printAggregatedProcStateTagProto(proto, + ProcessStatsStateProto.SCREEN_STATE, + ProcessStatsStateProto.PROCESS_STATE, + aggregatedKey); + proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.get(aggregatedKey)); + + ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.RSS, + 0, /* do not output a minimum value */ + meanRssByState.get(aggregatedKey), + maxRssByState.get(aggregatedKey)); + + proto.end(stateToken); + } + + proto.end(token); + } } diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index 009b1e0fa829..80f6272794d1 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -2178,29 +2178,7 @@ public final class ProcessStats implements Parcelable { * Writes to ProtoOutputStream. */ public void dumpDebug(ProtoOutputStream proto, long now, int section) { - proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime); - proto.write(ProcessStatsSectionProto.END_REALTIME_MS, - mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime); - proto.write(ProcessStatsSectionProto.START_UPTIME_MS, mTimePeriodStartUptime); - proto.write(ProcessStatsSectionProto.END_UPTIME_MS, mTimePeriodEndUptime); - proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime); - proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss); - boolean partial = true; - if ((mFlags & FLAG_SHUTDOWN) != 0) { - proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN); - partial = false; - } - if ((mFlags & FLAG_SYSPROPS) != 0) { - proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS); - partial = false; - } - if ((mFlags & FLAG_COMPLETE) != 0) { - proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE); - partial = false; - } - if (partial) { - proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL); - } + dumpProtoPreamble(proto); final int NPAGETYPES = mPageTypeLabels.size(); for (int i = 0; i < NPAGETYPES; i++) { @@ -2247,6 +2225,49 @@ public final class ProcessStats implements Parcelable { } } + /** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */ + public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto) { + dumpProtoPreamble(proto); + final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); + for (int ip = 0; ip < procMap.size(); ip++) { + final String procName = procMap.keyAt(ip); + final SparseArray<ProcessState> uids = procMap.valueAt(ip); + for (int iu = 0; iu < uids.size(); iu++) { + final int uid = uids.keyAt(iu); + final ProcessState procState = uids.valueAt(iu); + procState.dumpAggregatedProtoForStatsd(proto, + ProcessStatsSectionProto.PROCESS_STATS, + procName, uid, mTimePeriodEndRealtime); + } + } + } + + private void dumpProtoPreamble(ProtoOutputStream proto) { + proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime); + proto.write(ProcessStatsSectionProto.END_REALTIME_MS, + mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime); + proto.write(ProcessStatsSectionProto.START_UPTIME_MS, mTimePeriodStartUptime); + proto.write(ProcessStatsSectionProto.END_UPTIME_MS, mTimePeriodEndUptime); + proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime); + proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss); + boolean partial = true; + if ((mFlags & FLAG_SHUTDOWN) != 0) { + proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN); + partial = false; + } + if ((mFlags & FLAG_SYSPROPS) != 0) { + proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS); + partial = false; + } + if ((mFlags & FLAG_COMPLETE) != 0) { + proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE); + partial = false; + } + if (partial) { + proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL); + } + } + final public static class ProcessStateHolder { public final long appVersion; public ProcessState state; diff --git a/core/java/com/android/internal/app/procstats/PssTable.java b/core/java/com/android/internal/app/procstats/PssTable.java index fc93c3a0094e..a6bae6e05dbc 100644 --- a/core/java/com/android/internal/app/procstats/PssTable.java +++ b/core/java/com/android/internal/app/procstats/PssTable.java @@ -16,17 +16,17 @@ package com.android.internal.app.procstats; +import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; +import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; +import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; +import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT; -import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM; -import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; -import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; -import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM; -import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; +import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; import android.service.procstats.ProcessStatsStateProto; import android.util.proto.ProtoOutputStream; @@ -133,7 +133,6 @@ public class PssTable extends SparseMappingTable.Table { } if (stats[statsIndex + PSS_RSS_MINIMUM] > minRss) { - stats[statsIndex + PSS_RSS_MINIMUM] = minRss; } stats[statsIndex + PSS_RSS_AVERAGE] = (long)(((stats[statsIndex + PSS_RSS_AVERAGE] @@ -167,4 +166,10 @@ public class PssTable extends SparseMappingTable.Table { stats[statsIndex + PSS_RSS_AVERAGE], stats[statsIndex + PSS_RSS_MAXIMUM]); } + + long[] getRssMeanAndMax(int key) { + final long[] stats = getArrayForKey(key); + final int statsIndex = SparseMappingTable.getIndexFromKey(key); + return new long[]{stats[statsIndex + PSS_RSS_AVERAGE], stats[statsIndex + PSS_RSS_MAXIMUM]}; + } } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index fba237936f6e..8e99356a8a80 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3447,8 +3447,9 @@ TODO: move to input HAL once ready. --> <string name="config_doubleTouchGestureEnableFile"></string> - <!-- Package of the unbundled tv remote service which can connect to tv - remote provider --> + <!-- Comma-separated list of unbundled packages which can connect to the + tv remote provider. The tv remote service is an example of such a + service. --> <string name="config_tvRemoteServicePackage" translatable="false"></string> <!-- True if the device supports persisting security logs across reboots. diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java index eb39d58019d9..07aa654cae1e 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java @@ -38,13 +38,16 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +import static org.testng.Assert.assertFalse; import android.content.Intent; import android.content.pm.ResolveInfo; +import android.net.Uri; import android.os.UserHandle; import android.text.TextUtils; import android.view.View; import android.widget.RelativeLayout; +import android.widget.TextView; import androidx.test.InstrumentationRegistry; import androidx.test.espresso.Espresso; @@ -543,6 +546,51 @@ public class ResolverActivityTest { assertThat(activity.getWorkListAdapter().getCount(), is(4)); } + @Test + public void testWorkTab_headerIsVisibleInPersonalTab() { + // enable the work tab feature flag + ResolverActivity.ENABLE_TABBED_VIEW = true; + markWorkProfileUserAvailable(); + List<ResolvedComponentInfo> personalResolvedComponentInfos = + createResolvedComponentsForTestWithOtherProfile(1); + List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4); + setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); + Intent sendIntent = createOpenWebsiteIntent(); + + final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); + waitForIdle(); + TextView headerText = activity.findViewById(R.id.title); + String initialText = headerText.getText().toString(); + assertFalse(initialText.isEmpty(), "Header text is empty."); + assertThat(headerText.getVisibility(), is(View.VISIBLE)); + } + + @Test + public void testWorkTab_switchTabs_headerStaysSame() { + // enable the work tab feature flag + ResolverActivity.ENABLE_TABBED_VIEW = true; + markWorkProfileUserAvailable(); + List<ResolvedComponentInfo> personalResolvedComponentInfos = + createResolvedComponentsForTestWithOtherProfile(1); + List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4); + setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); + Intent sendIntent = createOpenWebsiteIntent(); + + final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); + waitForIdle(); + TextView headerText = activity.findViewById(R.id.title); + String initialText = headerText.getText().toString(); + onView(withText(R.string.resolver_work_tab)) + .perform(click()); + + waitForIdle(); + String currentText = headerText.getText().toString(); + assertThat(headerText.getVisibility(), is(View.VISIBLE)); + assertThat(String.format("Header text is not the same when switching tabs, personal profile" + + " header was %s but work profile header is %s", initialText, currentText), + TextUtils.equals(initialText, currentText)); + } + @Ignore // b/148156663 @Test public void testWorkTab_noPersonalApps_canStartWorkApps() @@ -761,6 +809,13 @@ public class ResolverActivityTest { return sendIntent; } + private Intent createOpenWebsiteIntent() { + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_VIEW); + sendIntent.setData(Uri.parse("https://google.com")); + return sendIntent; + } + private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) { List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults); for (int i = 0; i < numberOfResults; i++) { diff --git a/core/tests/overlaytests/host/TEST_MAPPING b/core/tests/overlaytests/host/TEST_MAPPING new file mode 100644 index 000000000000..e0c03e0f2aa4 --- /dev/null +++ b/core/tests/overlaytests/host/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name" : "OverlayHostTests" + } + ] +}
\ No newline at end of file diff --git a/media/OWNERS b/media/OWNERS index be605831a24b..a16373ef8c8d 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -1,7 +1,7 @@ andrewlewis@google.com chz@google.com -dwkang@google.com elaurent@google.com +essick@google.com etalvala@google.com gkasten@google.com hdmoon@google.com @@ -15,7 +15,7 @@ klhyun@google.com lajos@google.com marcone@google.com sungsoo@google.com -wjia@google.com +wonsik@google.com # For maintaining sync with AndroidX code per-file ExifInterface.java = jinpark@google.com, sungsoo@google.com diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index a31f177d66ab..362dfa0c88f4 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -132,6 +132,8 @@ static struct { jmethodID asReadOnlyBufferId; jmethodID positionId; jmethodID limitId; + jmethodID getPositionId; + jmethodID getLimitId; } gByteBufferInfo; static struct { @@ -2033,13 +2035,11 @@ static status_t ConvertKeyValueListsToAMessage( if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) { const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr); AString value; - if (tmp) { - value.setTo(tmp); - } - env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp); - if (value.empty()) { + if (!tmp) { return NO_MEMORY; } + value.setTo(tmp); + env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp); result->setString(key.c_str(), value); } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) { jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId); @@ -2051,8 +2051,8 @@ static status_t ConvertKeyValueListsToAMessage( jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId); result->setFloat(key.c_str(), value); } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) { - jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.positionId); - jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.limitId); + jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId); + jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId); sp<ABuffer> buffer{new ABuffer(limit - position)}; void *data = env->GetDirectBufferAddress(jvalue.get()); if (data != nullptr) { @@ -2773,6 +2773,14 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { clazz.get(), "limit", "(I)Ljava/nio/Buffer;"); CHECK(gByteBufferInfo.limitId != NULL); + gByteBufferInfo.getPositionId = env->GetMethodID( + clazz.get(), "position", "()I"); + CHECK(gByteBufferInfo.getPositionId != NULL); + + gByteBufferInfo.getLimitId = env->GetMethodID( + clazz.get(), "limit", "()I"); + CHECK(gByteBufferInfo.getLimitId != NULL); + clazz.reset(env->FindClass("java/util/ArrayList")); CHECK(clazz.get() != NULL); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index cd45fc908db4..d8111d04348b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -170,7 +169,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -251,7 +249,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index e163173daefb..f72ab25a8028 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -63,7 +63,6 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -145,7 +144,6 @@ public class CarStatusBarModule { NotificationInterruptStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -225,7 +223,6 @@ public class CarStatusBarModule { notificationInterruptionStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/SystemUI/res/drawable-nodpi/controls_btn_star.xml b/packages/SystemUI/res/drawable-nodpi/controls_btn_star.xml deleted file mode 100644 index cfe783892b1d..000000000000 --- a/packages/SystemUI/res/drawable-nodpi/controls_btn_star.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 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. - --> -<selector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp"> - <item android:state_checked="true" - android:drawable="@drawable/star_filled" - android:tint="@color/control_primary_text"/> - <item android:drawable="@drawable/star_outline" - android:tint="@color/control_primary_text"/> -</selector> diff --git a/packages/SystemUI/res/drawable-nodpi/star_filled.xml b/packages/SystemUI/res/drawable-nodpi/star_filled.xml deleted file mode 100644 index 62802d3cb838..000000000000 --- a/packages/SystemUI/res/drawable-nodpi/star_filled.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 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. - --> - -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M 11.99 0.027 L 8.628 8.382 L 0.027 9.15 L 6.559 15.111 L 4.597 23.97 L 11.99 19.27 L 19.383 23.97 L 17.421 15.111 L 23.953 9.15 L 15.352 8.382 Z" - android:fillColor="#FFFFFFFF"/> -</vector> diff --git a/packages/SystemUI/res/drawable-nodpi/star_outline.xml b/packages/SystemUI/res/drawable-nodpi/star_outline.xml deleted file mode 100644 index 13983c6fda8d..000000000000 --- a/packages/SystemUI/res/drawable-nodpi/star_outline.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 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. - --> - -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M 11.99 6.491 L 13.15 9.377 L 13.713 10.776 L 15.148 10.902 L 18.103 11.167 L 15.854 13.221 L 14.766 14.216 L 15.089 15.703 L 15.759 18.74 L 13.222 17.127 L 11.99 16.321 L 10.758 17.102 L 8.222 18.715 L 8.891 15.678 L 9.215 14.191 L 8.126 13.196 L 5.877 11.141 L 8.832 10.877 L 10.267 10.751 L 10.83 9.352 L 11.99 6.491 M 11.99 0.027 L 8.628 8.382 L 0.027 9.15 L 6.559 15.111 L 4.597 23.97 L 11.99 19.27 L 19.383 23.97 L 17.421 15.111 L 23.953 9.15 L 15.352 8.382 Z" - android:fillColor="#FFFFFFFF"/> -</vector> diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index 6a8621398191..fd75d91f0994 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -101,7 +101,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" - android:button="@drawable/controls_btn_star" android:background="@android:color/transparent" android:clickable="false" android:selectable="false" diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml new file mode 100644 index 000000000000..ccb4f7832a62 --- /dev/null +++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml @@ -0,0 +1,194 @@ +<!-- + ~ Copyright (C) 2020 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 + --> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/onboarding_half_shell_container" + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal|bottom" + android:paddingStart="4dp" + android:paddingEnd="4dp" + > + + <LinearLayout + android:id="@+id/half_shell" + android:layout_width="@dimen/qs_panel_width" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:paddingBottom="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:orientation="vertical" + android:gravity="bottom" + android:layout_gravity="center_horizontal|bottom" + android:background="@drawable/rounded_bg_full" + > + + <!-- We have a known number of rows that can be shown; just design them all here --> + <LinearLayout + android:id="@+id/show_at_top_tip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp" + android:orientation="horizontal" + > + <ImageView + android:id="@+id/bell_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center_vertical" + android:src="@drawable/ic_notifications_alert" + android:tint="?android:attr/colorControlNormal" /> + + <TextView + android:id="@+id/show_at_top_text" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:gravity="center_vertical|start" + android:textSize="15sp" + android:ellipsize="end" + android:maxLines="1" + android:text="@string/priority_onboarding_show_at_top_text" + style="@style/TextAppearance.NotificationInfo" + /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/show_avatar_tip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp" + android:orientation="horizontal" + > + <ImageView + android:id="@+id/avatar_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center_vertical" + android:src="@drawable/ic_person" + android:tint="?android:attr/colorControlNormal" /> + + <TextView + android:id="@+id/avatar_text" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:gravity="center_vertical|start" + android:textSize="15sp" + android:ellipsize="end" + android:maxLines="1" + android:text="@string/priority_onboarding_show_avatar_text" + style="@style/TextAppearance.NotificationInfo" + /> + + </LinearLayout> + + <!-- These rows show optionally --> + + <LinearLayout + android:id="@+id/floating_bubble_tip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp" + android:orientation="horizontal" + > + + <ImageView + android:id="@+id/bubble_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center_vertical" + android:src="@drawable/ic_create_bubble" + android:tint="?android:attr/colorControlNormal" /> + + <TextView + android:id="@+id/bubble_text" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:gravity="center_vertical|start" + android:textSize="15sp" + android:ellipsize="end" + android:maxLines="1" + android:text="@string/priority_onboarding_appear_as_bubble_text" + style="@style/TextAppearance.NotificationInfo" + /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/ignore_dnd_tip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp" + android:orientation="horizontal" + > + + <ImageView + android:id="@+id/dnd_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center_vertical" + android:src="@drawable/moon" + android:tint="?android:attr/colorControlNormal" /> + + <TextView + android:id="@+id/dnd_text" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:gravity="center_vertical|start" + android:textSize="15sp" + android:ellipsize="end" + android:maxLines="1" + android:text="@string/priority_onboarding_ignores_dnd_text" + style="@style/TextAppearance.NotificationInfo" + /> + + </LinearLayout> + + <!-- Bottom button container --> + <RelativeLayout + android:id="@+id/button_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp" + android:orientation="horizontal" + > + <TextView + android:id="@+id/done_button" + android:text="@string/priority_onboarding_done_button_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:gravity="end|center_vertical" + android:minWidth="@dimen/notification_importance_toggle_size" + android:minHeight="@dimen/notification_importance_toggle_size" + android:maxWidth="125dp" + style="@style/TextAppearance.NotificationInfo.Button"/> + + </RelativeLayout> + + </LinearLayout> +</FrameLayout> diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl index 716e1272f871..e4b6e0778664 100644 --- a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl +++ b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl @@ -3,74 +3,9 @@ precision mediump float; // The actual wallpaper texture. uniform sampler2D uTexture; -// The 85th percenile for the luminance histogram of the image (a value between 0 and 1). -// This value represents the point in histogram that includes 85% of the pixels of the image. -uniform float uPer85; - -// Reveal is the animation value that goes from 1 (the image is hidden) to 0 (the image is visible). -uniform float uReveal; - -// The opacity of locked screen (constant value). -uniform float uAod2Opacity; varying vec2 vTextureCoordinates; -/* - * Calculates the relative luminance of the pixel. - */ -vec3 luminosity(vec3 color) { - float lum = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; - return vec3(lum); -} - -vec4 transform(vec3 diffuse) { - // Getting the luminance for this pixel - vec3 lum = luminosity(diffuse); - - /* - * while the reveal > per85, it shows the luminance image (B&W image) - * then when moving passed that value, the image gets colored. - */ - float trans = smoothstep(0., uPer85, uReveal); - diffuse = mix(diffuse, lum, trans); - - // 'lower' value represents the capped 'reveal' value to the range [0, per85] - float selector = step(uPer85, uReveal); - float lower = mix(uReveal, uPer85, selector); - - /* - * Remaps image: - * - from reveal=1 to reveal=per85 => lower=per85, diffuse=luminance - * That means that remaps black and white image pixel - * from a possible values of [0,1] to [per85, 1] (if the pixel is darker than per85, - * it's gonna be black, if it's between per85 and 1, it's gonna be gray - * and if it's 1 it's gonna be white). - * - from reveal=per85 to reveal=0 => lower=reveal, 'diffuse' changes from luminance to color - * That means that remaps each image pixel color (rgb) - * from a possible values of [0,1] to [lower, 1] (if the pixel color is darker than 'lower', - * it's gonna be 0, if it's between 'lower' and 1, it's gonna be remap to a value - * between 0 and 1 and if it's 1 it's gonna be 1). - * - if reveal=0 => lower=0, diffuse=color image - * The image is shown as it is, colored. - */ - vec3 remaps = smoothstep(lower, 1., diffuse); - - // Interpolate between diffuse and remaps using reveal to avoid over saturation. - diffuse = mix(diffuse, remaps, uReveal); - - /* - * Fades in the pixel value: - * - if reveal=1 => fadeInOpacity=0 - * - from reveal=1 to reveal=per85 => 0<=fadeInOpacity<=1 - * - if reveal>per85 => fadeInOpacity=1 - */ - float fadeInOpacity = 1. - smoothstep(uPer85, 1., uReveal); - diffuse *= uAod2Opacity * fadeInOpacity; - - return vec4(diffuse.r, diffuse.g, diffuse.b, 1.); -} - void main() { // gets the pixel value of the wallpaper for this uv coordinates on screen. - vec4 fragColor = texture2D(uTexture, vTextureCoordinates); - gl_FragColor = transform(fragColor.rgb); + gl_FragColor = texture2D(uTexture, vTextureCoordinates); }
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 622e4ccef487..599ed1696ec9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1253,6 +1253,7 @@ <dimen name="control_base_item_margin">2dp</dimen> <dimen name="control_status_padding">3dp</dimen> <fraction name="controls_toggle_bg_intensity">5%</fraction> + <fraction name="controls_dimmed_alpha">40%</fraction> <!-- Home Controls activity view detail panel--> <dimen name="controls_activity_view_top_padding">25dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 49420e8620d1..cb20e7a15424 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2639,6 +2639,18 @@ <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] --> <string name="inattentive_sleep_warning_title">Standby</string> + <!-- Priority conversation onboarding screen --> + <!-- Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=50] --> + <string name="priority_onboarding_show_at_top_text">Show at top of conversation section</string> + <!-- Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=50] --> + <string name="priority_onboarding_show_avatar_text">Show profile picture on lock screen</string> + <!-- Text explaining that priority conversations will appear as a bubble [CHAR LIMIT=50] --> + <string name="priority_onboarding_appear_as_bubble_text">Appear as a floating bubble on top of apps</string> + <!-- Text explaining that priority conversations can interrupt DnD settings [CHAR LIMIT=50] --> + <string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string> + <!-- Title for the affirmative button [CHAR LIMIT=50] --> + <string name="priority_onboarding_done_button_title">Got it</string> + <!-- Window Magnification strings --> <!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] --> <string name="magnification_overlay_title">Magnification Overlay Window</string> diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index b6152dae33d6..0af026eb3509 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -75,7 +75,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; @@ -293,8 +292,6 @@ public class Dependency { @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler; @Inject Lazy<BubbleController> mBubbleController; @Inject Lazy<NotificationEntryManager> mNotificationEntryManager; - @Inject - Lazy<NotificationAlertingManager> mNotificationAlertingManager; @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager; @Inject Lazy<AutoHideController> mAutoHideController; @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener; @@ -493,7 +490,6 @@ public class Dependency { mRemoteInputQuickSettingsDisabler::get); mProviders.put(BubbleController.class, mBubbleController::get); mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get); - mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get); mProviders.put(ForegroundServiceNotificationListener.class, mForegroundServiceNotificationListener::get); mProviders.put(ClockManager.class, mClockManager::get); diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 5442299881c0..71ec33e16e0e 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -16,9 +16,6 @@ package com.android.systemui; -import android.app.ActivityManager; -import android.content.Context; -import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.os.HandlerThread; @@ -27,17 +24,12 @@ import android.os.Trace; import android.service.wallpaper.WallpaperService; import android.util.Log; import android.util.Size; -import android.view.DisplayInfo; import android.view.SurfaceHolder; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.glwallpaper.EglHelper; import com.android.systemui.glwallpaper.GLWallpaperRenderer; import com.android.systemui.glwallpaper.ImageWallpaperRenderer; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; -import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.phone.DozeParameters; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -53,16 +45,12 @@ public class ImageWallpaper extends WallpaperService { // We delayed destroy render context that subsequent render requests have chance to cancel it. // This is to avoid destroying then recreating render context in a very short time. private static final int DELAY_FINISH_RENDERING = 1000; - private static final int INTERVAL_WAIT_FOR_RENDERING = 100; - private static final int PATIENCE_WAIT_FOR_RENDERING = 10; - private static final boolean DEBUG = true; - private final DozeParameters mDozeParameters; + private static final boolean DEBUG = false; private HandlerThread mWorker; @Inject - public ImageWallpaper(DozeParameters dozeParameters) { + public ImageWallpaper() { super(); - mDozeParameters = dozeParameters; } @Override @@ -74,7 +62,7 @@ public class ImageWallpaper extends WallpaperService { @Override public Engine onCreateEngine() { - return new GLEngine(this, mDozeParameters); + return new GLEngine(); } @Override @@ -84,7 +72,7 @@ public class ImageWallpaper extends WallpaperService { mWorker = null; } - class GLEngine extends Engine implements GLWallpaperRenderer.SurfaceProxy, StateListener { + class GLEngine extends Engine { // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin) // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail. @VisibleForTesting @@ -94,40 +82,15 @@ public class ImageWallpaper extends WallpaperService { private GLWallpaperRenderer mRenderer; private EglHelper mEglHelper; - private StatusBarStateController mController; private final Runnable mFinishRenderingTask = this::finishRendering; - private boolean mShouldStopTransition; - private final DisplayInfo mDisplayInfo = new DisplayInfo(); - private final Object mMonitor = new Object(); - @VisibleForTesting - boolean mIsHighEndGfx; - private boolean mDisplayNeedsBlanking; - private boolean mNeedTransition; private boolean mNeedRedraw; - // This variable can only be accessed in synchronized block. - private boolean mWaitingForRendering; - GLEngine(Context context, DozeParameters dozeParameters) { - init(dozeParameters); + GLEngine() { } @VisibleForTesting - GLEngine(DozeParameters dozeParameters, Handler handler) { + GLEngine(Handler handler) { super(SystemClock::elapsedRealtime, handler); - init(dozeParameters); - } - - private void init(DozeParameters dozeParameters) { - mIsHighEndGfx = ActivityManager.isHighEndGfx(); - mDisplayNeedsBlanking = dozeParameters.getDisplayNeedsBlanking(); - mNeedTransition = false; - - // We will preserve EGL context when we are in lock screen or aod - // to avoid janking in following transition, we need to release when back to home. - mController = Dependency.get(StatusBarStateController.class); - if (mController != null) { - mController.addCallback(this /* StateListener */); - } } @Override @@ -135,9 +98,8 @@ public class ImageWallpaper extends WallpaperService { mEglHelper = getEglHelperInstance(); // Deferred init renderer because we need to get wallpaper by display context. mRenderer = getRendererInstance(); - getDisplayContext().getDisplay().getDisplayInfo(mDisplayInfo); setFixedSizeAllowed(true); - setOffsetNotificationsEnabled(mNeedTransition); + setOffsetNotificationsEnabled(false); updateSurfaceSize(); } @@ -146,7 +108,7 @@ public class ImageWallpaper extends WallpaperService { } ImageWallpaperRenderer getRendererInstance() { - return new ImageWallpaperRenderer(getDisplayContext(), this /* SurfaceProxy */); + return new ImageWallpaperRenderer(getDisplayContext()); } private void updateSurfaceSize() { @@ -157,79 +119,13 @@ public class ImageWallpaper extends WallpaperService { holder.setFixedSize(width, height); } - /** - * Check if necessary to stop transition with current wallpaper on this device. <br/> - * This should only be invoked after {@link #onSurfaceCreated(SurfaceHolder)}} - * is invoked since it needs display context and surface frame size. - * @return true if need to stop transition. - */ - @VisibleForTesting - boolean checkIfShouldStopTransition() { - int orientation = getDisplayContext().getResources().getConfiguration().orientation; - Rect frame = getSurfaceHolder().getSurfaceFrame(); - Rect display = new Rect(); - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - display.set(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); - } else { - display.set(0, 0, mDisplayInfo.logicalHeight, mDisplayInfo.logicalWidth); - } - return mNeedTransition - && (frame.width() < display.width() || frame.height() < display.height()); - } - - @Override - public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, - float yOffsetStep, int xPixelOffset, int yPixelOffset) { - if (mWorker == null) return; - mWorker.getThreadHandler().post(() -> mRenderer.updateOffsets(xOffset, yOffset)); - } - - @Override - public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { - if (mWorker == null || !mNeedTransition) return; - final long duration = mShouldStopTransition ? 0 : animationDuration; - if (DEBUG) { - Log.d(TAG, "onAmbientModeChanged: inAmbient=" + inAmbientMode - + ", duration=" + duration - + ", mShouldStopTransition=" + mShouldStopTransition); - } - mWorker.getThreadHandler().post( - () -> mRenderer.updateAmbientMode(inAmbientMode, duration)); - if (inAmbientMode && animationDuration == 0) { - // This means that we are transiting from home to aod, to avoid - // race condition between window visibility and transition, - // we don't return until the transition is finished. See b/136643341. - waitForBackgroundRendering(); - } - } - @Override public boolean shouldZoomOutWallpaper() { return true; } - private void waitForBackgroundRendering() { - synchronized (mMonitor) { - try { - mWaitingForRendering = true; - for (int patience = 1; mWaitingForRendering; patience++) { - mMonitor.wait(INTERVAL_WAIT_FOR_RENDERING); - mWaitingForRendering &= patience < PATIENCE_WAIT_FOR_RENDERING; - } - } catch (InterruptedException ex) { - } finally { - mWaitingForRendering = false; - } - } - } - @Override public void onDestroy() { - if (mController != null) { - mController.removeCallback(this /* StateListener */); - } - mController = null; - mWorker.getThreadHandler().post(() -> { mRenderer.finish(); mRenderer = null; @@ -240,7 +136,6 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceCreated(SurfaceHolder holder) { - mShouldStopTransition = checkIfShouldStopTransition(); if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { mEglHelper.init(holder, needSupportWideColorGamut()); @@ -251,32 +146,13 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mWorker == null) return; - mWorker.getThreadHandler().post(() -> { - mRenderer.onSurfaceChanged(width, height); - mNeedRedraw = true; - }); + mWorker.getThreadHandler().post(() -> mRenderer.onSurfaceChanged(width, height)); } @Override public void onSurfaceRedrawNeeded(SurfaceHolder holder) { if (mWorker == null) return; - if (DEBUG) { - Log.d(TAG, "onSurfaceRedrawNeeded: mNeedRedraw=" + mNeedRedraw); - } - - mWorker.getThreadHandler().post(() -> { - if (mNeedRedraw) { - drawFrame(); - mNeedRedraw = false; - } - }); - } - - @Override - public void onVisibilityChanged(boolean visible) { - if (DEBUG) { - Log.d(TAG, "wallpaper visibility changes: " + visible); - } + mWorker.getThreadHandler().post(this::drawFrame); } private void drawFrame() { @@ -285,15 +161,6 @@ public class ImageWallpaper extends WallpaperService { postRender(); } - @Override - public void onStatePostChange() { - // When back to home, we try to release EGL, which is preserved in lock screen or aod. - if (mWorker != null && mController.getState() == StatusBarState.SHADE) { - mWorker.getThreadHandler().post(this::scheduleFinishRendering); - } - } - - @Override public void preRender() { // This method should only be invoked from worker thread. Trace.beginSection("ImageWallpaper#preRender"); @@ -330,7 +197,6 @@ public class ImageWallpaper extends WallpaperService { } } - @Override public void requestRender() { // This method should only be invoked from worker thread. Trace.beginSection("ImageWallpaper#requestRender"); @@ -355,27 +221,13 @@ public class ImageWallpaper extends WallpaperService { } } - @Override public void postRender() { // This method should only be invoked from worker thread. Trace.beginSection("ImageWallpaper#postRender"); - notifyWaitingThread(); scheduleFinishRendering(); Trace.endSection(); } - private void notifyWaitingThread() { - synchronized (mMonitor) { - if (mWaitingForRendering) { - try { - mWaitingForRendering = false; - mMonitor.notify(); - } catch (IllegalMonitorStateException ex) { - } - } - } - } - private void cancelFinishRenderingTask() { if (mWorker == null) return; mWorker.getThreadHandler().removeCallbacks(mFinishRenderingTask); @@ -391,18 +243,11 @@ public class ImageWallpaper extends WallpaperService { Trace.beginSection("ImageWallpaper#finishRendering"); if (mEglHelper != null) { mEglHelper.destroyEglSurface(); - if (!needPreserveEglContext()) { - mEglHelper.destroyEglContext(); - } + mEglHelper.destroyEglContext(); } Trace.endSection(); } - private boolean needPreserveEglContext() { - return mNeedTransition && mController != null - && mController.getState() == StatusBarState.KEYGUARD; - } - private boolean needSupportWideColorGamut() { return mRenderer.isWcgContent(); } @@ -411,16 +256,6 @@ public class ImageWallpaper extends WallpaperService { protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { super.dump(prefix, fd, out, args); out.print(prefix); out.print("Engine="); out.println(this); - out.print(prefix); out.print("isHighEndGfx="); out.println(mIsHighEndGfx); - out.print(prefix); out.print("displayNeedsBlanking="); - out.println(mDisplayNeedsBlanking); - out.print(prefix); out.print("displayInfo="); out.print(mDisplayInfo); - out.print(prefix); out.print("mNeedTransition="); out.println(mNeedTransition); - out.print(prefix); out.print("mShouldStopTransition="); - out.println(mShouldStopTransition); - out.print(prefix); out.print("StatusBarState="); - out.println(mController != null ? mController.getState() : "null"); - out.print(prefix); out.print("valid surface="); out.println(getSurfaceHolder() != null && getSurfaceHolder().getSurface() != null ? getSurfaceHolder().getSurface().isValid() diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 6aa2326c388a..87990cd3bffa 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -21,11 +21,25 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import com.android.systemui.settings.CurrentUserContextTracker; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Map; import java.util.Set; +/** + * A helper class to store simple preferences for SystemUI. Its main use case is things such as + * feature education, e.g. "has the user seen this tooltip". + * + * As of this writing, feature education settings are *intentionally exempted* from backup and + * restore because there is not a great way to know which subset of features the user _should_ see + * again if, for instance, they are coming from multiple OSes back or switching OEMs. + * + * NOTE: Clients of this class should take care to pass in the correct user context when querying + * settings, otherwise you will always read/write for user 0 which is almost never what you want. + * See {@link CurrentUserContextTracker} for a simple way to get the current context + */ public final class Prefs { private Prefs() {} // no instantation @@ -109,6 +123,8 @@ public final class Prefs { String HAS_SEEN_BUBBLES_EDUCATION = "HasSeenBubblesOnboarding"; String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding"; String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount"; + /** Tracks whether the user has seen the onboarding screen for priority conversations */ + String HAS_SEEN_PRIORITY_ONBOARDING = "HasSeenPriorityOnboarding"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index 74b94e76dfc1..319a6e09d4d1 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -25,7 +25,6 @@ import android.os.Looper import android.os.Message import android.os.UserHandle import android.text.TextUtils -import android.util.Log import android.util.SparseArray import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Dumpable @@ -34,6 +33,7 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import java.io.FileDescriptor import java.io.PrintWriter +import java.lang.IllegalStateException import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton @@ -189,8 +189,8 @@ open class BroadcastDispatcher @Inject constructor ( data.user.identifier } if (userId < UserHandle.USER_ALL) { - if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId") - return + throw IllegalStateException( + "Attempting to register receiver for invalid user {$userId}") } val uBR = receiversByUser.get(userId, createUBRForUser(userId)) receiversByUser.put(userId, uBR) diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 0534efc0949d..0aabdff96e1e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -956,6 +956,8 @@ public class BubbleStackView extends FrameLayout { mVerticalPosPercentBeforeRotation = (mStackAnimationController.getStackPosition().y - allowablePos.top) / (allowablePos.bottom - allowablePos.top); + mVerticalPosPercentBeforeRotation = + Math.max(0f, Math.min(1f, mVerticalPosPercentBeforeRotation)); addOnLayoutChangeListener(mOrientationChangedListener); hideFlyoutImmediate(); } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index 7cab847d52f7..79a5b0a1ce52 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -23,6 +23,7 @@ import android.service.controls.actions.ControlAction import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.UserAwareController import com.android.systemui.controls.management.ControlsFavoritingActivity +import com.android.systemui.controls.ui.ControlWithState import com.android.systemui.controls.ui.ControlsUiController import java.util.function.Consumer @@ -111,6 +112,13 @@ interface ControlsController : UserAwareController { @ControlAction.ResponseResult response: Int ) + /** + * When a control should be highlighted, dimming down what's around it. + * + * @param cws focused control, or {@code null} if nothing should be highlighted. + */ + fun onFocusChanged(cws: ControlWithState?) + // FAVORITE MANAGEMENT /** diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index 6d34009169d5..5626a5de2e3c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -41,6 +41,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.management.ControlsListingController +import com.android.systemui.controls.ui.ControlWithState import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dump.DumpManager @@ -504,6 +505,10 @@ class ControlsControllerImpl @Inject constructor ( } } + override fun onFocusChanged(cws: ControlWithState?) { + uiController.onFocusChanged(cws) + } + override fun refreshStatus(componentName: ComponentName, control: Control) { if (!confirmAvailability()) { Log.d(TAG, "Controls not available") diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt index 2c1a91dca225..b3c6cab2adff 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -25,6 +25,7 @@ import android.service.controls.actions.CommandAction import android.util.Log import android.view.HapticFeedbackConstants import com.android.systemui.R +import com.android.systemui.controls.controller.ControlsController object ControlActionCoordinator { const val MIN_LEVEL = 0 @@ -76,4 +77,8 @@ object ControlActionCoordinator { it.show() } } + + fun setFocusedElement(cvh: ControlViewHolder?, controlsController: ControlsController) { + controlsController.onFocusChanged(cvh?.cws) + } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index 93e1bd444938..61a323d0b9a8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -31,6 +31,7 @@ import android.service.controls.templates.StatelessTemplate import android.service.controls.templates.TemperatureControlTemplate import android.service.controls.templates.ToggleRangeTemplate import android.service.controls.templates.ToggleTemplate +import android.util.MathUtils import android.view.View import android.view.ViewGroup import android.widget.ImageView @@ -68,6 +69,8 @@ class ControlViewHolder( private val toggleBackgroundIntensity: Float = layout.context.resources .getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1) + private val dimmedAlpha: Float = layout.context.resources + .getFraction(R.fraction.controls_dimmed_alpha, 1, 1) private var stateAnimator: ValueAnimator? = null private val baseLayer: GradientDrawable val icon: ImageView = layout.requireViewById(R.id.icon) @@ -82,6 +85,11 @@ class ControlViewHolder( var lastAction: ControlAction? = null val deviceType: Int get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType + var dimmed: Boolean = false + set(value) { + field = value + bindData(cws) + } init { val ld = layout.getBackground() as LayerDrawable @@ -177,7 +185,8 @@ class ControlViewHolder( val fg = context.resources.getColorStateList(ri.foreground, context.theme) val bg = context.resources.getColor(R.color.control_default_background, context.theme) - val (clip, newAlpha) = if (enabled) { + val dimAlpha = if (dimmed) dimmedAlpha else 1f + var (clip, newAlpha) = if (enabled) { listOf(ri.enabledBackground, ALPHA_ENABLED) } else { listOf(R.color.control_default_background, ALPHA_DISABLED) @@ -202,12 +211,14 @@ class ControlViewHolder( if (animated) { val oldColor = color?.defaultColor ?: newClipColor val oldBaseColor = baseLayer.color?.defaultColor ?: newBaseColor + val oldAlpha = layout.alpha stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply { addUpdateListener { alpha = it.animatedValue as Int setColor(ColorUtils.blendARGB(oldColor, newClipColor, it.animatedFraction)) baseLayer.setColor(ColorUtils.blendARGB(oldBaseColor, newBaseColor, it.animatedFraction)) + layout.alpha = MathUtils.lerp(oldAlpha, dimAlpha, it.animatedFraction) } addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { @@ -222,6 +233,7 @@ class ControlViewHolder( alpha = newAlpha setColor(newClipColor) baseLayer.setColor(newBaseColor) + layout.alpha = dimAlpha } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 0f105376847f..61a1a986c091 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -36,4 +36,5 @@ interface ControlsUiController { controlId: String, @ControlAction.ResponseResult response: Int ) + fun onFocusChanged(controlWithState: ControlWithState?) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index fab6fc7357dd..2adfb1bd6d4f 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -209,6 +209,20 @@ class ControlsUiControllerImpl @Inject constructor ( } } + override fun onFocusChanged(focusedControl: ControlWithState?) { + controlViewsById.forEach { key: ControlKey, viewHolder: ControlViewHolder -> + val state = controlsById.get(key) ?: return@forEach + val shouldBeDimmed = focusedControl != null && state != focusedControl + if (viewHolder.dimmed == shouldBeDimmed) { + return@forEach + } + + uiExecutor.execute { + viewHolder.dimmed = shouldBeDimmed + } + } + } + private fun startFavoritingActivity(context: Context, si: StructureInfo) { startTargetedActivity(context, si, ControlsFavoritingActivity::class.java) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt index d8b26e2e68d8..dafd8b25ec2e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -175,6 +175,7 @@ class ToggleRangeBehavior : Behavior { fun beginUpdateRange() { status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) + ControlActionCoordinator.setFocusedElement(cvh, cvh.controlsController) } fun updateRange(level: Int, checked: Boolean, isDragging: Boolean) { @@ -243,6 +244,7 @@ class ToggleRangeBehavior : Behavior { status.setText("$currentStatusText $currentRangeValue") cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(levelToRangeValue(clipLayer.getLevel())))) + ControlActionCoordinator.setFocusedElement(null, cvh.controlsController) } fun findNearestStep(value: Float): Float { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index 8c572fe8f842..88f96a8b19fe 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -24,6 +24,7 @@ import android.content.Context; import androidx.annotation.Nullable; import com.android.keyguard.KeyguardViewController; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.plugins.qs.QSFactory; @@ -33,6 +34,7 @@ import com.android.systemui.power.EnhancedEstimatesImpl; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsImplementation; +import com.android.systemui.settings.CurrentUserContextTracker; import com.android.systemui.stackdivider.DividerModule; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -136,4 +138,15 @@ public abstract class SystemUIDefaultModule { @Binds abstract KeyguardViewController bindKeyguardViewController( StatusBarKeyguardViewManager statusBarKeyguardViewManager); + + @Singleton + @Provides + static CurrentUserContextTracker provideCurrentUserContextTracker( + Context context, + BroadcastDispatcher broadcastDispatcher) { + CurrentUserContextTracker tracker = + new CurrentUserContextTracker(context, broadcastDispatcher); + tracker.initialize(); + return tracker; + } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 2c080b8efc63..9bb253b3d890 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -395,6 +395,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, if (preferredComponent == null) { Log.i(TAG, "Controls seeding: No preferred component has been set, will not seed"); mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply(); + return; } mControlsController.seedFavoritesForComponent( @@ -2316,4 +2317,4 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, && mControlsUiController.getAvailable() && !mControlsServiceInfos.isEmpty(); } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java index 88ab9ef4b014..61524900b89b 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java @@ -49,20 +49,6 @@ public interface GLWallpaperRenderer { void onDrawFrame(); /** - * Notify ambient mode is changed. - * @param inAmbientMode true if in ambient mode. - * @param duration duration of transition. - */ - void updateAmbientMode(boolean inAmbientMode, long duration); - - /** - * Notify the wallpaper offsets changed. - * @param xOffset offset along x axis. - * @param yOffset offset along y axis. - */ - void updateOffsets(float xOffset, float yOffset); - - /** * Ask renderer to report the surface size it needs. */ Size reportSurfaceSize(); @@ -81,24 +67,4 @@ public interface GLWallpaperRenderer { */ void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args); - /** - * A proxy which owns surface holder. - */ - interface SurfaceProxy { - - /** - * Ask proxy to start rendering frame to surface. - */ - void requestRender(); - - /** - * Ask proxy to prepare render context. - */ - void preRender(); - - /** - * Ask proxy to destroy render context. - */ - void postRender(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java index 626d0cfed997..fa45ea1acb95 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java @@ -33,7 +33,6 @@ import static android.opengl.GLES20.glUniform1i; import static android.opengl.GLES20.glVertexAttribPointer; import android.graphics.Bitmap; -import android.graphics.Rect; import android.opengl.GLUtils; import android.util.Log; @@ -50,14 +49,9 @@ import java.nio.FloatBuffer; class ImageGLWallpaper { private static final String TAG = ImageGLWallpaper.class.getSimpleName(); - static final String A_POSITION = "aPosition"; - static final String A_TEXTURE_COORDINATES = "aTextureCoordinates"; - static final String U_PER85 = "uPer85"; - static final String U_REVEAL = "uReveal"; - static final String U_AOD2OPACITY = "uAod2Opacity"; - static final String U_TEXTURE = "uTexture"; - - private static final int HANDLE_UNDEFINED = -1; + private static final String A_POSITION = "aPosition"; + private static final String A_TEXTURE_COORDINATES = "aTextureCoordinates"; + private static final String U_TEXTURE = "uTexture"; private static final int POSITION_COMPONENT_COUNT = 2; private static final int TEXTURE_COMPONENT_COUNT = 2; private static final int BYTES_PER_FLOAT = 4; @@ -88,14 +82,9 @@ class ImageGLWallpaper { private int mAttrPosition; private int mAttrTextureCoordinates; - private int mUniAod2Opacity; - private int mUniPer85; - private int mUniReveal; private int mUniTexture; private int mTextureId; - private float[] mCurrentTexCoordinate; - ImageGLWallpaper(ImageGLProgram program) { mProgram = program; @@ -135,31 +124,9 @@ class ImageGLWallpaper { } private void setupUniforms() { - mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY); - mUniPer85 = mProgram.getUniformHandle(U_PER85); - mUniReveal = mProgram.getUniformHandle(U_REVEAL); mUniTexture = mProgram.getUniformHandle(U_TEXTURE); } - int getHandle(String name) { - switch (name) { - case A_POSITION: - return mAttrPosition; - case A_TEXTURE_COORDINATES: - return mAttrTextureCoordinates; - case U_AOD2OPACITY: - return mUniAod2Opacity; - case U_PER85: - return mUniPer85; - case U_REVEAL: - return mUniReveal; - case U_TEXTURE: - return mUniTexture; - default: - return HANDLE_UNDEFINED; - } - } - void draw() { glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2); } @@ -201,87 +168,6 @@ class ImageGLWallpaper { } /** - * This method adjust s(x-axis), t(y-axis) texture coordinates to get current display area - * of texture and will be used during transition. - * The adjustment happens if either the width or height of the surface is larger than - * corresponding size of the display area. - * If both width and height are larger than corresponding size of the display area, - * the adjustment will happen at both s, t side. - * - * @param surface The size of the surface. - * @param scissor The display area. - * @param xOffset The offset amount along s axis. - * @param yOffset The offset amount along t axis. - */ - void adjustTextureCoordinates(Rect surface, Rect scissor, float xOffset, float yOffset) { - mCurrentTexCoordinate = TEXTURES.clone(); - - if (surface == null || scissor == null) { - mTextureBuffer.put(mCurrentTexCoordinate); - mTextureBuffer.position(0); - return; - } - - int surfaceWidth = surface.width(); - int surfaceHeight = surface.height(); - int scissorWidth = scissor.width(); - int scissorHeight = scissor.height(); - - if (surfaceWidth > scissorWidth) { - // Calculate the new s pos in pixels. - float pixelS = (float) Math.round((surfaceWidth - scissorWidth) * xOffset); - // Calculate the s pos in texture coordinate. - float coordinateS = pixelS / surfaceWidth; - // Calculate the percentage occupied by the scissor width in surface width. - float surfacePercentageW = (float) scissorWidth / surfaceWidth; - // Need also consider the case if surface height is smaller than scissor height. - if (surfaceHeight < scissorHeight) { - // We will narrow the surface percentage to keep aspect ratio. - surfacePercentageW *= (float) surfaceHeight / scissorHeight; - } - // Determine the final s pos, also limit the legal s pos to prevent from out of range. - float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS; - // Traverse the s pos in texture coordinates array and adjust the s pos accordingly. - for (int i = 0; i < mCurrentTexCoordinate.length; i += 2) { - // indices 2, 4 and 6 are the end of s coordinates. - if (i == 2 || i == 4 || i == 6) { - mCurrentTexCoordinate[i] = Math.min(1f, s + surfacePercentageW); - } else { - mCurrentTexCoordinate[i] = s; - } - } - } - - if (surfaceHeight > scissorHeight) { - // Calculate the new t pos in pixels. - float pixelT = (float) Math.round((surfaceHeight - scissorHeight) * yOffset); - // Calculate the t pos in texture coordinate. - float coordinateT = pixelT / surfaceHeight; - // Calculate the percentage occupied by the scissor height in surface height. - float surfacePercentageH = (float) scissorHeight / surfaceHeight; - // Need also consider the case if surface width is smaller than scissor width. - if (surfaceWidth < scissorWidth) { - // We will narrow the surface percentage to keep aspect ratio. - surfacePercentageH *= (float) surfaceWidth / scissorWidth; - } - // Determine the final t pos, also limit the legal t pos to prevent from out of range. - float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT; - // Traverse the t pos in texture coordinates array and adjust the t pos accordingly. - for (int i = 1; i < mCurrentTexCoordinate.length; i += 2) { - // indices 1, 3 and 11 are the end of t coordinates. - if (i == 1 || i == 3 || i == 11) { - mCurrentTexCoordinate[i] = Math.min(1f, t + surfacePercentageH); - } else { - mCurrentTexCoordinate[i] = t; - } - } - } - - mTextureBuffer.put(mCurrentTexCoordinate); - mTextureBuffer.position(0); - } - - /** * Called to dump current state. * @param prefix prefix. * @param fd fd. @@ -289,17 +175,5 @@ class ImageGLWallpaper { * @param args args. */ public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { - StringBuilder sb = new StringBuilder(); - sb.append('{'); - if (mCurrentTexCoordinate != null) { - for (int i = 0; i < mCurrentTexCoordinate.length; i++) { - sb.append(mCurrentTexCoordinate[i]).append(','); - if (i == mCurrentTexCoordinate.length - 1) { - sb.deleteCharAt(sb.length() - 1); - } - } - } - sb.append('}'); - out.print(prefix); out.print("mTexCoordinates="); out.println(sb.toString()); } } diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java deleted file mode 100644 index 703d5910500a..000000000000 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2019 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.systemui.glwallpaper; - -import static com.android.systemui.glwallpaper.ImageWallpaperRenderer.WallpaperTexture; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Handler.Callback; -import android.os.Message; -import android.util.Log; - -/** - * A helper class that computes threshold from a bitmap. - * Threshold will be computed each time the user picks a new image wallpaper. - */ -class ImageProcessHelper { - private static final String TAG = ImageProcessHelper.class.getSimpleName(); - private static final float DEFAULT_THRESHOLD = 0.8f; - private static final float DEFAULT_OTSU_THRESHOLD = 0f; - private static final float MAX_THRESHOLD = 0.89f; - private static final int MSG_UPDATE_THRESHOLD = 1; - - /** - * This color matrix will be applied to each pixel to get luminance from rgb by below formula: - * Luminance = .2126f * r + .7152f * g + .0722f * b. - */ - private static final float[] LUMINOSITY_MATRIX = new float[] { - .2126f, .0000f, .0000f, .0000f, .0000f, - .0000f, .7152f, .0000f, .0000f, .0000f, - .0000f, .0000f, .0722f, .0000f, .0000f, - .0000f, .0000f, .0000f, 1.000f, .0000f - }; - - private final Handler mHandler = new Handler(new Callback() { - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_THRESHOLD: - mThreshold = (float) msg.obj; - return true; - default: - return false; - } - } - }); - - private float mThreshold = DEFAULT_THRESHOLD; - - void start(WallpaperTexture texture) { - new ThresholdComputeTask(mHandler).execute(texture); - } - - float getThreshold() { - return Math.min(mThreshold, MAX_THRESHOLD); - } - - private static class ThresholdComputeTask extends AsyncTask<WallpaperTexture, Void, Float> { - private Handler mUpdateHandler; - - ThresholdComputeTask(Handler handler) { - super(handler); - mUpdateHandler = handler; - } - - @Override - protected Float doInBackground(WallpaperTexture... textures) { - WallpaperTexture texture = textures[0]; - final float[] threshold = new float[] {DEFAULT_THRESHOLD}; - if (texture == null) { - Log.e(TAG, "ThresholdComputeTask: WallpaperTexture not initialized"); - return threshold[0]; - } - - texture.use(bitmap -> { - if (bitmap != null) { - threshold[0] = new Threshold().compute(bitmap); - } else { - Log.e(TAG, "ThresholdComputeTask: Can't get bitmap"); - } - }); - return threshold[0]; - } - - @Override - protected void onPostExecute(Float result) { - Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_THRESHOLD, result); - mUpdateHandler.sendMessage(msg); - } - } - - private static class Threshold { - public float compute(Bitmap bitmap) { - Bitmap grayscale = toGrayscale(bitmap); - int[] histogram = getHistogram(grayscale); - boolean isSolidColor = isSolidColor(grayscale, histogram); - - // We will see gray wallpaper during the transition if solid color wallpaper is set, - // please refer to b/130360362#comment16. - // As a result, we use Percentile85 rather than Otsus if a solid color wallpaper is set. - ThresholdAlgorithm algorithm = isSolidColor ? new Percentile85() : new Otsus(); - return algorithm.compute(grayscale, histogram); - } - - private Bitmap toGrayscale(Bitmap bitmap) { - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - - Bitmap grayscale = Bitmap.createBitmap(width, height, bitmap.getConfig(), - false /* hasAlpha */, bitmap.getColorSpace()); - Canvas canvas = new Canvas(grayscale); - ColorMatrix cm = new ColorMatrix(LUMINOSITY_MATRIX); - Paint paint = new Paint(); - paint.setColorFilter(new ColorMatrixColorFilter(cm)); - canvas.drawBitmap(bitmap, new Matrix(), paint); - - return grayscale; - } - - private int[] getHistogram(Bitmap grayscale) { - int width = grayscale.getWidth(); - int height = grayscale.getHeight(); - - // TODO: Fine tune the performance here, tracking on b/123615079. - int[] histogram = new int[256]; - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - int pixel = grayscale.getPixel(col, row); - int y = Color.red(pixel) + Color.green(pixel) + Color.blue(pixel); - histogram[y]++; - } - } - - return histogram; - } - - private boolean isSolidColor(Bitmap bitmap, int[] histogram) { - boolean solidColor = false; - int pixels = bitmap.getWidth() * bitmap.getHeight(); - - // In solid color case, only one element of histogram has value, - // which is pixel counts and the value of other elements should be 0. - for (int value : histogram) { - if (value != 0 && value != pixels) { - break; - } - if (value == pixels) { - solidColor = true; - break; - } - } - return solidColor; - } - } - - private static class Percentile85 implements ThresholdAlgorithm { - @Override - public float compute(Bitmap bitmap, int[] histogram) { - float per85 = DEFAULT_THRESHOLD; - int pixelCount = bitmap.getWidth() * bitmap.getHeight(); - float[] acc = new float[256]; - for (int i = 0; i < acc.length; i++) { - acc[i] = (float) histogram[i] / pixelCount; - float prev = i == 0 ? 0f : acc[i - 1]; - float next = acc[i]; - float idx = (float) (i + 1) / 255; - float sum = prev + next; - if (prev < 0.85f && sum >= 0.85f) { - per85 = idx; - } - if (i > 0) { - acc[i] += acc[i - 1]; - } - } - return per85; - } - } - - private static class Otsus implements ThresholdAlgorithm { - @Override - public float compute(Bitmap bitmap, int[] histogram) { - float threshold = DEFAULT_OTSU_THRESHOLD; - float maxVariance = 0; - float pixelCount = bitmap.getWidth() * bitmap.getHeight(); - float[] w = new float[2]; - float[] m = new float[2]; - float[] u = new float[2]; - - for (int i = 0; i < histogram.length; i++) { - m[1] += i * histogram[i]; - } - - w[1] = pixelCount; - for (int tonalValue = 0; tonalValue < histogram.length; tonalValue++) { - float dU; - float variance; - float numPixels = histogram[tonalValue]; - float tmp = numPixels * tonalValue; - w[0] += numPixels; - w[1] -= numPixels; - - if (w[0] == 0 || w[1] == 0) { - continue; - } - - m[0] += tmp; - m[1] -= tmp; - u[0] = m[0] / w[0]; - u[1] = m[1] / w[1]; - dU = u[0] - u[1]; - variance = w[0] * w[1] * dU * dU; - - if (variance > maxVariance) { - threshold = (tonalValue + 1f) / histogram.length; - maxVariance = variance; - } - } - return threshold; - } - } - - private interface ThresholdAlgorithm { - float compute(Bitmap bitmap, int[] histogram); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java deleted file mode 100644 index f815b5d476ec..000000000000 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2019 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.systemui.glwallpaper; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.util.Log; - -import com.android.systemui.Interpolators; - -/** - * Use ValueAnimator and appropriate interpolator to control the progress of reveal transition. - * The transition will happen while getting awake and quit events. - */ -class ImageRevealHelper { - private static final String TAG = ImageRevealHelper.class.getSimpleName(); - private static final float MAX_REVEAL = 0f; - private static final float MIN_REVEAL = 1f; - private static final boolean DEBUG = true; - - private final ValueAnimator mAnimator; - private final RevealStateListener mRevealListener; - private float mReveal = MAX_REVEAL; - private boolean mAwake = false; - - ImageRevealHelper(RevealStateListener listener) { - mRevealListener = listener; - mAnimator = ValueAnimator.ofFloat(); - mAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); - mAnimator.addUpdateListener(animator -> { - mReveal = (float) animator.getAnimatedValue(); - if (mRevealListener != null) { - mRevealListener.onRevealStateChanged(); - } - }); - mAnimator.addListener(new AnimatorListenerAdapter() { - private boolean mIsCanceled; - - @Override - public void onAnimationCancel(Animator animation) { - mIsCanceled = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - if (!mIsCanceled && mRevealListener != null) { - if (DEBUG) { - Log.d(TAG, "transition end"); - } - mRevealListener.onRevealEnd(); - } - mIsCanceled = false; - } - - @Override - public void onAnimationStart(Animator animation) { - if (mRevealListener != null) { - if (DEBUG) { - Log.d(TAG, "transition start"); - } - mRevealListener.onRevealStart(true /* animate */); - } - } - }); - } - - public float getReveal() { - return mReveal; - } - - void updateAwake(boolean awake, long duration) { - if (DEBUG) { - Log.d(TAG, "updateAwake: awake=" + awake + ", duration=" + duration); - } - mAnimator.cancel(); - mAwake = awake; - if (duration == 0) { - // We are transiting from home to aod or aod to home directly, - // we don't need to do transition in these cases. - mReveal = mAwake ? MAX_REVEAL : MIN_REVEAL; - mRevealListener.onRevealStart(false /* animate */); - mRevealListener.onRevealStateChanged(); - mRevealListener.onRevealEnd(); - } else { - mAnimator.setDuration(duration); - mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL); - mAnimator.start(); - } - } - - /** - * A listener to trace value changes of reveal. - */ - public interface RevealStateListener { - - /** - * Called back while reveal status changes. - */ - void onRevealStateChanged(); - - /** - * Called back while reveal starts. - */ - void onRevealStart(boolean animate); - - /** - * Called back while reveal ends. - */ - void onRevealEnd(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index e9ddb3831b1a..1a0356c4446d 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -19,18 +19,14 @@ package com.android.systemui.glwallpaper; import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; import static android.opengl.GLES20.glClear; import static android.opengl.GLES20.glClearColor; -import static android.opengl.GLES20.glUniform1f; import static android.opengl.GLES20.glViewport; import android.app.WallpaperManager; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Rect; import android.util.Log; -import android.util.MathUtils; import android.util.Size; -import android.view.DisplayInfo; import com.android.systemui.R; @@ -42,57 +38,24 @@ import java.util.function.Consumer; /** * A GL renderer for image wallpaper. */ -public class ImageWallpaperRenderer implements GLWallpaperRenderer, - ImageRevealHelper.RevealStateListener { +public class ImageWallpaperRenderer implements GLWallpaperRenderer { private static final String TAG = ImageWallpaperRenderer.class.getSimpleName(); - private static final float SCALE_VIEWPORT_MIN = 1f; - private static final float SCALE_VIEWPORT_MAX = 1.1f; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private final ImageGLProgram mProgram; private final ImageGLWallpaper mWallpaper; - private final ImageProcessHelper mImageProcessHelper; - private final ImageRevealHelper mImageRevealHelper; - - private SurfaceProxy mProxy; - private final Rect mScissor; private final Rect mSurfaceSize = new Rect(); - private final Rect mViewport = new Rect(); - private boolean mScissorMode; - private float mXOffset; - private float mYOffset; private final WallpaperTexture mTexture; - public ImageWallpaperRenderer(Context context, SurfaceProxy proxy) { + public ImageWallpaperRenderer(Context context) { final WallpaperManager wpm = context.getSystemService(WallpaperManager.class); if (wpm == null) { Log.w(TAG, "WallpaperManager not available"); } mTexture = new WallpaperTexture(wpm); - DisplayInfo displayInfo = new DisplayInfo(); - context.getDisplay().getDisplayInfo(displayInfo); - - // We only do transition in portrait currently, b/137962047. - int orientation = context.getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); - } else { - mScissor = new Rect(0, 0, displayInfo.logicalHeight, displayInfo.logicalWidth); - } - - mProxy = proxy; mProgram = new ImageGLProgram(context); mWallpaper = new ImageGLWallpaper(mProgram); - mImageProcessHelper = new ImageProcessHelper(); - mImageRevealHelper = new ImageRevealHelper(this); - - startProcessingImage(); - } - - protected void startProcessingImage() { - // Compute threshold of the image, this is an async work. - mImageProcessHelper.start(mTexture); } @Override @@ -121,103 +84,26 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, @Override public void onDrawFrame() { - float threshold = mImageProcessHelper.getThreshold(); - float reveal = mImageRevealHelper.getReveal(); - - glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), 1); - glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), threshold); - glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal); - glClear(GL_COLOR_BUFFER_BIT); - // We only need to scale viewport while doing transition. - if (mScissorMode) { - scaleViewport(reveal); - } else { - glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height()); - } + glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height()); mWallpaper.useTexture(); mWallpaper.draw(); } @Override - public void updateAmbientMode(boolean inAmbientMode, long duration) { - mImageRevealHelper.updateAwake(!inAmbientMode, duration); - } - - @Override - public void updateOffsets(float xOffset, float yOffset) { - mXOffset = xOffset; - mYOffset = yOffset; - int left = (int) ((mSurfaceSize.width() - mScissor.width()) * xOffset); - int right = left + mScissor.width(); - mScissor.set(left, mScissor.top, right, mScissor.bottom); - } - - @Override public Size reportSurfaceSize() { - mTexture.use(null); + mTexture.use(null /* consumer */); mSurfaceSize.set(mTexture.getTextureDimensions()); return new Size(mSurfaceSize.width(), mSurfaceSize.height()); } @Override public void finish() { - mProxy = null; - } - - private void scaleViewport(float reveal) { - int left = mScissor.left; - int top = mScissor.top; - int width = mScissor.width(); - int height = mScissor.height(); - // Interpolation between SCALE_VIEWPORT_MAX and SCALE_VIEWPORT_MIN by reveal. - float vpScaled = MathUtils.lerp(SCALE_VIEWPORT_MIN, SCALE_VIEWPORT_MAX, reveal); - // Calculate the offset amount from the lower left corner. - float offset = (SCALE_VIEWPORT_MIN - vpScaled) / 2; - // Change the viewport. - mViewport.set((int) (left + width * offset), (int) (top + height * offset), - (int) (width * vpScaled), (int) (height * vpScaled)); - glViewport(mViewport.left, mViewport.top, mViewport.right, mViewport.bottom); - } - - @Override - public void onRevealStateChanged() { - mProxy.requestRender(); - } - - @Override - public void onRevealStart(boolean animate) { - if (animate) { - mScissorMode = true; - // Use current display area of texture. - mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset); - } - mProxy.preRender(); - } - - @Override - public void onRevealEnd() { - if (mScissorMode) { - mScissorMode = false; - // reset texture coordinates to use full texture. - mWallpaper.adjustTextureCoordinates(null, null, 0, 0); - // We need draw full texture back before finishing render. - mProxy.requestRender(); - } - mProxy.postRender(); } @Override public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { - out.print(prefix); out.print("mProxy="); out.print(mProxy); out.print(prefix); out.print("mSurfaceSize="); out.print(mSurfaceSize); - out.print(prefix); out.print("mScissor="); out.print(mScissor); - out.print(prefix); out.print("mViewport="); out.print(mViewport); - out.print(prefix); out.print("mScissorMode="); out.print(mScissorMode); - out.print(prefix); out.print("mXOffset="); out.print(mXOffset); - out.print(prefix); out.print("mYOffset="); out.print(mYOffset); - out.print(prefix); out.print("threshold="); out.print(mImageProcessHelper.getThreshold()); - out.print(prefix); out.print("mReveal="); out.print(mImageRevealHelper.getReveal()); out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent()); mWallpaper.dump(prefix, fd, out, args); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index a8a5d896537f..00f693de8f4d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -168,6 +168,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, void synchronizePinnedStackBounds() { cancelAnimations(); mBounds.set(mPipTaskOrganizer.getLastReportedBounds()); + mFloatingContentCoordinator.onContentMoved(this); } /** diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt new file mode 100644 index 000000000000..fa1b0267fafa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 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.systemui.settings + +import android.content.Context +import android.os.UserHandle +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.util.Assert +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Tracks a reference to the context for the current user + */ +@Singleton +class CurrentUserContextTracker @Inject constructor( + private val sysuiContext: Context, + broadcastDispatcher: BroadcastDispatcher +) { + private val userTracker: CurrentUserTracker + var currentUserContext: Context + + init { + userTracker = object : CurrentUserTracker(broadcastDispatcher) { + override fun onUserSwitched(newUserId: Int) { + handleUserSwitched(newUserId) + } + } + + currentUserContext = makeUserContext(userTracker.currentUserId) + } + + fun initialize() { + userTracker.startTracking() + } + + private fun handleUserSwitched(newUserId: Int) { + currentUserContext = makeUserContext(newUserId) + } + + private fun makeUserContext(uid: Int): Context { + Assert.isMainThread() + return sysuiContext.createContextAsUser( + UserHandle.getUserHandleForUid(userTracker.currentUserId), 0) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index d37e16b17620..75493f89993b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -699,7 +699,8 @@ public class NotificationEntryManager implements entry, oldImportances.get(entry.getKey()), oldAdjustments.get(entry.getKey()), - NotificationUiAdjustment.extractFromNotificationEntry(entry)); + NotificationUiAdjustment.extractFromNotificationEntry(entry), + mInflationCallback); } updateNotifications("updateNotificationRanking"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java index 2a3b2b7d815d..3fde2ed249d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; -import static com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager.alertAgain; +import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain; import android.annotation.Nullable; @@ -29,7 +29,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.headsup.HeadsUpViewBinder; +import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java index f4c4924b4b9a..710b137d2795 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java @@ -51,5 +51,6 @@ public interface NotificationRowBinder { NotificationEntry entry, @Nullable Integer oldImportance, NotificationUiAdjustment oldAdjustment, - NotificationUiAdjustment newAdjustment); + NotificationUiAdjustment newAdjustment, + NotificationRowContentBinder.InflationCallback callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 73f12f86e52e..e6a4cff0d893 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -180,13 +180,14 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { NotificationEntry entry, @Nullable Integer oldImportance, NotificationUiAdjustment oldAdjustment, - NotificationUiAdjustment newAdjustment) { + NotificationUiAdjustment newAdjustment, + NotificationRowContentBinder.InflationCallback callback) { if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) { if (entry.rowExists()) { ExpandableNotificationRow row = entry.getRow(); row.reset(); updateRow(entry, row); - inflateContentViews(entry, row, null /* callback */); + inflateContentViews(entry, row, callback); } else { // Once the RowInflaterTask is done, it will pick up the updated entry, so // no-op here. @@ -221,7 +222,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { private void inflateContentViews( NotificationEntry entry, ExpandableNotificationRow row, - NotificationRowContentBinder.InflationCallback inflationCallback) { + @Nullable NotificationRowContentBinder.InflationCallback inflationCallback) { final boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance()); final boolean isLowPriority = entry.isAmbient(); @@ -238,7 +239,9 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { mRowContentBindStage.requestRebind(entry, en -> { row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight); row.setIsLowPriority(isLowPriority); - inflationCallback.onAsyncInflationFinished(en); + if (inflationCallback != null) { + inflationCallback.onAsyncInflationFinished(en); + } }); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 565a082533a7..78ee5f25b111 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.settings.CurrentUserContextTracker; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -45,7 +46,6 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl; import com.android.systemui.statusbar.notification.init.NotificationsControllerStub; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -53,13 +53,14 @@ import com.android.systemui.statusbar.notification.logging.NotificationPanelLogg import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; import java.util.concurrent.Executor; +import javax.inject.Provider; import javax.inject.Singleton; import dagger.Binds; @@ -109,7 +110,9 @@ public interface NotificationsModule { HighPriorityProvider highPriorityProvider, INotificationManager notificationManager, LauncherApps launcherApps, - ShortcutManager shortcutManager) { + ShortcutManager shortcutManager, + CurrentUserContextTracker contextTracker, + Provider<PriorityOnboardingDialogController.Builder> builderProvider) { return new NotificationGutsManager( context, visualStabilityManager, @@ -119,7 +122,9 @@ public interface NotificationsModule { highPriorityProvider, notificationManager, launcherApps, - shortcutManager); + shortcutManager, + contextTracker, + builderProvider); } /** Provides an instance of {@link VisualStabilityManager} */ @@ -130,27 +135,6 @@ public interface NotificationsModule { return new VisualStabilityManager(notificationEntryManager, handler); } - /** Provides an instance of {@link NotificationAlertingManager} */ - @Singleton - @Provides - static NotificationAlertingManager provideNotificationAlertingManager( - NotificationEntryManager notificationEntryManager, - NotificationRemoteInputManager remoteInputManager, - VisualStabilityManager visualStabilityManager, - StatusBarStateController statusBarStateController, - NotificationInterruptStateProvider notificationInterruptStateProvider, - NotificationListener notificationListener, - HeadsUpManager headsUpManager) { - return new NotificationAlertingManager( - notificationEntryManager, - remoteInputManager, - visualStabilityManager, - statusBarStateController, - notificationInterruptStateProvider, - notificationListener, - headsUpManager); - } - /** Provides an instance of {@link NotificationLogger} */ @Singleton @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java deleted file mode 100644 index a7b1f37edf0e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.headsup; - -import androidx.annotation.NonNull; - -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Controller class for old pipeline heads up view binding. It listens to - * {@link NotificationEntryManager} entry events and appropriately binds or unbinds the heads up - * view. - * - * This has a subtle contract with {@link NotificationAlertingManager} where this controller handles - * the heads up binding, but {@link NotificationAlertingManager} listens for general inflation - * events to actually mark it heads up/update. In the new pipeline, we combine the classes. - * See {@link HeadsUpCoordinator}. - */ -@Singleton -public class HeadsUpBindController { - private final HeadsUpViewBinder mHeadsUpViewBinder; - private final NotificationInterruptStateProvider mInterruptStateProvider; - - @Inject - HeadsUpBindController( - HeadsUpViewBinder headsUpViewBinder, - NotificationInterruptStateProvider notificationInterruptStateProvider) { - mInterruptStateProvider = notificationInterruptStateProvider; - mHeadsUpViewBinder = headsUpViewBinder; - } - - /** - * Attach this controller and add its listeners. - */ - public void attach( - NotificationEntryManager entryManager, - HeadsUpManager headsUpManager) { - entryManager.addCollectionListener(mCollectionListener); - headsUpManager.addListener(mOnHeadsUpChangedListener); - } - - private NotifCollectionListener mCollectionListener = new NotifCollectionListener() { - @Override - public void onEntryAdded(NotificationEntry entry) { - if (mInterruptStateProvider.shouldHeadsUp(entry)) { - mHeadsUpViewBinder.bindHeadsUpView(entry, null); - } - } - - @Override - public void onEntryUpdated(NotificationEntry entry) { - if (mInterruptStateProvider.shouldHeadsUp(entry)) { - mHeadsUpViewBinder.bindHeadsUpView(entry, null); - } - } - - @Override - public void onEntryCleanUp(NotificationEntry entry) { - mHeadsUpViewBinder.abortBindCallback(entry); - } - }; - - private OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() { - @Override - public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) { - if (!isHeadsUp) { - mHeadsUpViewBinder.unbindHeadsUpView(entry); - } - } - }; -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 5fac5b1cf159..7f2f898565d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -28,7 +28,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.NotificationListController import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer -import com.android.systemui.statusbar.notification.headsup.HeadsUpBindController +import com.android.systemui.statusbar.notification.interruption.HeadsUpController import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper @@ -36,7 +36,7 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager import com.android.systemui.statusbar.phone.StatusBar import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.HeadsUpManager -import com.android.systemui.statusbar.notification.headsup.HeadsUpViewBinder +import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.policy.RemoteInputUriController import dagger.Lazy import java.io.FileDescriptor @@ -66,7 +66,7 @@ class NotificationsControllerImpl @Inject constructor( private val groupManager: NotificationGroupManager, private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper, private val headsUpManager: HeadsUpManager, - private val headsUpBindController: HeadsUpBindController, + private val headsUpController: HeadsUpController, private val headsUpViewBinder: HeadsUpViewBinder ) : NotificationsController { @@ -112,7 +112,7 @@ class NotificationsControllerImpl @Inject constructor( groupAlertTransferHelper.bind(entryManager, groupManager) headsUpManager.addListener(groupManager) headsUpManager.addListener(groupAlertTransferHelper) - headsUpBindController.attach(entryManager, headsUpManager) + headsUpController.attach(entryManager, headsUpManager) groupManager.setHeadsUpManager(headsUpManager) groupAlertTransferHelper.setHeadsUpManager(headsUpManager) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java index 5d070981f81b..6d14ccf85716 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -22,117 +22,117 @@ import android.app.Notification; import android.service.notification.StatusBarNotification; import android.util.Log; -import com.android.internal.statusbar.NotificationVisibility; +import androidx.annotation.NonNull; + import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.dagger.NotificationsModule; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; -/** Handles heads-up and pulsing behavior driven by notification changes. */ -public class NotificationAlertingManager { - - private static final String TAG = "NotifAlertManager"; +import javax.inject.Inject; +import javax.inject.Singleton; +/** + * Controller class for old pipeline heads up logic. It listens to {@link NotificationEntryManager} + * entry events and appropriately binds or unbinds the heads up view and promotes it to the top + * of the screen. + */ +@Singleton +public class HeadsUpController { + private final HeadsUpViewBinder mHeadsUpViewBinder; + private final NotificationInterruptStateProvider mInterruptStateProvider; private final NotificationRemoteInputManager mRemoteInputManager; private final VisualStabilityManager mVisualStabilityManager; private final StatusBarStateController mStatusBarStateController; - private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final NotificationListener mNotificationListener; + private final HeadsUpManager mHeadsUpManager; - private HeadsUpManager mHeadsUpManager; - - /** - * Injected constructor. See {@link NotificationsModule}. - */ - public NotificationAlertingManager( - NotificationEntryManager notificationEntryManager, + @Inject + HeadsUpController( + HeadsUpViewBinder headsUpViewBinder, + NotificationInterruptStateProvider notificationInterruptStateProvider, + HeadsUpManager headsUpManager, NotificationRemoteInputManager remoteInputManager, - VisualStabilityManager visualStabilityManager, StatusBarStateController statusBarStateController, - NotificationInterruptStateProvider notificationInterruptionStateProvider, - NotificationListener notificationListener, - HeadsUpManager headsUpManager) { + VisualStabilityManager visualStabilityManager, + NotificationListener notificationListener) { + mHeadsUpViewBinder = headsUpViewBinder; + mHeadsUpManager = headsUpManager; + mInterruptStateProvider = notificationInterruptStateProvider; mRemoteInputManager = remoteInputManager; - mVisualStabilityManager = visualStabilityManager; mStatusBarStateController = statusBarStateController; - mNotificationInterruptStateProvider = notificationInterruptionStateProvider; + mVisualStabilityManager = visualStabilityManager; mNotificationListener = notificationListener; - mHeadsUpManager = headsUpManager; + } - notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { - @Override - public void onEntryInflated(NotificationEntry entry) { - showAlertingView(entry); - } + /** + * Attach this controller and add its listeners. + */ + public void attach( + NotificationEntryManager entryManager, + HeadsUpManager headsUpManager) { + entryManager.addCollectionListener(mCollectionListener); + headsUpManager.addListener(mOnHeadsUpChangedListener); + } - @Override - public void onPreEntryUpdated(NotificationEntry entry) { - updateAlertState(entry); + private NotifCollectionListener mCollectionListener = new NotifCollectionListener() { + @Override + public void onEntryAdded(NotificationEntry entry) { + if (mInterruptStateProvider.shouldHeadsUp(entry)) { + mHeadsUpViewBinder.bindHeadsUpView( + entry, HeadsUpController.this::showAlertingView); } + } - @Override - public void onEntryRemoved( - NotificationEntry entry, - NotificationVisibility visibility, - boolean removedByUser, - int reason) { - stopAlerting(entry.getKey()); - } - }); - } + @Override + public void onEntryUpdated(NotificationEntry entry) { + updateHunState(entry); + } + + @Override + public void onEntryRemoved(NotificationEntry entry, int reason) { + stopAlerting(entry); + } + + @Override + public void onEntryCleanUp(NotificationEntry entry) { + mHeadsUpViewBinder.abortBindCallback(entry); + } + }; /** - * Adds the entry to the respective alerting manager if the content view was inflated and - * the entry should still alert. + * Adds the entry to the HUN manager and show it for the first time. */ private void showAlertingView(NotificationEntry entry) { - // TODO: Instead of this back and forth, we should listen to changes in heads up and - // cancel on-going heads up view inflation using the bind pipeline. - if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) { - mHeadsUpManager.showNotification(entry); - if (!mStatusBarStateController.isDozing()) { - // Mark as seen immediately - setNotificationShown(entry.getSbn()); - } + mHeadsUpManager.showNotification(entry); + if (!mStatusBarStateController.isDozing()) { + // Mark as seen immediately + setNotificationShown(entry.getSbn()); } } - private void updateAlertState(NotificationEntry entry) { - boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification()); + private void updateHunState(NotificationEntry entry) { + boolean hunAgain = alertAgain(entry, entry.getSbn().getNotification()); // includes check for whether this notification should be filtered: - boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry); - final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey()); - if (wasAlerting) { - if (shouldAlert) { - mHeadsUpManager.updateNotification(entry.getKey(), alertAgain); + boolean shouldHeadsUp = mInterruptStateProvider.shouldHeadsUp(entry); + final boolean wasHeadsUp = mHeadsUpManager.isAlerting(entry.getKey()); + if (wasHeadsUp) { + if (shouldHeadsUp) { + mHeadsUpManager.updateNotification(entry.getKey(), hunAgain); } else if (!mHeadsUpManager.isEntryAutoHeadsUpped(entry.getKey())) { // We don't want this to be interrupting anymore, let's remove it mHeadsUpManager.removeNotification(entry.getKey(), false /* removeImmediately */); } - } else if (shouldAlert && alertAgain) { - // This notification was updated to be alerting, show it! - mHeadsUpManager.showNotification(entry); + } else if (shouldHeadsUp && hunAgain) { + mHeadsUpViewBinder.bindHeadsUpView(entry, mHeadsUpManager::showNotification); } } - /** - * Checks whether an update for a notification warrants an alert for the user. - * - * @param oldEntry the entry for this notification. - * @param newNotification the new notification for this entry. - * @return whether this notification should alert the user. - */ - public static boolean alertAgain( - NotificationEntry oldEntry, Notification newNotification) { - return oldEntry == null || !oldEntry.hasInterrupted() - || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; - } - private void setNotificationShown(StatusBarNotification n) { try { mNotificationListener.setNotificationsShown(new String[]{n.getKey()}); @@ -141,10 +141,11 @@ public class NotificationAlertingManager { } } - private void stopAlerting(final String key) { - // Attempt to remove notifications from their alert manager. + private void stopAlerting(NotificationEntry entry) { + // Attempt to remove notifications from their HUN manager. // Though the remove itself may fail, it lets the manager know to remove as soon as // possible. + String key = entry.getKey(); if (mHeadsUpManager.isAlerting(key)) { // A cancel() in response to a remote input shouldn't be delayed, as it makes the // sending look longer than it takes. @@ -157,4 +158,28 @@ public class NotificationAlertingManager { mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); } } + + /** + * Checks whether an update for a notification warrants an alert for the user. + * + * @param oldEntry the entry for this notification. + * @param newNotification the new notification for this entry. + * @return whether this notification should alert the user. + */ + public static boolean alertAgain( + NotificationEntry oldEntry, Notification newNotification) { + return oldEntry == null || !oldEntry.hasInterrupted() + || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; + } + + private OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() { + @Override + public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) { + if (!isHeadsUp) { + mHeadsUpViewBinder.unbindHeadsUpView(entry); + } + } + }; + + private static final String TAG = "HeadsUpBindController"; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java index 37acfa8dc0a4..ff139957031a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpViewBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.headsup; +package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; @@ -42,7 +42,7 @@ import javax.inject.Singleton; * content view. * * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated - * (i.e. when {@link HeadsUpBindController} is removed). + * (i.e. when {@link HeadsUpController} is removed). */ @Singleton public class HeadsUpViewBinder { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index ab2cffa57c3e..55a593541819 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -23,6 +23,7 @@ import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static android.provider.Settings.Global.NOTIFICATION_BUBBLES; import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN; @@ -45,6 +46,7 @@ import android.graphics.drawable.Icon; import android.os.Handler; import android.os.Parcelable; import android.os.RemoteException; +import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.transition.ChangeBounds; @@ -53,7 +55,7 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.util.AttributeSet; import android.util.Log; -import android.util.Slog; +import android.view.LayoutInflater; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; @@ -63,6 +65,7 @@ import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Dependency; +import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.statusbar.notification.NotificationChannelHelper; import com.android.systemui.statusbar.notification.VisualStabilityManager; @@ -71,6 +74,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.lang.annotation.Retention; import java.util.List; +import javax.inject.Provider; + /** * The guts of a conversation notification revealed when performing a long press. */ @@ -93,6 +98,9 @@ public class NotificationConversationInfo extends LinearLayout implements private ShortcutInfo mShortcutInfo; private String mConversationId; private StatusBarNotification mSbn; + private Notification.BubbleMetadata mBubbleMetadata; + private Context mUserContext; + private Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider; private boolean mIsDeviceProvisioned; private int mAppBubble; @@ -136,17 +144,17 @@ public class NotificationConversationInfo extends LinearLayout implements */ private OnClickListener mOnFavoriteClick = v -> { - mSelectedAction = ACTION_FAVORITE; + setSelectedAction(ACTION_FAVORITE); updateToggleActions(mSelectedAction, true); }; private OnClickListener mOnDefaultClick = v -> { - mSelectedAction = ACTION_DEFAULT; + setSelectedAction(ACTION_DEFAULT); updateToggleActions(mSelectedAction, true); }; private OnClickListener mOnMuteClick = v -> { - mSelectedAction = ACTION_MUTE; + setSelectedAction(ACTION_MUTE); updateToggleActions(mSelectedAction, true); }; @@ -170,6 +178,23 @@ public class NotificationConversationInfo extends LinearLayout implements void onClick(View v, int hoursToSnooze); } + @VisibleForTesting + void setSelectedAction(int selectedAction) { + if (mSelectedAction == selectedAction) { + return; + } + + mSelectedAction = selectedAction; + onSelectedActionChanged(); + } + + private void onSelectedActionChanged() { + // If the user selected Priority, maybe show the priority onboarding + if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) { + showPriorityOnboarding(); + } + } + public void bindNotification( ShortcutManager shortcutManager, PackageManager pm, @@ -181,6 +206,8 @@ public class NotificationConversationInfo extends LinearLayout implements OnSettingsClickListener onSettingsClick, OnSnoozeClickListener onSnoozeClickListener, ConversationIconFactory conversationIconFactory, + Context userContext, + Provider<PriorityOnboardingDialogController.Builder> builderProvider, boolean isDeviceProvisioned) { mSelectedAction = -1; mINotificationManager = iNotificationManager; @@ -196,6 +223,9 @@ public class NotificationConversationInfo extends LinearLayout implements mIsDeviceProvisioned = isDeviceProvisioned; mOnSnoozeClickListener = onSnoozeClickListener; mIconFactory = conversationIconFactory; + mUserContext = userContext; + mBubbleMetadata = entry.getBubbleMetadata(); + mBuilderProvider = builderProvider; mShortcutManager = shortcutManager; mConversationId = mNotificationChannel.getConversationId(); @@ -213,7 +243,7 @@ public class NotificationConversationInfo extends LinearLayout implements try { mAppBubble = mINotificationManager.getBubblePreferenceForPackage(mPackageName, mAppUid); } catch (RemoteException e) { - Slog.e(TAG, "can't reach OS", e); + Log.e(TAG, "can't reach OS", e); mAppBubble = BUBBLE_PREFERENCE_SELECTED; } @@ -491,6 +521,38 @@ public class NotificationConversationInfo extends LinearLayout implements mAppUid, mSelectedAction, mNotificationChannel)); } + private boolean shouldShowPriorityOnboarding() { + return !Prefs.getBoolean(mUserContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, false); + } + + private void showPriorityOnboarding() { + View onboardingView = LayoutInflater.from(mContext) + .inflate(R.layout.priority_onboarding_half_shell, null); + + boolean ignoreDnd = false; + try { + ignoreDnd = (mINotificationManager + .getConsolidatedNotificationPolicy().priorityConversationSenders + & NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT) != 0; + } catch (RemoteException e) { + Log.e(TAG, "Could not check conversation senders", e); + } + + boolean showAsBubble = mBubbleMetadata.getAutoExpandBubble() + && Settings.Global.getInt(mContext.getContentResolver(), + NOTIFICATION_BUBBLES, 0) == 1; + + PriorityOnboardingDialogController controller = mBuilderProvider.get() + .setContext(mUserContext) + .setView(onboardingView) + .setIgnoresDnd(ignoreDnd) + .setShowsAsBubble(showAsBubble) + .build(); + + controller.init(); + controller.show(); + } + /** * Closes the controls and commits the updated importance values (indirectly). * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 2487d1a898a3..624fabc0a496 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -49,6 +49,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.settings.CurrentUserContextTracker; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; @@ -67,6 +68,8 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; import java.io.PrintWriter; +import javax.inject.Provider; + import dagger.Lazy; /** @@ -111,6 +114,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final INotificationManager mNotificationManager; private final LauncherApps mLauncherApps; private final ShortcutManager mShortcutManager; + private final CurrentUserContextTracker mContextTracker; + private final Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider; /** * Injected constructor. See {@link NotificationsModule}. @@ -121,7 +126,9 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx HighPriorityProvider highPriorityProvider, INotificationManager notificationManager, LauncherApps launcherApps, - ShortcutManager shortcutManager) { + ShortcutManager shortcutManager, + CurrentUserContextTracker contextTracker, + Provider<PriorityOnboardingDialogController.Builder> builderProvider) { mContext = context; mVisualStabilityManager = visualStabilityManager; mStatusBarLazy = statusBarLazy; @@ -131,6 +138,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mNotificationManager = notificationManager; mLauncherApps = launcherApps; mShortcutManager = shortcutManager; + mContextTracker = contextTracker; + mBuilderProvider = builderProvider; } public void setUpWithPresenter(NotificationPresenter presenter, @@ -403,6 +412,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx onSettingsClick, onSnoozeClickListener, iconFactoryLoader, + mContextTracker.getCurrentUserContext(), + mBuilderProvider, mDeviceProvisionedController.isDeviceProvisioned()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt new file mode 100644 index 000000000000..d1b405256f39 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2020 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.systemui.statusbar.notification.row + +import android.app.Dialog +import android.content.Context +import android.graphics.Color +import android.graphics.PixelFormat +import android.graphics.drawable.ColorDrawable +import android.view.Gravity +import android.view.View +import android.view.View.GONE +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.view.Window +import android.view.WindowInsets.Type.statusBars +import android.view.WindowManager +import android.widget.LinearLayout +import android.widget.TextView +import com.android.systemui.Prefs +import com.android.systemui.R +import java.lang.IllegalStateException +import javax.inject.Inject + +/** + * Controller to handle presenting the priority conversations onboarding dialog + */ +class PriorityOnboardingDialogController @Inject constructor( + val view: View, + val context: Context, + val ignoresDnd: Boolean, + val showsAsBubble: Boolean +) { + + private lateinit var dialog: Dialog + + fun init() { + initDialog() + } + + fun show() { + dialog.show() + } + + private fun done() { + // Log that the user has seen the onboarding + Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true) + dialog.dismiss() + } + + class Builder @Inject constructor() { + private lateinit var view: View + private lateinit var context: Context + private var ignoresDnd = false + private var showAsBubble = false + + fun setView(v: View): Builder { + view = v + return this + } + + fun setContext(c: Context): Builder { + context = c + return this + } + + fun setIgnoresDnd(ignore: Boolean): Builder { + ignoresDnd = ignore + return this + } + + fun setShowsAsBubble(bubble: Boolean): Builder { + showAsBubble = bubble + return this + } + + fun build(): PriorityOnboardingDialogController { + val controller = PriorityOnboardingDialogController( + view, context, ignoresDnd, showAsBubble) + return controller + } + } + + private fun initDialog() { + dialog = Dialog(context) + + if (dialog.window == null) { + throw IllegalStateException("Need a window for the onboarding dialog to show") + } + + dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) + // Prevent a11y readers from reading the first element in the dialog twice + dialog.setTitle("\u00A0") + dialog.apply { + setContentView(view) + setCanceledOnTouchOutside(true) + + findViewById<TextView>(R.id.done_button)?.setOnClickListener { + done() + } + + if (!ignoresDnd) { + findViewById<LinearLayout>(R.id.ignore_dnd_tip).visibility = GONE + } + + if (!showsAsBubble) { + findViewById<LinearLayout>(R.id.floating_bubble_tip).visibility = GONE + } + + window?.apply { + setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + addFlags(wmFlags) + setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL) + setWindowAnimations(com.android.internal.R.style.Animation_InputMethod) + + attributes = attributes.apply { + format = PixelFormat.TRANSLUCENT + title = ChannelEditorDialogController::class.java.simpleName + gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL + fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv() + width = MATCH_PARENT + height = WRAP_CONTENT + } + } + } + } + + private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS + or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 900b3ea97010..ca65665d4ae5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -193,7 +193,6 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -623,7 +622,6 @@ public class StatusBar extends SystemUI implements DemoMode, NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, // need to inject for now DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index b81a5198b498..02e031217904 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -62,7 +62,6 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -143,7 +142,6 @@ public interface StatusBarPhoneModule { NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -223,7 +221,6 @@ public interface StatusBarPhoneModule { notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 6e5f8a0ae5e9..051bd29bc323 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -367,7 +367,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mobileSignalController.unregisterListener(); } mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener); - mContext.unregisterReceiver(this); + mBroadcastDispatcher.unregisterReceiver(this); } public int getConnectedWifiLevel() { @@ -859,6 +859,7 @@ public class NetworkControllerImpl extends BroadcastReceiver pw.println(" - telephony ------"); pw.print(" hasVoiceCallingFeature()="); pw.println(hasVoiceCallingFeature()); + pw.println(" mListening=" + mListening); pw.println(" - connectivity ------"); pw.print(" mConnectedTransports="); diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt index ca4b67db0d46..242f7cde9d3b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt @@ -187,16 +187,23 @@ class FloatingContentCoordinator @Inject constructor() { // Tell that content to get out of the way, and save the bounds it says it's moving // (or animating) to. .forEach { (content, bounds) -> - content.moveToBounds( - content.calculateNewBoundsOnOverlap( - conflictingNewBounds, - // Pass all of the content bounds except the bounds of the - // content we're asking to move, and the conflicting new bounds - // (since those are passed separately). - otherContentBounds = allContentBounds.values - .minus(bounds) - .minus(conflictingNewBounds))) - allContentBounds[content] = content.getFloatingBoundsOnScreen() + val newBounds = content.calculateNewBoundsOnOverlap( + conflictingNewBounds, + // Pass all of the content bounds except the bounds of the + // content we're asking to move, and the conflicting new bounds + // (since those are passed separately). + otherContentBounds = allContentBounds.values + .minus(bounds) + .minus(conflictingNewBounds)) + + // If the new bounds are empty, it means there's no non-overlapping position + // that is in bounds. Just leave the content where it is. This should normally + // not happen, but sometimes content like PIP reports incorrect bounds + // temporarily. + if (!newBounds.isEmpty) { + content.moveToBounds(newBounds) + allContentBounds[content] = content.getFloatingBoundsOnScreen() + } } currentlyResolvingConflicts = false @@ -229,8 +236,8 @@ class FloatingContentCoordinator @Inject constructor() { * @param allowedBounds The area within which we're allowed to find new bounds for the * content. * @return New bounds for the content that don't intersect the exclusion rects or the - * newly overlapping rect, and that is within bounds unless no possible in-bounds position - * exists. + * newly overlapping rect, and that is within bounds - or an empty Rect if no in-bounds + * position exists. */ @JvmStatic fun findAreaForContentVertically( @@ -274,7 +281,13 @@ class FloatingContentCoordinator @Inject constructor() { !overlappingContentPushingDown && !positionAboveInBounds // Return the content rect, but offset to reflect the new position. - return if (usePositionBelow) newContentBoundsBelow else newContentBoundsAbove + val newBounds = if (usePositionBelow) newContentBoundsBelow else newContentBoundsAbove + + // If the new bounds are within the allowed bounds, return them. If not, it means that + // there are no legal new bounds. This can happen if the new content's bounds are too + // large (for example, full-screen PIP). Since there is no reasonable action to take + // here, return an empty Rect and we will just not move the content. + return if (allowedBounds.contains(newBounds)) newBounds else Rect() } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java index 5227aaf01249..0c69ffdef372 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java @@ -16,7 +16,6 @@ package com.android.systemui; -import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.doReturn; @@ -32,19 +31,16 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.ColorSpace; -import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.Handler; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.util.Size; import android.view.Display; import android.view.DisplayInfo; import android.view.SurfaceHolder; import com.android.systemui.glwallpaper.ImageWallpaperRenderer; -import com.android.systemui.statusbar.phone.DozeParameters; import org.junit.Before; import org.junit.Test; @@ -72,8 +68,6 @@ public class ImageWallpaperTest extends SysuiTestCase { @Mock private Bitmap mWallpaperBitmap; @Mock - private DozeParameters mDozeParam; - @Mock private Handler mHandler; private CountDownLatch mEventCountdown; @@ -100,14 +94,13 @@ public class ImageWallpaperTest extends SysuiTestCase { when(wallpaperManager.getBitmap(false)).thenReturn(mWallpaperBitmap); when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB)); when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888); - when(mDozeParam.getDisplayNeedsBlanking()).thenReturn(false); } private ImageWallpaper createImageWallpaper() { - return new ImageWallpaper(mDozeParam) { + return new ImageWallpaper() { @Override public Engine onCreateEngine() { - return new GLEngine(mDozeParam, mHandler) { + return new GLEngine(mHandler) { @Override public Context getDisplayContext() { return mMockContext; @@ -130,75 +123,52 @@ public class ImageWallpaperTest extends SysuiTestCase { }; } - private ImageWallpaperRenderer createImageWallpaperRenderer(ImageWallpaper.GLEngine engine) { - return new ImageWallpaperRenderer(mMockContext, engine) { - @Override - public void startProcessingImage() { - // No - Op - } - }; - } - @Test public void testBitmapWallpaper_normal() { // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH. // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH. - // Finally, we assert the transition will not be stopped. - verifySurfaceSizeAndAssertTransition(DISPLAY_WIDTH /* bmpWidth */, + verifySurfaceSize(DISPLAY_WIDTH /* bmpWidth */, DISPLAY_WIDTH /* bmpHeight */, DISPLAY_WIDTH /* surfaceWidth */, - DISPLAY_WIDTH /* surfaceHeight */, - false /* assertion */); + DISPLAY_WIDTH /* surfaceHeight */); } @Test public void testBitmapWallpaper_low_resolution() { // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT. // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT. - // Finally, we assert the transition will be stopped. - verifySurfaceSizeAndAssertTransition(LOW_BMP_WIDTH /* bmpWidth */, + verifySurfaceSize(LOW_BMP_WIDTH /* bmpWidth */, LOW_BMP_HEIGHT /* bmpHeight */, LOW_BMP_WIDTH /* surfaceWidth */, - LOW_BMP_HEIGHT /* surfaceHeight */, - false /* assertion */); + LOW_BMP_HEIGHT /* surfaceHeight */); } @Test public void testBitmapWallpaper_too_small() { // Will use a image wallpaper with dimensions INVALID_BMP_WIDTH x INVALID_BMP_HEIGHT. // Then we expect the surface size will be also MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT. - // Finally, we assert the transition will be stopped. - verifySurfaceSizeAndAssertTransition(INVALID_BMP_WIDTH /* bmpWidth */, + verifySurfaceSize(INVALID_BMP_WIDTH /* bmpWidth */, INVALID_BMP_HEIGHT /* bmpHeight */, ImageWallpaper.GLEngine.MIN_SURFACE_WIDTH /* surfaceWidth */, - ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */, - false /* assertion */); + ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */); } - private void verifySurfaceSizeAndAssertTransition(int bmpWidth, int bmpHeight, - int surfaceWidth, int surfaceHeight, boolean assertion) { + private void verifySurfaceSize(int bmpWidth, int bmpHeight, + int surfaceWidth, int surfaceHeight) { ImageWallpaper.GLEngine wallpaperEngine = (ImageWallpaper.GLEngine) createImageWallpaper().onCreateEngine(); ImageWallpaper.GLEngine engineSpy = spy(wallpaperEngine); - when(engineSpy.mIsHighEndGfx).thenReturn(true); when(mWallpaperBitmap.getWidth()).thenReturn(bmpWidth); when(mWallpaperBitmap.getHeight()).thenReturn(bmpHeight); - ImageWallpaperRenderer renderer = createImageWallpaperRenderer(engineSpy); + ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mMockContext); doReturn(renderer).when(engineSpy).getRendererInstance(); engineSpy.onCreate(engineSpy.getSurfaceHolder()); verify(mSurfaceHolder, times(1)).setFixedSize(surfaceWidth, surfaceHeight); assertWithMessage("setFixedSizeAllowed should have been called.").that( mEventCountdown.getCount()).isEqualTo(0); - - Size frameSize = renderer.reportSurfaceSize(); - Rect frame = new Rect(0, 0, frameSize.getWidth(), frameSize.getHeight()); - when(mSurfaceHolder.getSurfaceFrame()).thenReturn(frame); - - assertThat(engineSpy.checkIfShouldStopTransition()).isEqualTo(assertion); - // destroy } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java index 4b47093bb951..e23507b0a895 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java @@ -40,6 +40,7 @@ import com.android.systemui.SysuiTestCase; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -84,22 +85,17 @@ public class EglHelperTest extends SysuiTestCase { } @Test - public void testInit_finish() { + public void testInit_normal() { mEglHelper.init(mSurfaceHolder, false /* wideColorGamut */); assertThat(mEglHelper.hasEglDisplay()).isTrue(); assertThat(mEglHelper.hasEglContext()).isTrue(); assertThat(mEglHelper.hasEglSurface()).isTrue(); verify(mEglHelper).askCreatingEglWindowSurface( any(SurfaceHolder.class), eq(null), anyInt()); - - mEglHelper.finish(); - assertThat(mEglHelper.hasEglSurface()).isFalse(); - assertThat(mEglHelper.hasEglContext()).isFalse(); - assertThat(mEglHelper.hasEglDisplay()).isFalse(); } @Test - public void testInit_finish_wide_gamut() { + public void testInit_wide_gamut() { // In EglHelper, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490; doReturn(0x3490).when(mEglHelper).getWcgCapability(); // In EglHelper, KHR_GL_COLOR_SPACE = "EGL_KHR_gl_colorspace"; @@ -113,10 +109,10 @@ public class EglHelperTest extends SysuiTestCase { .askCreatingEglWindowSurface(any(SurfaceHolder.class), ac.capture(), anyInt()); assertThat(ac.getValue()).isNotNull(); assertThat(ac.getValue()).isEqualTo(expectedArgument); - mEglHelper.finish(); } @Test + @Ignore public void testFinish_shouldNotCrash() { mEglHelper.terminateEglDisplay(); assertThat(mEglHelper.hasEglDisplay()).isFalse(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java deleted file mode 100644 index c827ac7ab963..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2019 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.systemui.glwallpaper; - -import static com.google.common.truth.Truth.assertThat; - -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class ImageRevealHelperTest extends SysuiTestCase { - - static final int ANIMATION_DURATION = 500; - ImageRevealHelper mImageRevealHelper; - ImageRevealHelper.RevealStateListener mRevealStateListener; - - @Before - public void setUp() throws Exception { - mRevealStateListener = new ImageRevealHelper.RevealStateListener() { - @Override - public void onRevealStateChanged() { - // no-op - } - - @Override - public void onRevealStart(boolean animate) { - // no-op - } - - @Override - public void onRevealEnd() { - // no-op - } - }; - mImageRevealHelper = new ImageRevealHelper(mRevealStateListener); - } - - @Test - public void testBiometricAuthUnlockAnimateImageRevealState_shouldNotBlackoutScreen() { - assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f); - - mImageRevealHelper.updateAwake(true /* awake */, ANIMATION_DURATION); - assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f); - - // When device unlock through Biometric, should not show reveal transition - mImageRevealHelper.updateAwake(false /* awake */, 0); - assertThat(mImageRevealHelper.getReveal()).isEqualTo(1f); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java index d61be37692c4..24f3eb27579a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java @@ -16,8 +16,6 @@ package com.android.systemui.glwallpaper; -import static com.android.systemui.glwallpaper.GLWallpaperRenderer.SurfaceProxy; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; @@ -48,30 +46,12 @@ import java.util.Set; public class ImageWallpaperRendererTest extends SysuiTestCase { private WallpaperManager mWpmSpy; - private SurfaceProxy mSurfaceProxy; @Before public void setUp() throws Exception { final WallpaperManager wpm = mContext.getSystemService(WallpaperManager.class); mWpmSpy = spy(wpm); mContext.addMockSystemService(WallpaperManager.class, mWpmSpy); - - mSurfaceProxy = new SurfaceProxy() { - @Override - public void requestRender() { - // NO-op - } - - @Override - public void preRender() { - // No-op - } - - @Override - public void postRender() { - // No-op - } - }; } @Test @@ -91,12 +71,12 @@ public class ImageWallpaperRendererTest extends SysuiTestCase { doReturn(supportedWideGamuts).when(cmProxySpy).getSupportedColorSpaces(); mWpmSpy.setBitmap(p3Bitmap); - ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext, mSurfaceProxy); + ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext); rendererP3.reportSurfaceSize(); assertThat(rendererP3.isWcgContent()).isTrue(); mWpmSpy.setBitmap(srgbBitmap); - ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext, mSurfaceProxy); + ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext); assertThat(renderer.isWcgContent()).isFalse(); } finally { srgbBitmap.recycle(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java index f3038ce051cd..730481afe638 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java @@ -39,7 +39,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.headsup.HeadsUpViewBinder; +import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; import com.android.systemui.statusbar.policy.HeadsUpManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java index 6bcaee100496..61388b6d0389 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java @@ -16,15 +16,12 @@ package com.android.systemui.statusbar.notification.row; -import static android.app.Notification.FLAG_BUBBLE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME; -import static android.provider.Settings.Global.NOTIFICATION_BUBBLES; -import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -38,8 +35,10 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -51,6 +50,7 @@ import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.PendingIntent; import android.app.Person; +import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherApps; @@ -61,20 +61,19 @@ import android.content.pm.ShortcutManager; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.UserHandle; -import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.LayoutInflater; import android.view.View; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Dependency; +import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; @@ -89,6 +88,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; @@ -99,6 +99,8 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; +import javax.inject.Provider; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -145,6 +147,11 @@ public class NotificationConversationInfoTest extends SysuiTestCase { private ShadeController mShadeController; @Mock private ConversationIconFactory mIconFactory; + @Mock + private Context mUserContext; + @Mock(answer = Answers.RETURNS_SELF) + private PriorityOnboardingDialogController.Builder mBuilder; + private Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider = () -> mBuilder; @Before public void setUp() throws Exception { @@ -236,6 +243,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon); assertEquals(mIconDrawable, view.getDrawable()); @@ -255,6 +264,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name); assertTrue(textView.getText().toString().contains("App Name")); @@ -300,6 +311,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final TextView textView = mNotificationInfo.findViewById(R.id.group_name); assertTrue(textView.getText().toString().contains(group.getName())); @@ -321,6 +334,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final TextView textView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -341,6 +356,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(GONE, nameView.getVisibility()); @@ -368,6 +385,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(VISIBLE, nameView.getVisibility()); @@ -391,6 +410,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { }, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final View settingsButton = mNotificationInfo.findViewById(R.id.info); @@ -412,6 +433,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); @@ -434,6 +457,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { }, null, mIconFactory, + mUserContext, + mBuilderProvider, false); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); @@ -454,6 +479,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View view = mNotificationInfo.findViewById(R.id.silence); assertThat(view.isSelected()).isTrue(); @@ -477,6 +504,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View view = mNotificationInfo.findViewById(R.id.default_behavior); assertThat(view.isSelected()).isTrue(); @@ -503,6 +532,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View view = mNotificationInfo.findViewById(R.id.default_behavior); assertThat(view.isSelected()).isTrue(); @@ -528,6 +559,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View fave = mNotificationInfo.findViewById(R.id.priority); @@ -566,6 +599,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); @@ -603,6 +638,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View silence = mNotificationInfo.findViewById(R.id.silence); @@ -641,6 +678,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View fave = mNotificationInfo.findViewById(R.id.priority); @@ -673,6 +712,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View fave = mNotificationInfo.findViewById(R.id.priority); @@ -703,6 +744,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); @@ -734,6 +777,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); @@ -765,6 +810,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); @@ -795,6 +842,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); View silence = mNotificationInfo.findViewById(R.id.silence); @@ -824,6 +873,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage( @@ -844,9 +895,81 @@ public class NotificationConversationInfoTest extends SysuiTestCase { null, null, mIconFactory, + mUserContext, + mBuilderProvider, true); verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage( anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID)); } + + @Test + public void testSelectPriorityPresentsOnboarding_firstTime() { + // GIVEN pref is false + Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, false); + + // GIVEN the priority onboarding screen is present + PriorityOnboardingDialogController.Builder b = + new PriorityOnboardingDialogController.Builder(); + PriorityOnboardingDialogController controller = + mock(PriorityOnboardingDialogController.class); + when(b.build()).thenReturn(controller); + + // GIVEN the user is changing conversation settings + when(mBuilderProvider.get()).thenReturn(b); + mNotificationInfo.bindNotification( + mShortcutManager, + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mEntry, + null, + null, + mIconFactory, + mUserContext, + mBuilderProvider, + true); + + // WHEN user clicks "priority" + mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); + + // THEN the user is presented with the priority onboarding screen + verify(controller, atLeastOnce()).show(); + } + + @Test + public void testSelectPriorityDoesNotShowOnboarding_secondTime() { + //WHEN pref is true + Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true); + + PriorityOnboardingDialogController.Builder b = + new PriorityOnboardingDialogController.Builder(); + PriorityOnboardingDialogController controller = + mock(PriorityOnboardingDialogController.class); + when(b.build()).thenReturn(controller); + + when(mBuilderProvider.get()).thenReturn(b); + mNotificationInfo.bindNotification( + mShortcutManager, + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mEntry, + null, + null, + mIconFactory, + mUserContext, + mBuilderProvider, + true); + + // WHEN user clicks "priority" + mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); + + // THEN the user is presented with the priority onboarding screen + verify(controller, never()).show(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index ed4642344dba..5813740712b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -66,6 +66,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.settings.CurrentUserContextTracker; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.notification.NotificationActivityStarter; @@ -83,11 +84,14 @@ import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import javax.inject.Provider; + /** * Tests for {@link NotificationGutsManager}. */ @@ -120,6 +124,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private LauncherApps mLauncherApps; @Mock private ShortcutManager mShortcutManager; @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier; + @Mock private CurrentUserContextTracker mContextTracker; + @Mock(answer = Answers.RETURNS_SELF) + private PriorityOnboardingDialogController.Builder mBuilder; + private Provider<PriorityOnboardingDialogController.Builder> mProvider = () -> mBuilder; @Before public void setUp() { @@ -136,7 +144,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager, () -> mStatusBar, mHandler, mAccessibilityManager, mHighPriorityProvider, - mINotificationManager, mLauncherApps, mShortcutManager); + mINotificationManager, mLauncherApps, mShortcutManager, mContextTracker, mProvider); mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, mCheckSaveListener, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index b905bddb98f5..5a08c9ca017b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -120,7 +120,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake; @@ -193,7 +192,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private StatusBarNotificationPresenter mNotificationPresenter; @Mock private NotificationEntryListener mEntryListener; @Mock private NotificationFilter mNotificationFilter; - @Mock private NotificationAlertingManager mNotificationAlertingManager; @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration; @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -352,7 +350,6 @@ public class StatusBarTest extends SysuiTestCase { mNotificationInterruptStateProvider, mNotificationViewHierarchyManager, mKeyguardViewMediator, - mNotificationAlertingManager, new DisplayMetrics(), mMetricsLogger, mUiBgExecutor, diff --git a/read-snapshot.txt b/read-snapshot.txt deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/read-snapshot.txt +++ /dev/null diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index d252f9e69a22..f21f0e73e787 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -197,8 +197,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final MainHandler mMainHandler; - // Lazily initialized - access through getSystemActionPerfomer() - private SystemActionPerformer mSystemActionPerformer; + private final SystemActionPerformer mSystemActionPerformer; private MagnificationController mMagnificationController; @@ -296,6 +295,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class); mPackageManager = mContext.getPackageManager(); mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this); + mSystemActionPerformer = + new SystemActionPerformer(mContext, mWindowManagerService, null, this); mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, mWindowManagerService, this, mSecurityPolicy, this); mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); @@ -671,7 +672,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mSecurityPolicy.enforceCallerIsRecentsOrHasPermission( Manifest.permission.MANAGE_ACCESSIBILITY, FUNCTION_REGISTER_SYSTEM_ACTION); - getSystemActionPerformer().registerSystemAction(actionId, action); + mSystemActionPerformer.registerSystemAction(actionId, action); } /** @@ -684,15 +685,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mSecurityPolicy.enforceCallerIsRecentsOrHasPermission( Manifest.permission.MANAGE_ACCESSIBILITY, FUNCTION_UNREGISTER_SYSTEM_ACTION); - getSystemActionPerformer().unregisterSystemAction(actionId); - } - - private SystemActionPerformer getSystemActionPerformer() { - if (mSystemActionPerformer == null) { - mSystemActionPerformer = - new SystemActionPerformer(mContext, mWindowManagerService, null, this); - } - return mSystemActionPerformer; + mSystemActionPerformer.unregisterSystemAction(actionId); } @Override @@ -804,7 +797,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub synchronized (mLock) { mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient, mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler, - mSecurityPolicy, this, mWindowManagerService, getSystemActionPerformer(), + mSecurityPolicy, this, mWindowManagerService, mSystemActionPerformer, mA11yWindowManager, flags); onUserStateChangedLocked(getCurrentUserStateLocked()); } @@ -1515,7 +1508,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (service == null) { service = new AccessibilityServiceConnection(userState, mContext, componentName, installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, - this, mWindowManagerService, getSystemActionPerformer(), + this, mWindowManagerService, mSystemActionPerformer, mA11yWindowManager, mActivityTaskManagerService); } else if (userState.mBoundServices.contains(service)) { continue; @@ -2764,7 +2757,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub userState, mContext, COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, AccessibilityManagerService.this, mWindowManagerService, - getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) { + mSystemActionPerformer, mA11yWindowManager, mActivityTaskManagerService) { @Override public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { return true; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 5a3464d8a35f..764ac969e188 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2338,8 +2338,7 @@ public final class PowerManagerService extends SystemService nextTimeout = -1; } - if (((mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0 - || (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM) != 0) + if ((mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0 && (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) == 0) { nextTimeout = mAttentionDetector.updateUserActivity(nextTimeout, screenDimDuration); diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 288c22a94b45..1afec9c18a7f 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -2059,32 +2059,35 @@ public class StatsPullAtomService extends SystemService { synchronized (mProcessStatsLock) { final long token = Binder.clearCallingIdentity(); try { + // force procstats to flush & combine old files into one store long lastHighWaterMark = readProcStatsHighWaterMark(section); List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); - long highWaterMark = processStatsService.getCommittedStats( - lastHighWaterMark, section, true, statsFiles); - if (statsFiles.size() != 1) { - return StatsManager.PULL_SKIP; - } - unpackStreamedData(atomTag, pulledData, statsFiles); + + ProcessStats procStats = new ProcessStats(false); + long highWaterMark = processStatsService.getCommittedStatsMerged( + lastHighWaterMark, section, true, statsFiles, procStats); + + // aggregate the data together for westworld consumption + ProtoOutputStream proto = new ProtoOutputStream(); + procStats.dumpAggregatedProtoForStatsd(proto); + + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeByteArray(proto.getBytes()) + .build(); + pulledData.add(e); + new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark) .delete(); new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark) .createNewFile(); - } catch (IOException e) { - Slog.e(TAG, "Getting procstats failed: ", e); - return StatsManager.PULL_SKIP; - } catch (RemoteException e) { - Slog.e(TAG, "Getting procstats failed: ", e); - return StatsManager.PULL_SKIP; - } catch (SecurityException e) { + } catch (RemoteException | IOException e) { Slog.e(TAG, "Getting procstats failed: ", e); return StatsManager.PULL_SKIP; } finally { Binder.restoreCallingIdentity(token); } } - return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java index 06c2354c7a7d..f59d431d4382 100644 --- a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java +++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java @@ -27,6 +27,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Handler; import android.os.UserHandle; +import android.text.TextUtils.SimpleStringSplitter; import android.util.Log; import android.util.Slog; @@ -34,6 +35,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; +import java.util.Set; /** * Watches for emote provider services to be installed. @@ -51,8 +54,8 @@ final class TvRemoteProviderWatcher { private final PackageManager mPackageManager; private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>(); private final int mUserId; - private final String mUnbundledServicePackage; private final Object mLock; + private final Set<String> mUnbundledServicePackages = new HashSet<>(); private boolean mRunning; @@ -61,9 +64,19 @@ final class TvRemoteProviderWatcher { mHandler = new Handler(true); mUserId = UserHandle.myUserId(); mPackageManager = context.getPackageManager(); - mUnbundledServicePackage = context.getString( - com.android.internal.R.string.config_tvRemoteServicePackage); mLock = lock; + + // Unbundled package names supports a comma-separated list + SimpleStringSplitter splitter = new SimpleStringSplitter(','); + splitter.setString(context.getString( + com.android.internal.R.string.config_tvRemoteServicePackage)); + + splitter.forEach(packageName -> { + packageName = packageName.trim(); + if (!packageName.isEmpty()) { + mUnbundledServicePackages.add(packageName); + } + }); } public void start() { @@ -157,7 +170,7 @@ final class TvRemoteProviderWatcher { } // Check if package name is white-listed here. - if (!serviceInfo.packageName.equals(mUnbundledServicePackage)) { + if (!mUnbundledServicePackages.contains(serviceInfo.packageName)) { Slog.w(TAG, "Ignoring atv remote provider service because the package has not " + "been set and/or whitelisted: " + serviceInfo.packageName + "/" + serviceInfo.name); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 1ffa01c2bd66..ea5967a51c5f 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1373,6 +1373,9 @@ class Task extends WindowContainer<WindowContainer> { void addChild(WindowContainer child, int index) { // If this task had any child before we added this one. boolean hadChild = hasChild(); + // getActivityType() looks at the top child, so we need to read the type before adding + // a new child in case the new child is on top and UNDEFINED. + final int activityType = getActivityType(); index = getAdjustedChildPosition(child, index); super.addChild(child, index); @@ -1413,7 +1416,7 @@ class Task extends WindowContainer<WindowContainer> { ActivityTaskManager.getMaxAppRecentsLimitStatic()); } else { // Otherwise make all added activities match this one. - r.setActivityType(getActivityType()); + r.setActivityType(activityType); } updateEffectiveIntent(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 2b1f174d1175..00c84ecb9f1f 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1457,7 +1457,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void onDisplayChanged(DisplayContent dc) { - if (dc != null && mDisplayContent != null + if (dc != null && mDisplayContent != null && dc != mDisplayContent && mDisplayContent.mInputMethodInputTarget == this) { dc.setInputMethodInputTarget(mDisplayContent.mInputMethodInputTarget); mDisplayContent.mInputMethodInputTarget = null; diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING new file mode 100644 index 000000000000..8070bd1f06a1 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.om." + } + ] + } + ] +}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java index 0a2bb620eb11..55e526f01aef 100644 --- a/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java @@ -84,6 +84,22 @@ public class TvRemoteProviderWatcherTest { } @Test + public void acceptsValidCsvPackageName() { + // Test intentionally includes empty spacing for a more complex test + when(mMockResources.getString(com.android.internal.R.string.config_tvRemoteServicePackage)) + .thenReturn(",,foo, " + TV_REMOTE_SERVICE_PACKAGE_NAME + ",bar, baz,,"); + assertTrue(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo())); + } + + @Test + public void rejectsInvalidCsvPackageName() { + // Checks include empty strings to validate that processing as well + when(mMockResources.getString(com.android.internal.R.string.config_tvRemoteServicePackage)) + .thenReturn(",,foo,, ,bar, baz,,"); + assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo())); + } + + @Test public void tvServiceIsTrusted() { assertTrue(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo())); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java index ecb80156aecc..5e8de8792cd1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java @@ -25,6 +25,8 @@ import static android.view.Gravity.BOTTOM; import static android.view.Gravity.LEFT; import static android.view.Gravity.RIGHT; import static android.view.Gravity.TOP; +import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -60,7 +62,6 @@ import android.view.WindowInsets; import android.view.WindowManager; import android.widget.TextView; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.After; @@ -78,8 +79,6 @@ import java.util.function.BooleanSupplier; */ // TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags. // TODO: Test non-Activity windows. -@FlakyTest(detail = "TODO (b/145242835): Re-enable once type mapping is implemented for " - + "PRIVATE_FLAG_IS_SCREEN_DECOR") @SmallTest @Presubmit public class ScreenDecorWindowTests { @@ -187,13 +186,24 @@ public class ScreenDecorWindowTests { assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop()); } + @Test + public void testProvidesInsetsTypes() { + int[] providesInsetsTypes = new int[]{ITYPE_STATUS_BAR}; + final View win = createWindow("StatusBarSubPanel", TOP, MATCH_PARENT, mDecorThickness, RED, + FLAG_LAYOUT_IN_SCREEN, 0, providesInsetsTypes); + + assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness); + } + private View createDecorWindow(int gravity, int width, int height) { + int[] providesInsetsTypes = + new int[]{gravity == TOP ? ITYPE_STATUS_BAR : ITYPE_NAVIGATION_BAR}; return createWindow("decorWindow", gravity, width, height, RED, - FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR); + FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR, providesInsetsTypes); } private View createWindow(String name, int gravity, int width, int height, int color, int flags, - int privateFlags) { + int privateFlags, int[] providesInsetsTypes) { final View[] viewHolder = new View[1]; final int finalFlag = flags @@ -205,6 +215,7 @@ public class ScreenDecorWindowTests { width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE); lp.gravity = gravity; lp.privateFlags |= privateFlags; + lp.providesInsetsTypes = providesInsetsTypes; final TextView view = new TextView(mContext); view.setText("ScreenDecorWindowTests - " + name); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index 413ae134fe18..7cb5e84e4e48 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -208,4 +208,22 @@ public class TaskStackTests extends WindowTestsBase { assertEquals(stackBounds.left - stackOutset, stack.getLastSurfacePosition().x); assertEquals(stackBounds.top - stackOutset, stack.getLastSurfacePosition().y); } + + @Test + public void testActivityAndTaskGetsProperType() { + final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task task1 = createTaskInStack(stack, 0 /* userId */); + ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + + // First activity should become standard + task1.addChild(activity1, 0); + assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity1.getActivityType()); + assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType()); + + // Second activity should also become standard + ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + task1.addChild(activity2, WindowContainer.POSITION_TOP); + assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity2.getActivityType()); + assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType()); + } } diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml index c6b4a54f3b0b..dd255ef5233b 100644 --- a/tests/UiBench/AndroidManifest.xml +++ b/tests/UiBench/AndroidManifest.xml @@ -306,5 +306,14 @@ <category android:name="com.android.test.uibench.TEST" /> </intent-filter> </activity> + + <activity + android:name="WindowInsetsControllerActivity" + android:label="WindowInsetsControllerActivity" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.uibench.TEST" /> + </intent-filter> + </activity> </application> </manifest> diff --git a/tests/UiBench/src/com/android/test/uibench/WindowInsetsControllerActivity.java b/tests/UiBench/src/com/android/test/uibench/WindowInsetsControllerActivity.java new file mode 100644 index 000000000000..e4b89cdd5c8d --- /dev/null +++ b/tests/UiBench/src/com/android/test/uibench/WindowInsetsControllerActivity.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 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.test.uibench; + +import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; + +import android.os.Bundle; +import android.os.PersistableBundle; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import java.util.List; + +public class WindowInsetsControllerActivity extends AppCompatActivity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EditText text = new EditText(this); + text.setText("WindowInsetsController"); + setContentView(text); + getWindow().setDecorFitsSystemWindows(false); + + text.setWindowInsetsAnimationCallback( + new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { + @NonNull + @Override + public WindowInsets onProgress(@NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations) { + return WindowInsets.CONSUMED; + } + }); + } +} diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt index 2ecf3092035d..e55a89fddd0c 100644 --- a/wifi/jarjar-rules.txt +++ b/wifi/jarjar-rules.txt @@ -1,14 +1,41 @@ -# used by wifi-service -# TODO (b/153596226): Find a solution for networkstack's AIDL parcelables & interfaces. -# Parcelable class names are serialized in the wire, so renaming them -# will result in the class not being found for any parcelable received/sent from the -# wifi-service jar. +## used by service-wifi ## -# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). -rule android.net.DhcpResultsParcelable* @0 +# Network Stack AIDL interface. +rule android.net.DhcpResultsParcelable* com.android.wifi.x.@0 +rule android.net.IIpMemoryStore* com.android.wifi.x.@0 +rule android.net.IIpMemoryStoreCallbacks* com.android.wifi.x.@0 +rule android.net.INetd* com.android.wifi.x.@0 +rule android.net.INetdUnsolicitedEventListener* com.android.wifi.x.@0 +rule android.net.INetworkStackConnector* com.android.wifi.x.@0 +rule android.net.InformationElementParcelable* com.android.wifi.x.@0 +rule android.net.InitialConfigurationParcelable* com.android.wifi.x.@0 +rule android.net.InterfaceConfigurationParcel* com.android.wifi.x.@0 +rule android.net.Layer2InformationParcelable* com.android.wifi.x.@0 +rule android.net.Layer2PacketParcelable* com.android.wifi.x.@0 +rule android.net.MarkMaskParcel* com.android.wifi.x.@0 +rule android.net.NattKeepalivePacketDataParcelable* com.android.wifi.x.@0 +rule android.net.PrivateDnsConfigParcel* com.android.wifi.x.@0 +rule android.net.ProvisioningConfigurationParcelable* com.android.wifi.x.@0 +rule android.net.ResolverParamsParcel* com.android.wifi.x.@0 +rule android.net.RouteInfoParcel* com.android.wifi.x.@0 +rule android.net.ScanResultInfoParcelable* com.android.wifi.x.@0 +rule android.net.TetherConfigParcel* com.android.wifi.x.@0 +rule android.net.TetherOffloadRuleParcel* com.android.wifi.x.@0 +rule android.net.TetherStatsParcel* com.android.wifi.x.@0 +rule android.net.UidRangeParcel* com.android.wifi.x.@0 +rule android.net.dhcp.DhcpLeaseParcelable* com.android.wifi.x.@0 +rule android.net.dhcp.DhcpServingParamsParcel* com.android.wifi.x.@0 +rule android.net.ip.IIpClient* com.android.wifi.x.@0 +rule android.net.ip.IIpClientCallbacks* com.android.wifi.x.@0 +rule android.net.ipmemorystore.Blob* com.android.wifi.x.@0 +rule android.net.ipmemorystore.IOnBlobRetrievedListener* com.android.wifi.x.@0 +rule android.net.ipmemorystore.IOnStatusListener* com.android.wifi.x.@0 +rule android.net.ipmemorystore.NetworkAttributesParcelable* com.android.wifi.x.@0 +rule android.net.ipmemorystore.SameL3NetworkResponseParcelable* com.android.wifi.x.@0 +rule android.net.ipmemorystore.StatusParcelable* com.android.wifi.x.@0 + +# Net utils (includes Network Stack helper classes). rule android.net.DhcpResults* com.android.wifi.x.@0 -# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). -rule android.net.InterfaceConfigurationParcel* @0 rule android.net.InterfaceConfiguration* com.android.wifi.x.@0 rule android.net.IpMemoryStore* com.android.wifi.x.@0 rule android.net.NetworkMonitorManager* com.android.wifi.x.@0 @@ -19,8 +46,6 @@ rule android.net.ip.IpClientManager* com.android.wifi.x.@0 rule android.net.ip.IpClientUtil* com.android.wifi.x.@0 rule android.net.ipmemorystore.OnBlobRetrievedListener* com.android.wifi.x.@0 rule android.net.ipmemorystore.OnStatusListener* com.android.wifi.x.@0 -# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). -rule android.net.ipmemorystore.StatusParcelable* @0 rule android.net.ipmemorystore.Status* com.android.wifi.x.@0 rule android.net.networkstack.ModuleNetworkStackClient* com.android.wifi.x.@0 rule android.net.networkstack.NetworkStackClientBase* com.android.wifi.x.@0 @@ -81,7 +106,7 @@ rule org.ksoap2.** com.android.wifi.x.@0 # Use our statically linked nanohttpd rule fi.iki.elonen.** com.android.wifi.x.@0 -# used by both framework-wifi and wifi-service +## used by both framework-wifi and service-wifi ## rule android.content.pm.BaseParceledListSlice* com.android.wifi.x.@0 rule android.content.pm.ParceledListSlice* com.android.wifi.x.@0 rule android.net.shared.Inet4AddressUtils* com.android.wifi.x.@0 |