diff options
65 files changed, 1802 insertions, 551 deletions
diff --git a/Android.bp b/Android.bp index d8bcdbbbe26f..5590609659db 100644 --- a/Android.bp +++ b/Android.bp @@ -113,6 +113,7 @@ java_library {          "core/java/android/content/IOnPrimaryClipChangedListener.aidl",          "core/java/android/content/IRestrictionsManager.aidl",          "core/java/android/content/ISyncAdapter.aidl", +        "core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl",          "core/java/android/content/ISyncContext.aidl",          "core/java/android/content/ISyncServiceAdapter.aidl",          "core/java/android/content/ISyncStatusObserver.aidl", diff --git a/api/current.txt b/api/current.txt index 206d377bab47..70add6585cd0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8767,6 +8767,7 @@ package android.content {      method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);      method public void onSyncCanceled();      method public void onSyncCanceled(java.lang.Thread); +    method public boolean onUnsyncableAccount();      field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7    } @@ -36518,6 +36519,18 @@ package android.provider {      field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";    } +  public class SettingsSlicesContract { +    field public static final java.lang.String AUTHORITY = "android.settings.slices"; +    field public static final android.net.Uri BASE_URI; +    field public static final java.lang.String KEY_AIRPLANE_MODE = "airplane_mode"; +    field public static final java.lang.String KEY_BATTERY_SAVER = "battery_saver"; +    field public static final java.lang.String KEY_BLUETOOTH = "bluetooth"; +    field public static final java.lang.String KEY_LOCATION = "location"; +    field public static final java.lang.String KEY_WIFI = "wifi"; +    field public static final java.lang.String PATH_SETTING_ACTION = "action"; +    field public static final java.lang.String PATH_SETTING_INTENT = "intent"; +  } +    public class SyncStateContract {      ctor public SyncStateContract();    } diff --git a/api/system-current.txt b/api/system-current.txt index 6be004c5e82d..91270599f62b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5625,7 +5625,7 @@ package android.webkit {      field public final java.lang.String description;      field public final boolean isFallback;      field public final java.lang.String packageName; -    field public final java.lang.String[] signatures; +    field public final android.content.pm.Signature[] signatures;    }    public final class WebViewUpdateService { diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md index 9ea6fea966f2..5946515aa263 100644 --- a/cmds/bootanimation/FORMAT.md +++ b/cmds/bootanimation/FORMAT.md @@ -30,7 +30,7 @@ The first line defines the general parameters of the animation:  It is followed by a number of rows of the form: -    TYPE COUNT PAUSE PATH [#RGBHEX CLOCK] +    TYPE COUNT PAUSE PATH [#RGBHEX [CLOCK1 [CLOCK2]]]    * **TYPE:** a single char indicating what type of animation segment this is:        + `p` -- this part will play unless interrupted by the end of the boot @@ -39,11 +39,38 @@ It is followed by a number of rows of the form:    * **PAUSE:** number of FRAMES to delay after this part ends    * **PATH:** directory in which to find the frames for this part (e.g. `part0`)    * **RGBHEX:** _(OPTIONAL)_ a background color, specified as `#RRGGBB` -  * **CLOCK:** _(OPTIONAL)_ the y-coordinate at which to draw the current time (for watches) +  * **CLOCK1, CLOCK2:** _(OPTIONAL)_ the coordinates at which to draw the current time (for watches): +      + If only `CLOCK1` is provided it is the y-coordinate of the clock and the x-coordinate +        defaults to `c` +      + If both `CLOCK1` and `CLOCK2` are provided then `CLOCK1` is the x-coordinate and `CLOCK2` is +        the y-coodinate +      + Values can be either a positive integer, a negative integer, or `c` +          - `c` -- will centre the text +          - `n` -- will position the text n pixels from the start; left edge for x-axis, bottom edge +            for y-axis +          - `-n` -- will position the text n pixels from the end; right edge for x-axis, top edge +            for y-axis +          - Examples: +              * `-24` or `c -24` will position the text 24 pixels from the top of the screen, +                centred horizontally +              * `16 c` will position the text 16 pixels from the left of the screen, centred +                vertically +              * `-32 32` will position the text such that the bottom right corner is 32 pixels above +                and 32 pixels left of the edges of the screen  There is also a special TYPE, `$SYSTEM`, that loads `/system/media/bootanimation.zip`  and plays that. +## clock_font.png + +The file used to draw the time on top of the boot animation. The font format is as follows: +  * The file specifies glyphs for the ascii characters 32-127 (0x20-0x7F), both regular weight and +    bold weight. +  * The image is divided into a grid of characters +  * There are 16 columns and 6 rows +  * Each row is divided in half: regular weight glyphs on the top half, bold glyphs on the bottom +  * For a NxM image each character glyph will be N/16 pixels wide and M/(12*2) pixels high +  ## loading and playing frames  Each part is scanned and loaded directly from the zip archive. Within a part directory, every file diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 77b156f81e1a..c9902965ced0 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -21,7 +21,7 @@ package android.os.statsd;  option java_package = "com.android.os";  option java_outer_classname = "AtomsProto"; -import "frameworks/base/core/proto/android/app/activitymanager.proto"; +import "frameworks/base/core/proto/android/app/enums.proto";  /**   * The master atom class. This message defines all of the available @@ -44,7 +44,7 @@ message Atom {          BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;          BleScanResultReceived ble_scan_result_received = 4;          SensorStateChanged sensor_state_changed = 5; -        GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested +        GpsScanStateChanged gps_scan_state_changed = 6;          SyncStateChanged sync_state_changed = 7;          ScheduledJobStateChanged scheduled_job_state_changed = 8;          ScreenBrightnessChanged screen_brightness_changed = 9; @@ -185,9 +185,8 @@ message ScreenStateChanged {  message UidProcessStateChanged {      optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation -    // The state. -    // TODO: Use the real (mapped) process states. -    optional android.app.ProcessState state = 2; +    // The state, from frameworks/base/core/proto/android/app/enums.proto. +    optional android.app.ProcessStateEnum state = 2;  }  /** diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index 83b72d966a39..00d86582951f 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -63,7 +63,7 @@ static void parseFileName(char* name, int64_t* result) {  }  static string getFilePath(const char* path, int64_t timestamp, int64_t uid, int64_t configID) { -    return StringPrintf("%s/%lld-%d-%lld", path, (long long)timestamp, (int)uid, +    return StringPrintf("%s/%lld_%d_%lld", path, (long long)timestamp, (int)uid,                          (long long)configID);  } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index cd029c06b91d..b58c523f7927 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -129,6 +129,8 @@ import com.android.internal.app.WindowDecorActionBar;  import com.android.internal.policy.DecorView;  import com.android.internal.policy.PhoneWindow; +import dalvik.system.VMRuntime; +  import java.io.FileDescriptor;  import java.io.PrintWriter;  import java.lang.annotation.Retention; @@ -2136,11 +2138,15 @@ public class Activity extends ContextThemeWrapper       * @param params non-null parameters to be combined with previously set parameters when entering       * picture-in-picture.       * -     * @return true if the system puts this activity into picture-in-picture mode or was already -     * in picture-in-picture mode (@see {@link #isInPictureInPictureMode()) +     * @return true if the system successfully put this activity into picture-in-picture mode or was +     * already in picture-in-picture mode (@see {@link #isInPictureInPictureMode()). If the device +     * does not support picture-in-picture, return false.       */      public boolean enterPictureInPictureMode(@NonNull PictureInPictureParams params) {          try { +            if (!deviceSupportsPictureInPictureMode()) { +                return false; +            }              if (params == null) {                  throw new IllegalArgumentException("Expected non-null picture-in-picture params");              } @@ -2168,6 +2174,9 @@ public class Activity extends ContextThemeWrapper       */      public void setPictureInPictureParams(@NonNull PictureInPictureParams params) {          try { +            if (!deviceSupportsPictureInPictureMode()) { +                return; +            }              if (params == null) {                  throw new IllegalArgumentException("Expected non-null picture-in-picture params");              } @@ -2190,6 +2199,13 @@ public class Activity extends ContextThemeWrapper          }      } +    /** +     * @return Whether this device supports picture-in-picture. +     */ +    private boolean deviceSupportsPictureInPictureMode() { +        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); +    } +      void dispatchMovedToDisplay(int displayId, Configuration config) {          updateDisplay(displayId);          onMovedToDisplay(displayId, config); @@ -7099,11 +7115,12 @@ public class Activity extends ContextThemeWrapper          mFragments.dispatchStart();          mFragments.reportLoaderStart(); -        // This property is set for all builds except final release -        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;          boolean isAppDebuggable =                  (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; +        // This property is set for all builds except final release +        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1; +          if (isAppDebuggable || isDlwarningEnabled) {              String dlwarning = getDlWarning();              if (dlwarning != null) { @@ -7124,6 +7141,28 @@ public class Activity extends ContextThemeWrapper              }          } +        // We might disable this for final builds. +        boolean isApiWarningEnabled = true; + +        if (isAppDebuggable || isApiWarningEnabled) { +            if (VMRuntime.getRuntime().hasUsedHiddenApi()) { +                String appName = getApplicationInfo().loadLabel(getPackageManager()) +                        .toString(); +                String warning = "Detected problems with API compatiblity\n" +                                 + "(please consult log for detail)"; +                if (isAppDebuggable) { +                    new AlertDialog.Builder(this) +                        .setTitle(appName) +                        .setMessage(warning) +                        .setPositiveButton(android.R.string.ok, null) +                        .setCancelable(false) +                        .show(); +                } else { +                    Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show(); +                } +            } +        } +          mActivityTransitionState.enterReady(this);      } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index fcf8bd7b6699..4d5ac6f45703 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -575,18 +575,68 @@ public class ActivityManager {      /** @hide Process does not exist. */      public static final int PROCESS_STATE_NONEXISTENT = 19; -    // NOTE: If PROCESS_STATEs are added or changed, then new fields must be added -    // to frameworks/base/core/proto/android/app/activitymanager.proto and the following method must +    // NOTE: If PROCESS_STATEs are added, then new fields must be added +    // to frameworks/base/core/proto/android/app/enums.proto and the following method must      // be updated to correctly map between them. +    // However, if the current ActivityManager values are merely modified, no update should be made +    // to enums.proto, to which values can only be added but never modified. Note that the proto +    // versions do NOT have the ordering restrictions of the ActivityManager process state.      /** -     * Maps ActivityManager.PROCESS_STATE_ values to ProcessState enum. +     * Maps ActivityManager.PROCESS_STATE_ values to enums.proto ProcessStateEnum value.       *       * @param amInt a process state of the form ActivityManager.PROCESS_STATE_ -     * @return the value of the corresponding ActivityManager's ProcessState enum. +     * @return the value of the corresponding enums.proto ProcessStateEnum value.       * @hide       */      public static final int processStateAmToProto(int amInt) { -        return amInt * 100; +        switch (amInt) { +            case PROCESS_STATE_UNKNOWN: +                return AppProtoEnums.PROCESS_STATE_UNKNOWN; +            case PROCESS_STATE_PERSISTENT: +                return AppProtoEnums.PROCESS_STATE_PERSISTENT; +            case PROCESS_STATE_PERSISTENT_UI: +                return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI; +            case PROCESS_STATE_TOP: +                return AppProtoEnums.PROCESS_STATE_TOP; +            case PROCESS_STATE_FOREGROUND_SERVICE: +                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE; +            case PROCESS_STATE_BOUND_FOREGROUND_SERVICE: +                return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; +            case PROCESS_STATE_IMPORTANT_FOREGROUND: +                return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND; +            case PROCESS_STATE_IMPORTANT_BACKGROUND: +                return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND; +            case PROCESS_STATE_TRANSIENT_BACKGROUND: +                return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND; +            case PROCESS_STATE_BACKUP: +                return AppProtoEnums.PROCESS_STATE_BACKUP; +            case PROCESS_STATE_SERVICE: +                return AppProtoEnums.PROCESS_STATE_SERVICE; +            case PROCESS_STATE_RECEIVER: +                return AppProtoEnums.PROCESS_STATE_RECEIVER; +            case PROCESS_STATE_TOP_SLEEPING: +                return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING; +            case PROCESS_STATE_HEAVY_WEIGHT: +                return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT; +            case PROCESS_STATE_HOME: +                return AppProtoEnums.PROCESS_STATE_HOME; +            case PROCESS_STATE_LAST_ACTIVITY: +                return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY; +            case PROCESS_STATE_CACHED_ACTIVITY: +                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY; +            case PROCESS_STATE_CACHED_ACTIVITY_CLIENT: +                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; +            case PROCESS_STATE_CACHED_RECENT: +                return AppProtoEnums.PROCESS_STATE_CACHED_RECENT; +            case PROCESS_STATE_CACHED_EMPTY: +                return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY; +            case PROCESS_STATE_NONEXISTENT: +                return AppProtoEnums.PROCESS_STATE_NONEXISTENT; +            default: +                // ActivityManager process state (amInt) +                // could not be mapped to an AppProtoEnums ProcessState state. +                return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO; +        }      }      /** @hide The lowest process state number */ diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 939762ac4a30..6dcecf197ed2 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -147,6 +147,7 @@ interface IActivityManager {      void publishService(in IBinder token, in Intent intent, in IBinder service);      void activityResumed(in IBinder token);      void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent); +    void setAgentApp(in String packageName, @nullable String agent);      void setAlwaysFinish(boolean enabled);      boolean startInstrumentation(in ComponentName className, in String profileFile,              int flags, in Bundle arguments, in IInstrumentationWatcher watcher, diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java index 0ed1b0824946..6fbe9c6efb40 100644 --- a/core/java/android/app/ProfilerInfo.java +++ b/core/java/android/app/ProfilerInfo.java @@ -87,6 +87,15 @@ public class ProfilerInfo implements Parcelable {      }      /** +     * Return a new ProfilerInfo instance, with fields populated from this object, +     * and {@link agent} and {@link attachAgentDuringBind} as given. +     */ +    public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) { +        return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval, +                this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind); +    } + +    /**       * Close profileFd, if it is open. The field will be null after a call to this function.       */      public void closeFd() { diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index 2629929e91ce..5a1216b79b82 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -21,6 +21,7 @@ import android.os.Build;  import android.os.Bundle;  import android.os.IBinder;  import android.os.Process; +import android.os.RemoteException;  import android.os.Trace;  import android.util.Log; @@ -166,6 +167,12 @@ public abstract class AbstractThreadedSyncAdapter {      private class ISyncAdapterImpl extends ISyncAdapter.Stub {          @Override +        public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) +                throws RemoteException { +            cb.onUnsyncableAccountDone(AbstractThreadedSyncAdapter.this.onUnsyncableAccount()); +        } + +        @Override          public void startSync(ISyncContext syncContext, String authority, Account account,                  Bundle extras) {              if (ENABLE_LOG) { @@ -374,6 +381,26 @@ public abstract class AbstractThreadedSyncAdapter {      }      /** +     * Allows to defer syncing until all accounts are properly set up. +     * +     * <p>Called when a account / authority pair +     * <ul> +     * <li>that can be handled by this adapter</li> +     * <li>{@link ContentResolver#requestSync(SyncRequest) is synced}</li> +     * <li>and the account/provider {@link ContentResolver#getIsSyncable(Account, String) has +     * unknown state (<0)}.</li> +     * </ul> +     * +     * <p>This might be called on a different service connection as {@link #onPerformSync}. +     * +     * @return If {@code false} syncing is deferred. Returns {@code true} by default, i.e. by +     *         default syncing starts immediately. +     */ +    public boolean onUnsyncableAccount() { +        return true; +    } + +    /**       * Perform a sync for this account. SyncAdapter-specific parameters may       * be specified in extras, which is guaranteed to not be null. Invocations       * of this method are guaranteed to be serialized. diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl index 4660527925c5..0eb581e6b585 100644 --- a/core/java/android/content/ISyncAdapter.aidl +++ b/core/java/android/content/ISyncAdapter.aidl @@ -19,6 +19,7 @@ package android.content;  import android.accounts.Account;  import android.os.Bundle;  import android.content.ISyncContext; +import android.content.ISyncAdapterUnsyncableAccountCallback;  /**   * Interface used to control the sync activity on a SyncAdapter @@ -26,6 +27,14 @@ import android.content.ISyncContext;   */  oneway interface ISyncAdapter {      /** +     * Called before {@link #startSync}. This allows the adapter to defer syncs until the +     * adapter is ready for the account +     * +     * @param cb If called back with {@code false} accounts are not synced. +     */ +    void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb); + +    /**       * Initiate a sync for this account. SyncAdapter-specific parameters may       * be specified in extras, which is guaranteed to not be null.       * diff --git a/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl new file mode 100644 index 000000000000..a738ac2785c5 --- /dev/null +++ b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +/** + * Callback for {@link ISyncAdapter#onUnsyncableAccount} + * @hide + */ +oneway interface ISyncAdapterUnsyncableAccountCallback { +    /** +     * Deliver the result for {@link ISyncAdapter#onUnsyncableAccount} +     * +     * @param isReady Iff {@code false} account is not synced. +     */ +    void onUnsyncableAccountDone(boolean isReady); +} diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 1de8882e057a..fdea5a2f9351 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1246,7 +1246,7 @@ public final class InputManager {              int repeat;              if (effect instanceof VibrationEffect.OneShot) {                  VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect; -                pattern = new long[] { 0, oneShot.getTiming() }; +                pattern = new long[] { 0, oneShot.getDuration() };                  repeat = -1;              } else if (effect instanceof VibrationEffect.Waveform) {                  VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 7528bc3989c2..a817f33ce7ba 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -265,6 +265,10 @@ public class InputMethodService extends AbstractInputMethodService {       */      public static final int IME_VISIBLE = 0x2; +    // Min and max values for back disposition. +    private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT; +    private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_WILL_DISMISS; +      InputMethodManager mImm;      int mTheme = 0; @@ -501,9 +505,8 @@ public class InputMethodService extends AbstractInputMethodService {              }              clearInsetOfPreviousIme();              // If user uses hard keyboard, IME button should always be shown. -            boolean showing = isInputViewShown();              mImm.setImeWindowStatus(mToken, mStartInputToken, -                    IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); +                    mapToImeWindowStatus(isInputViewShown()), mBackDisposition);              if (resultReceiver != null) {                  resultReceiver.send(wasVis != isInputViewShown()                          ? InputMethodManager.RESULT_SHOWN @@ -1014,7 +1017,16 @@ public class InputMethodService extends AbstractInputMethodService {      }      public void setBackDisposition(int disposition) { +        if (disposition == mBackDisposition) { +            return; +        } +        if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) { +            Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified."); +            return; +        }          mBackDisposition = disposition; +        mImm.setImeWindowStatus(mToken, mStartInputToken, mapToImeWindowStatus(isInputViewShown()), +                mBackDisposition);      }      public int getBackDisposition() { @@ -1762,7 +1774,7 @@ public class InputMethodService extends AbstractInputMethodService {              startExtractingText(false);          } -        final int nextImeWindowStatus = IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0); +        final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());          if (previousImeWindowStatus != nextImeWindowStatus) {              mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus,                      mBackDisposition); @@ -1889,6 +1901,7 @@ public class InputMethodService extends AbstractInputMethodService {          mInputStarted = false;          mStartedInputConnection = null;          mCurCompletions = null; +        mBackDisposition = BACK_DISPOSITION_DEFAULT;      }      void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) { @@ -2104,7 +2117,11 @@ public class InputMethodService extends AbstractInputMethodService {       * them to perform navigation in the underlying application.       */      public boolean onKeyDown(int keyCode, KeyEvent event) { +          if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { +            if (mBackDisposition == BACK_DISPOSITION_WILL_NOT_DISMISS) { +                return false; +            }              final ExtractEditText eet = getExtractEditTextIfVisible();              if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {                  return true; @@ -2738,6 +2755,10 @@ public class InputMethodService extends AbstractInputMethodService {          mImm.exposeContent(mToken, inputContentInfo, getCurrentInputEditorInfo());      } +    private static int mapToImeWindowStatus(boolean isInputViewShown) { +        return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0); +    } +      /**       * Performs a dump of the InputMethodService's internal state.  Override       * to add your own information to the dump. diff --git a/core/java/android/net/metrics/NetworkMetrics.java b/core/java/android/net/metrics/NetworkMetrics.java index 2b662a0c28e2..2425bba9e668 100644 --- a/core/java/android/net/metrics/NetworkMetrics.java +++ b/core/java/android/net/metrics/NetworkMetrics.java @@ -96,6 +96,13 @@ public class NetworkMetrics {          }      } +    /** Accumulate a single netd sock_diag poll result reported by netd. */ +    public void addTcpStatsResult(int sent, int lost, int rttUs, int sentAckDiffMs) { +        pendingSummary.tcpLossRate.count(lost, sent); +        pendingSummary.roundTripTimeUs.count(rttUs); +        pendingSummary.sentAckTimeDiffenceMs.count(sentAckDiffMs); +    } +      /** Represents running sums for dns and connect average error counts and average latencies. */      public static class Summary { @@ -109,6 +116,13 @@ public class NetworkMetrics {          public final Metrics connectLatencies = new Metrics();          // Blocking and non blocking connect error rate measured in percentage points.          public final Metrics connectErrorRate = new Metrics(); +        // TCP socket packet loss stats collected from Netlink sock_diag. +        public final Metrics tcpLossRate = new Metrics(); +        // TCP averaged microsecond round-trip-time stats collected from Netlink sock_diag. +        public final Metrics roundTripTimeUs = new Metrics(); +        // TCP stats collected from Netlink sock_diag that averages millisecond per-socket +        // differences between last packet sent timestamp and last ack received timestamp. +        public final Metrics sentAckTimeDiffenceMs = new Metrics();          public Summary(int netId, long transports) {              this.netId = netId; @@ -120,6 +134,7 @@ public class NetworkMetrics {              dnsErrorRate.merge(that.dnsErrorRate);              connectLatencies.merge(that.connectLatencies);              connectErrorRate.merge(that.connectErrorRate); +            tcpLossRate.merge(that.tcpLossRate);          }          @Override @@ -135,6 +150,10 @@ public class NetworkMetrics {              j.add(String.format("connect avg=%dms max=%dms err=%.1f%% tot=%d",                      (int) connectLatencies.average(), (int) connectLatencies.max,                      100 * connectErrorRate.average(), connectErrorRate.count)); +            j.add(String.format("tcp avg_loss=%.1f%% total_sent=%d total_lost=%d", +                    100 * tcpLossRate.average(), tcpLossRate.count, (int) tcpLossRate.sum)); +            j.add(String.format("tcp rtt=%dms", (int) (roundTripTimeUs.average() / 1000))); +            j.add(String.format("tcp sent-ack_diff=%dms", (int) sentAckTimeDiffenceMs.average()));              return j.toString();          }      } @@ -152,7 +171,11 @@ public class NetworkMetrics {          }          void count(double value) { -            count++; +            count(value, 1); +        } + +        void count(double value, int subcount) { +            count += subcount;              sum += value;              max = Math.max(max, value);          } diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index da0ed54e003e..b6f16a7b9ff8 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -16,7 +16,9 @@  package android.os; +import android.hardware.vibrator.V1_0.Constants.EffectStrength;  import android.hardware.vibrator.V1_1.Constants.Effect_1_1; +import android.util.MathUtils;  import java.util.Arrays; @@ -36,6 +38,12 @@ public abstract class VibrationEffect implements Parcelable {      public static final int DEFAULT_AMPLITUDE = -1;      /** +     * The maximum amplitude value +     * @hide +     */ +    public static final int MAX_AMPLITUDE = 255; + +    /**       * A click effect.       *       * @see #get(int) @@ -198,38 +206,75 @@ public abstract class VibrationEffect implements Parcelable {      /** @hide */      public abstract void validate(); +    /** +     * Gets the estimated duration of the vibration in milliseconds. +     * +     * For effects without a defined end (e.g. a Waveform with a non-negative repeat index), this +     * returns Long.MAX_VALUE. For effects with an unknown duration (e.g. Prebaked effects where +     * the length is device and potentially run-time dependent), this returns -1. +     * +     * @hide +     */ +    public abstract long getDuration(); + +    /** +     * Scale the amplitude with the given constraints. +     * +     * This assumes that the previous value was in the range [0, MAX_AMPLITUDE] +     * @hide +     */ +    protected static int scale(int amplitude, float gamma, int maxAmplitude) { +        float val = MathUtils.pow(amplitude / (float) MAX_AMPLITUDE, gamma); +        return (int) (val * maxAmplitude); +    } +      /** @hide */      public static class OneShot extends VibrationEffect implements Parcelable { -        private long mTiming; -        private int mAmplitude; +        private final long mDuration; +        private final int mAmplitude;          public OneShot(Parcel in) { -            this(in.readLong(), in.readInt()); +            mDuration = in.readLong(); +            mAmplitude = in.readInt();          }          public OneShot(long milliseconds, int amplitude) { -            mTiming = milliseconds; +            mDuration = milliseconds;              mAmplitude = amplitude;          } -        public long getTiming() { -            return mTiming; +        @Override +        public long getDuration() { +            return mDuration;          }          public int getAmplitude() {              return mAmplitude;          } +        /** +         * Scale the amplitude of this effect. +         * +         * @param gamma the gamma adjustment to apply +         * @param maxAmplitude the new maximum amplitude of the effect +         * +         * @return A {@link OneShot} effect with the same timing but scaled amplitude. +         */ +        public VibrationEffect scale(float gamma, int maxAmplitude) { +            int newAmplitude = scale(mAmplitude, gamma, maxAmplitude); +            return new OneShot(mDuration, newAmplitude); +        } +          @Override          public void validate() {              if (mAmplitude < -1 || mAmplitude == 0 || mAmplitude > 255) {                  throw new IllegalArgumentException( -                        "amplitude must either be DEFAULT_AMPLITUDE, " + -                        "or between 1 and 255 inclusive (amplitude=" + mAmplitude + ")"); +                        "amplitude must either be DEFAULT_AMPLITUDE, " +                        + "or between 1 and 255 inclusive (amplitude=" + mAmplitude + ")");              } -            if (mTiming <= 0) { +            if (mDuration <= 0) {                  throw new IllegalArgumentException( -                        "timing must be positive (timing=" + mTiming + ")"); +                        "duration must be positive (duration=" + mDuration + ")");              }          } @@ -239,26 +284,26 @@ public abstract class VibrationEffect implements Parcelable {                  return false;              }              VibrationEffect.OneShot other = (VibrationEffect.OneShot) o; -            return other.mTiming == mTiming && other.mAmplitude == mAmplitude; +            return other.mDuration == mDuration && other.mAmplitude == mAmplitude;          }          @Override          public int hashCode() {              int result = 17; -            result = 37 * (int) mTiming; -            result = 37 * mAmplitude; +            result += 37 * (int) mDuration; +            result += 37 * mAmplitude;              return result;          }          @Override          public String toString() { -            return "OneShot{mTiming=" + mTiming +", mAmplitude=" + mAmplitude + "}"; +            return "OneShot{mDuration=" + mDuration + ", mAmplitude=" + mAmplitude + "}";          }          @Override          public void writeToParcel(Parcel out, int flags) {              out.writeInt(PARCEL_TOKEN_ONE_SHOT); -            out.writeLong(mTiming); +            out.writeLong(mDuration);              out.writeInt(mAmplitude);          } @@ -279,9 +324,9 @@ public abstract class VibrationEffect implements Parcelable {      /** @hide */      public static class Waveform extends VibrationEffect implements Parcelable { -        private long[] mTimings; -        private int[] mAmplitudes; -        private int mRepeat; +        private final long[] mTimings; +        private final int[] mAmplitudes; +        private final int mRepeat;          public Waveform(Parcel in) {              this(in.createLongArray(), in.createIntArray(), in.readInt()); @@ -308,34 +353,68 @@ public abstract class VibrationEffect implements Parcelable {          }          @Override +        public long getDuration() { +            if (mRepeat >= 0) { +                return Long.MAX_VALUE; +            } +            long duration = 0; +            for (long d : mTimings) { +                duration += d; +            } +            return duration; +        } + +        /** +         * Scale the Waveform with the given gamma and new max amplitude. +         * +         * @param gamma the gamma adjustment to apply +         * @param maxAmplitude the new maximum amplitude of the effect +         * +         * @return A {@link Waveform} effect with the same timings and repeat index +         *         but scaled amplitude. +         */ +        public VibrationEffect scale(float gamma, int maxAmplitude) { +            if (gamma == 1.0f && maxAmplitude == MAX_AMPLITUDE) { +                // Just return a copy of the original if there's no scaling to be done. +                return new Waveform(mTimings, mAmplitudes, mRepeat); +            } + +            int[] scaledAmplitudes = Arrays.copyOf(mAmplitudes, mAmplitudes.length); +            for (int i = 0; i < scaledAmplitudes.length; i++) { +                scaledAmplitudes[i] = scale(scaledAmplitudes[i], gamma, maxAmplitude); +            } +            return new Waveform(mTimings, scaledAmplitudes, mRepeat); +        } + +        @Override          public void validate() {              if (mTimings.length != mAmplitudes.length) {                  throw new IllegalArgumentException( -                        "timing and amplitude arrays must be of equal length" + -                        " (timings.length=" + mTimings.length + -                        ", amplitudes.length=" + mAmplitudes.length + ")"); +                        "timing and amplitude arrays must be of equal length" +                        + " (timings.length=" + mTimings.length +                        + ", amplitudes.length=" + mAmplitudes.length + ")");              }              if (!hasNonZeroEntry(mTimings)) { -                throw new IllegalArgumentException("at least one timing must be non-zero" + -                        " (timings=" + Arrays.toString(mTimings) + ")"); +                throw new IllegalArgumentException("at least one timing must be non-zero" +                        + " (timings=" + Arrays.toString(mTimings) + ")");              }              for (long timing : mTimings) {                  if (timing < 0) { -                    throw new IllegalArgumentException("timings must all be >= 0" + -                            " (timings=" + Arrays.toString(mTimings) + ")"); +                    throw new IllegalArgumentException("timings must all be >= 0" +                            + " (timings=" + Arrays.toString(mTimings) + ")");                  }              }              for (int amplitude : mAmplitudes) {                  if (amplitude < -1 || amplitude > 255) {                      throw new IllegalArgumentException( -                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255" + -                            " (amplitudes=" + Arrays.toString(mAmplitudes) + ")"); +                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255" +                            + " (amplitudes=" + Arrays.toString(mAmplitudes) + ")");                  }              }              if (mRepeat < -1 || mRepeat >= mTimings.length) {                  throw new IllegalArgumentException( -                        "repeat index must be within the bounds of the timings array" + -                        " (timings.length=" + mTimings.length + ", index=" + mRepeat +")"); +                        "repeat index must be within the bounds of the timings array" +                        + " (timings.length=" + mTimings.length + ", index=" + mRepeat + ")");              }          } @@ -345,26 +424,26 @@ public abstract class VibrationEffect implements Parcelable {                  return false;              }              VibrationEffect.Waveform other = (VibrationEffect.Waveform) o; -            return Arrays.equals(mTimings, other.mTimings) && -                Arrays.equals(mAmplitudes, other.mAmplitudes) && -                mRepeat == other.mRepeat; +            return Arrays.equals(mTimings, other.mTimings) +                && Arrays.equals(mAmplitudes, other.mAmplitudes) +                && mRepeat == other.mRepeat;          }          @Override          public int hashCode() {              int result = 17; -            result = 37 * Arrays.hashCode(mTimings); -            result = 37 * Arrays.hashCode(mAmplitudes); -            result = 37 * mRepeat; +            result += 37 * Arrays.hashCode(mTimings); +            result += 37 * Arrays.hashCode(mAmplitudes); +            result += 37 * mRepeat;              return result;          }          @Override          public String toString() { -            return "Waveform{mTimings=" + Arrays.toString(mTimings) + -                ", mAmplitudes=" + Arrays.toString(mAmplitudes) + -                ", mRepeat=" + mRepeat + -                "}"; +            return "Waveform{mTimings=" + Arrays.toString(mTimings) +                + ", mAmplitudes=" + Arrays.toString(mAmplitudes) +                + ", mRepeat=" + mRepeat +                + "}";          }          @Override @@ -402,16 +481,20 @@ public abstract class VibrationEffect implements Parcelable {      /** @hide */      public static class Prebaked extends VibrationEffect implements Parcelable { -        private int mEffectId; -        private boolean mFallback; +        private final int mEffectId; +        private final boolean mFallback; + +        private int mEffectStrength;          public Prebaked(Parcel in) {              this(in.readInt(), in.readByte() != 0); +            mEffectStrength = in.readInt();          }          public Prebaked(int effectId, boolean fallback) {              mEffectId = effectId;              mFallback = fallback; +            mEffectStrength = EffectStrength.MEDIUM;          }          public int getId() { @@ -427,6 +510,39 @@ public abstract class VibrationEffect implements Parcelable {          }          @Override +        public long getDuration() { +            return -1; +        } + +        /** +         * Set the effect strength of the prebaked effect. +         */ +        public void setEffectStrength(int strength) { +            if (!isValidEffectStrength(strength)) { +                throw new IllegalArgumentException("Invalid effect strength: " + strength); +            } +            mEffectStrength = strength; +        } + +        /** +         * Set the effect strength. +         */ +        public int getEffectStrength() { +            return mEffectStrength; +        } + +        private static boolean isValidEffectStrength(int strength) { +            switch (strength) { +                case EffectStrength.LIGHT: +                case EffectStrength.MEDIUM: +                case EffectStrength.STRONG: +                    return true; +                default: +                    return false; +            } +        } + +        @Override          public void validate() {              switch (mEffectId) {                  case EFFECT_CLICK: @@ -437,6 +553,10 @@ public abstract class VibrationEffect implements Parcelable {                      throw new IllegalArgumentException(                              "Unknown prebaked effect type (value=" + mEffectId + ")");              } +            if (!isValidEffectStrength(mEffectStrength)) { +                throw new IllegalArgumentException( +                        "Unknown prebaked effect strength (value=" + mEffectStrength + ")"); +            }          }          @Override @@ -445,17 +565,25 @@ public abstract class VibrationEffect implements Parcelable {                  return false;              }              VibrationEffect.Prebaked other = (VibrationEffect.Prebaked) o; -            return mEffectId == other.mEffectId && mFallback == other.mFallback; +            return mEffectId == other.mEffectId +                && mFallback == other.mFallback +                && mEffectStrength == other.mEffectStrength;          }          @Override          public int hashCode() { -            return mEffectId; +            int result = 17; +            result += 37 * mEffectId; +            result += 37 * mEffectStrength; +            return result;          }          @Override          public String toString() { -            return "Prebaked{mEffectId=" + mEffectId + ", mFallback=" + mFallback + "}"; +            return "Prebaked{mEffectId=" + mEffectId +                + ", mEffectStrength=" + mEffectStrength +                + ", mFallback=" + mFallback +                + "}";          } @@ -464,6 +592,7 @@ public abstract class VibrationEffect implements Parcelable {              out.writeInt(PARCEL_TOKEN_EFFECT);              out.writeInt(mEffectId);              out.writeByte((byte) (mFallback ? 1 : 0)); +            out.writeInt(mEffectStrength);          }          public static final Parcelable.Creator<Prebaked> CREATOR = diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index 8078fb87eb27..f1f6f414eba8 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -16,6 +16,7 @@  package android.os; +import android.annotation.IntDef;  import android.annotation.RequiresPermission;  import android.annotation.SystemService;  import android.app.ActivityThread; @@ -23,6 +24,9 @@ import android.content.Context;  import android.media.AudioAttributes;  import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +  /**   * Class that operates the vibrator on the device.   * <p> @@ -33,6 +37,40 @@ import android.util.Log;  public abstract class Vibrator {      private static final String TAG = "Vibrator"; +    /** +     * Vibration intensity: no vibrations. +     * @hide +     */ +    public static final int VIBRATION_INTENSITY_OFF = 0; + +    /** +     * Vibration intensity: low. +     * @hide +     */ +    public static final int VIBRATION_INTENSITY_LOW = 1; + +    /** +     * Vibration intensity: medium. +     * @hide +     */ +    public static final int VIBRATION_INTENSITY_MEDIUM = 2; + +    /** +     * Vibration intensity: high. +     * @hide +     */ +    public static final int VIBRATION_INTENSITY_HIGH = 3; + +    /** @hide */ +    @Retention(RetentionPolicy.SOURCE) +    @IntDef(prefix = { "VIBRATION_INTENSITY_" }, value = { +        VIBRATION_INTENSITY_OFF, +        VIBRATION_INTENSITY_LOW, +        VIBRATION_INTENSITY_MEDIUM, +        VIBRATION_INTENSITY_HIGH +    }) +    public @interface VibrationIntensity{} +      private final String mPackageName;      /** @@ -50,6 +88,22 @@ public abstract class Vibrator {      }      /** +     * Get the default vibration intensity for haptic feedback. +     * @hide +     */ +    public int getDefaultHapticFeedbackIntensity() { +        return VIBRATION_INTENSITY_MEDIUM; +    } + +    /** +     * Get the default vibration intensity for notifications and ringtones. +     * @hide +     */ +    public int getDefaultNotificationVibrationIntensity() { +        return VIBRATION_INTENSITY_HIGH; +    } + +    /**       * Check whether the hardware has a vibrator.       *       * @return True if the hardware has a vibrator, else false. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e957842dc262..26495cd22aff 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3175,6 +3175,43 @@ public final class Settings {          private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = BOOLEAN_VALIDATOR;          /** +         * The intensity of notification vibrations, if configurable. +         * +         * Not all devices are capable of changing their vibration intensity; on these devices +         * there will likely be no difference between the various vibration intensities except for +         * intensity 0 (off) and the rest. +         * +         * <b>Values:</b><br/> +         * 0 - Vibration is disabled<br/> +         * 1 - Weak vibrations<br/> +         * 2 - Medium vibrations<br/> +         * 3 - Strong vibrations +         * @hide +         */ +        public static final String NOTIFICATION_VIBRATION_INTENSITY = +                "notification_vibration_intensity"; + +        /** +         * The intensity of haptic feedback vibrations, if configurable. +         * +         * Not all devices are capable of changing their feedback intensity; on these devices +         * there will likely be no difference between the various vibration intensities except for +         * intensity 0 (off) and the rest. +         * +         * <b>Values:</b><br/> +         * 0 - Vibration is disabled<br/> +         * 1 - Weak vibrations<br/> +         * 2 - Medium vibrations<br/> +         * 3 - Strong vibrations +         * @hide +         */ +        public static final String HAPTIC_FEEDBACK_INTENSITY = +                "haptic_feedback_intensity"; + +        private static final Validator VIBRATION_INTENSITY_VALIDATOR = +                new SettingsValidators.InclusiveIntegerRangeValidator(0, 3); + +        /**           * Ringer volume. This is used internally, changing this value will not           * change the volume. See AudioManager.           * @@ -3995,7 +4032,9 @@ public final class Settings {              LOCK_TO_APP_ENABLED,              NOTIFICATION_SOUND,              ACCELEROMETER_ROTATION, -            SHOW_BATTERY_PERCENT +            SHOW_BATTERY_PERCENT, +            NOTIFICATION_VIBRATION_INTENSITY, +            HAPTIC_FEEDBACK_INTENSITY,          };          /** @@ -4136,6 +4175,8 @@ public final class Settings {              VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);              VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);              VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR); +            VALIDATORS.put(NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); +            VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);              VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);              VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);              VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR); diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java new file mode 100644 index 000000000000..f79d852ddefc --- /dev/null +++ b/core/java/android/provider/SettingsSlicesContract.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.provider; + +import android.content.ContentResolver; +import android.net.Uri; + +/** + * Provides a contract for platform-supported Settings {@link android.app.slice.Slice Slices}. + * <p> + * Contains definitions for the supported {@link android.app.slice.SliceProvider SliceProvider} + * authority, authority {@link Uri}, and key constants. + * <p> + * {@link android.app.slice.Slice Slice} presenters interested in learning meta-data about the + * {@link android.app.slice.Slice Slice} should read the {@link android.app.slice.Slice Slice} + * object at runtime. + * <p> + * {@link Uri} builder example: + * <pre> + * Uri wifiActionUri = AUTHORITY_URI + *         .buildUpon() + *         .appendPath(PATH_SETTING_ACTION) + *         .appendPath(KEY_WIFI) + *         .build(); + * Uri bluetoothIntentUri = AUTHORITY_URI + *         .buildUpon() + *         .appendPath(PATH_SETTING_INTENT) + *         .appendPath(KEY_BLUETOOTH) + *         .build(); + * </pre> + */ +public class SettingsSlicesContract { +    private SettingsSlicesContract() { +    } + +    /** +     * Authority for platform Settings Slices. +     */ +    public static final String AUTHORITY = "android.settings.slices"; + +    /** +     * A content:// style uri to the Settings Slices authority, {@link #AUTHORITY}. +     */ +    public static final Uri BASE_URI = new Uri.Builder() +            .scheme(ContentResolver.SCHEME_CONTENT) +            .authority(AUTHORITY) +            .build(); + +    /** +     * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should +     * have inline controls for the corresponding setting. +     * <p> +     * This path will only contain Slices defined by keys in this class. +     */ +    public static final String PATH_SETTING_ACTION = "action"; + +    /** +     * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should +     * be {@link android.content.Intent Intent}-only. +     * <p> +     * {@link android.app.slice.Slice Slices} with actions should use the {@link +     * #PATH_SETTING_ACTION} path. +     * <p> +     * This path will only contain Slices defined by keys in this class +     */ +    public static final String PATH_SETTING_INTENT = "intent"; + +    /** +     * {@link Uri} key for the Airplane Mode setting. +     */ +    public static final String KEY_AIRPLANE_MODE = "airplane_mode"; + +    /** +     * {@link Uri} key for the Battery Saver setting. +     */ +    public static final String KEY_BATTERY_SAVER = "battery_saver"; + +    /** +     * {@link Uri} key for the Bluetooth setting. +     */ +    public static final String KEY_BLUETOOTH = "bluetooth"; + +    /** +     * {@link Uri} key for the Location setting. +     */ +    public static final String KEY_LOCATION = "location"; + +    /** +     * {@link Uri} key for the Wi-fi setting. +     */ +    public static final String KEY_WIFI = "wifi"; +} diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java index 5d091c91abfb..b0e9f0194ed4 100644 --- a/core/java/android/webkit/WebViewProviderInfo.java +++ b/core/java/android/webkit/WebViewProviderInfo.java @@ -17,10 +17,10 @@  package android.webkit;  import android.annotation.SystemApi; +import android.content.pm.Signature;  import android.os.Parcel;  import android.os.Parcelable; - -import java.util.Arrays; +import android.util.Base64;  /**   * @hide @@ -34,7 +34,14 @@ public final class WebViewProviderInfo implements Parcelable {          this.description = description;          this.availableByDefault = availableByDefault;          this.isFallback = isFallback; -        this.signatures = signatures; +        if (signatures == null) { +            this.signatures = new Signature[0]; +        } else { +            this.signatures = new Signature[signatures.length]; +            for (int n = 0; n < signatures.length; n++) { +                this.signatures[n] = new Signature(Base64.decode(signatures[n], Base64.DEFAULT)); +            } +        }      }      // aidl stuff @@ -54,7 +61,7 @@ public final class WebViewProviderInfo implements Parcelable {          description = in.readString();          availableByDefault = (in.readInt() > 0);          isFallback = (in.readInt() > 0); -        signatures = in.createStringArray(); +        signatures = in.createTypedArray(Signature.CREATOR);      }      @Override @@ -68,7 +75,7 @@ public final class WebViewProviderInfo implements Parcelable {          out.writeString(description);          out.writeInt(availableByDefault ? 1 : 0);          out.writeInt(isFallback ? 1 : 0); -        out.writeStringArray(signatures); +        out.writeTypedArray(signatures, 0);      }      // fields read from framework resource @@ -76,5 +83,5 @@ public final class WebViewProviderInfo implements Parcelable {      public final String description;      public final boolean availableByDefault;      public final boolean isFallback; -    public final String[] signatures; +    public final Signature[] signatures;  } diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java index 8650c0a0521c..7f0c086ff8e9 100644 --- a/core/java/android/widget/VideoView2.java +++ b/core/java/android/widget/VideoView2.java @@ -23,6 +23,7 @@ import android.content.Context;  import android.media.AudioAttributes;  import android.media.AudioManager;  import android.media.MediaPlayerBase; +import android.media.session.MediaController;  import android.media.update.ApiLoader;  import android.media.update.VideoView2Provider;  import android.media.update.ViewProvider; @@ -76,8 +77,8 @@ import java.util.Map;   * If a developer wants to attach a customed MediaControlView2, then set enableControlView attribute   * to false and assign the customed media control widget using {@link #setMediaControlView2}.   * <li> VideoView2 is integrated with MediaPlayer2 while VideoView is integrated with MediaPlayer. - * <li> VideoView2 is integrated with MediaSession2 and so it responses with media key events. - * A VideoView2 keeps a MediaSession2 instance internally and connects it to a corresponding + * <li> VideoView2 is integrated with MediaSession and so it responses with media key events. + * A VideoView2 keeps a MediaSession instance internally and connects it to a corresponding   * MediaControlView2 instance.   * </p>   * </ul> @@ -159,60 +160,18 @@ public class VideoView2 extends FrameLayout {          return mProvider.getMediaControlView2_impl();      } -    /** -     * Starts playback with the media contents specified by {@link #setVideoURI} and -     * {@link #setVideoPath}. -     * If it has been paused, this method will resume playback from the current position. -     */ -    public void start() { -        mProvider.start_impl(); -    }      /** -     * Pauses playback. -     */ -    public void pause() { -        mProvider.pause_impl(); -    } - -    /** -     * Gets the duration of the media content specified by #setVideoURI and #setVideoPath -     * in milliseconds. -     */ -    public int getDuration() { -        return mProvider.getDuration_impl(); -    } - -    /** -     * Gets current playback position in milliseconds. -     */ -    public int getCurrentPosition() { -        return mProvider.getCurrentPosition_impl(); -    } - -    // TODO: mention about key-frame related behavior. -    /** -     * Moves the media by specified time position. -     * @param msec the offset in milliseconds from the start to seek to. -     */ -    public void seekTo(int msec) { -        mProvider.seekTo_impl(msec); -    } - -    /** -     * Says if the media is currently playing. -     * @return true if the media is playing, false if it is not (eg. paused or stopped). -     */ -    public boolean isPlaying() { -        return mProvider.isPlaying_impl(); -    } - -    // TODO: check what will return if it is a local media. -    /** -     * Gets the percentage (0-100) of the content that has been buffered or played so far. +     * Returns MediaController instance which is connected with MediaSession that VideoView2 is +     * using. This method should be called when VideoView2 is attached to window, or it throws +     * IllegalStateException, since internal MediaSession instance is not available until +     * this view is attached to window. Please check {@link android.view.View#isAttachedToWindow} +     * before calling this method. +     * +     * @throws IllegalStateException if interal MediaSession is not created yet.       */ -    public int getBufferPercentage() { -        return mProvider.getBufferPercentage_impl(); +    public MediaController getMediaController() { +        return mProvider.getMediaController_impl();      }      /** @@ -244,7 +203,6 @@ public class VideoView2 extends FrameLayout {          mProvider.setFullScreen_impl(fullScreen);      } -    // TODO: This should be revised after integration with MediaPlayer2.      /**       * Sets playback speed.       * @@ -254,21 +212,12 @@ public class VideoView2 extends FrameLayout {       * be reset to the normal speed 1.0f.       * @param speed the playback speed. It should be positive.       */ +    // TODO: Support this via MediaController2.      public void setSpeed(float speed) {          mProvider.setSpeed_impl(speed);      }      /** -     * Returns current speed setting. -     * -     * If setSpeed() has never been called, returns the default value 1.0f. -     * @return current speed setting -     */ -    public float getSpeed() { -        return mProvider.getSpeed_impl(); -    } - -    /**       * Sets which type of audio focus will be requested during the playback, or configures playback       * to not request audio focus. Valid values for focus requests are       * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT}, @@ -367,14 +316,6 @@ public class VideoView2 extends FrameLayout {      }      /** -     * Stops playback and release all the resources. This should be called whenever a VideoView2 -     * instance is no longer to be used. -     */ -    public void stopPlayback() { -        mProvider.stopPlayback_impl(); -    } - -    /**       * Registers a callback to be invoked when the media file is loaded and ready to go.       *       * @param l the callback that will be run. diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto index 03f820435151..4756c13d71db 100644 --- a/core/proto/android/app/activitymanager.proto +++ b/core/proto/android/app/activitymanager.proto @@ -21,65 +21,6 @@ package android.app;  option java_multiple_files = true;  option java_outer_classname = "ActivityManagerProto"; -// ActivityManager.java PROCESS_STATEs -enum ProcessState { -  // Order matters for process states, so values have been spaced to provide -  // room for future additions. - -  // Not a real process state. -  PROCESS_STATE_UNKNOWN = -100; -  // Process is a persistent system process. -  PROCESS_STATE_PERSISTENT = 0; -  // Process is a persistent system process and is doing UI. -  PROCESS_STATE_PERSISTENT_UI = 100; -  // Process is hosting the current top activities. Note that this covers -  // all activities that are visible to the user. -  PROCESS_STATE_TOP = 200; -  // Process is hosting a foreground service due to a system binding. -  PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 300; -  // Process is hosting a foreground service. -  PROCESS_STATE_FOREGROUND_SERVICE = 400; -  // Process is important to the user, and something they are aware of. -  PROCESS_STATE_IMPORTANT_FOREGROUND = 500; -  // Process is important to the user, but not something they are aware of. -  PROCESS_STATE_IMPORTANT_BACKGROUND = 600; -  // Process is in the background transient so we will try to keep running. -  PROCESS_STATE_TRANSIENT_BACKGROUND = 700; -  // Process is in the background running a backup/restore operation. -  PROCESS_STATE_BACKUP = 800; -  // Process is in the background running a service. Unlike oom_adj, this -  // level is used for both the normal running in background state and the -  // executing operations state. -  PROCESS_STATE_SERVICE = 900; -  // Process is in the background running a receiver. Note that from the -  // perspective of oom_adj, receivers run at a higher foreground level, but -  // for our prioritization here that is not necessary and putting them -  // below services means many fewer changes in some process states as they -  // receive broadcasts. -  PROCESS_STATE_RECEIVER = 1000; -  // Same as PROCESS_STATE_TOP but while device is sleeping. -  PROCESS_STATE_TOP_SLEEPING = 1100; -  // Process is in the background, but it can't restore its state so we want -  // to try to avoid killing it. -  PROCESS_STATE_HEAVY_WEIGHT = 1200; -  // Process is in the background but hosts the home activity. -  PROCESS_STATE_HOME = 1300; -  // Process is in the background but hosts the last shown activity. -  PROCESS_STATE_LAST_ACTIVITY = 1400; -  // Process is being cached for later use and contains activities. -  PROCESS_STATE_CACHED_ACTIVITY = 1500; -  // Process is being cached for later use and is a client of another cached -  // process that contains activities. -  PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1600; -  // Process is being cached for later use and has an activity that corresponds -  // to an existing recent task. -  PROCESS_STATE_CACHED_RECENT = 1700; -  // Process is being cached for later use and is empty. -  PROCESS_STATE_CACHED_EMPTY = 1800; -  // Process does not exist. -  PROCESS_STATE_NONEXISTENT = 1900; -} -  // ActivityManager.java UID_OBSERVERs flags  enum UidObserverFlag {    // report changes in process state, original value is 1 << 0 diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto new file mode 100644 index 000000000000..2de2574ad401 --- /dev/null +++ b/core/proto/android/app/enums.proto @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017 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. + */ + +syntax = "proto2"; + +package android.app; + +option java_outer_classname = "AppProtoEnums"; +option java_multiple_files = true; + +// ActivityManager.java PROCESS_STATEs +enum ProcessStateEnum { +    // Unlike the ActivityManager PROCESS_STATE values, the ordering and numerical values +    // here are completely fixed and arbitrary. Order is irrelevant. +    // No attempt need be made to keep them in sync. +    // The values here must not be modified. Any new process states can be appended to the end. + +    // Process state that is unknown to this proto file (i.e. is not mapped +    // by ActivityManager.processStateAmToProto()). Can only happen if there's a bug in the mapping. +    PROCESS_STATE_UNKNOWN_TO_PROTO = 998; +    // Not a real process state. +    PROCESS_STATE_UNKNOWN = 999; +    // Process is a persistent system process. +    PROCESS_STATE_PERSISTENT = 1000; +    // Process is a persistent system process and is doing UI. +    PROCESS_STATE_PERSISTENT_UI = 1001; +    // Process is hosting the current top activities. Note that this covers +    // all activities that are visible to the user. +    PROCESS_STATE_TOP = 1002; +    // Process is hosting a foreground service. +    PROCESS_STATE_FOREGROUND_SERVICE = 1003; +    // Process is hosting a foreground service due to a system binding. +    PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 1004; +    // Process is important to the user, and something they are aware of. +    PROCESS_STATE_IMPORTANT_FOREGROUND = 1005; +    // Process is important to the user, but not something they are aware of. +    PROCESS_STATE_IMPORTANT_BACKGROUND = 1006; +    // Process is in the background transient so we will try to keep running. +    PROCESS_STATE_TRANSIENT_BACKGROUND = 1007; +    // Process is in the background running a backup/restore operation. +    PROCESS_STATE_BACKUP = 1008; +    // Process is in the background running a service. Unlike oom_adj, this +    // level is used for both the normal running in background state and the +    // executing operations state. +    PROCESS_STATE_SERVICE = 1009; +    // Process is in the background running a receiver. Note that from the +    // perspective of oom_adj, receivers run at a higher foreground level, but +    // for our prioritization here that is not necessary and putting them +    // below services means many fewer changes in some process states as they +    // receive broadcasts. +    PROCESS_STATE_RECEIVER = 1010; +    // Same as PROCESS_STATE_TOP but while device is sleeping. +    PROCESS_STATE_TOP_SLEEPING = 1011; +    // Process is in the background, but it can't restore its state so we want +    // to try to avoid killing it. +    PROCESS_STATE_HEAVY_WEIGHT = 1012; +    // Process is in the background but hosts the home activity. +    PROCESS_STATE_HOME = 1013; +    // Process is in the background but hosts the last shown activity. +    PROCESS_STATE_LAST_ACTIVITY = 1014; +    // Process is being cached for later use and contains activities. +    PROCESS_STATE_CACHED_ACTIVITY = 1015; +    // Process is being cached for later use and is a client of another cached +    // process that contains activities. +    PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1016; +    // Process is being cached for later use and has an activity that corresponds +    // to an existing recent task. +    PROCESS_STATE_CACHED_RECENT = 1017; +    // Process is being cached for later use and is empty. +    PROCESS_STATE_CACHED_EMPTY = 1018; +    // Process does not exist. +    PROCESS_STATE_NONEXISTENT = 1019; +} + diff --git a/core/proto/android/content/clipdata.proto b/core/proto/android/content/clipdata.proto index 6967b69352bd..aeeef977d401 100644 --- a/core/proto/android/content/clipdata.proto +++ b/core/proto/android/content/clipdata.proto @@ -21,13 +21,18 @@ option java_multiple_files = true;  import "frameworks/base/core/proto/android/content/clipdescription.proto";  import "frameworks/base/core/proto/android/content/intent.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto";  // An android.content.ClipData object.  message ClipDataProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      optional android.content.ClipDescriptionProto description = 1;      // Custom dump of an android.graphics.Bitmap object.      message Icon { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional int32 width = 1;          optional int32 height = 2;      } @@ -35,6 +40,8 @@ message ClipDataProto {      // An android.content.ClipData.Item object.      message Item { +        option (.android.msg_privacy).dest = DEST_EXPLICIT; +          oneof data {              string html_text = 1;              string text = 2; diff --git a/core/proto/android/content/clipdescription.proto b/core/proto/android/content/clipdescription.proto index 40f4ad3ed724..bc0e9407faf8 100644 --- a/core/proto/android/content/clipdescription.proto +++ b/core/proto/android/content/clipdescription.proto @@ -20,11 +20,14 @@ package android.content;  option java_multiple_files = true;  import "frameworks/base/core/proto/android/os/persistablebundle.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto";  // An android.content.ClipDescription object.  message ClipDescriptionProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      repeated string mime_types = 1; -    optional string label = 2; +    optional string label = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];      optional android.os.PersistableBundleProto extras = 3;      optional int64 timestamp_ms = 4;  } diff --git a/core/proto/android/content/component_name.proto b/core/proto/android/content/component_name.proto index fc0c8c55c2b1..4e49cf2bfcd5 100644 --- a/core/proto/android/content/component_name.proto +++ b/core/proto/android/content/component_name.proto @@ -20,10 +20,14 @@ option java_multiple_files = true;  package android.content; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; +  /**   * An android.content.ComponentName object.   */  message ComponentNameProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      optional string package_name = 1;      optional string class_name = 2;  } diff --git a/core/proto/android/net/network.proto b/core/proto/android/net/network.proto index 9c7ea5da8c84..e13ca9f682eb 100644 --- a/core/proto/android/net/network.proto +++ b/core/proto/android/net/network.proto @@ -19,9 +19,14 @@ option java_multiple_files = true;  package android.net; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; +  /**   * An android.net.Network object.   */  message NetworkProto { -    optional int32 net_id = 1; +    // The netId is an implementation detail which might be changed in the +    // future, or which alone (i.e. in the absence of some additional context) +    // might not be sufficient to fully identify a Network. +    optional int32 net_id = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ];  } diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto index e1c2af191f71..0338bf8f37b6 100644 --- a/core/proto/android/net/networkcapabilities.proto +++ b/core/proto/android/net/networkcapabilities.proto @@ -20,10 +20,14 @@ package android.net;  option java_multiple_files = true; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; +  /**   * An android.net.NetworkCapabilities object.   */  message NetworkCapabilitiesProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      enum Transport {          // Indicates this network uses a Cellular transport.          TRANSPORT_CELLULAR = 0; @@ -118,7 +122,7 @@ message NetworkCapabilitiesProto {      optional int32 link_up_bandwidth_kbps = 3;      optional int32 link_down_bandwidth_kbps = 4; -    optional string network_specifier = 5; +    optional string network_specifier = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];      // True if this object specifies a signal strength.      optional bool can_report_signal_strength = 6; diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto index 9884464c5a3a..d260b13a29eb 100644 --- a/core/proto/android/net/networkrequest.proto +++ b/core/proto/android/net/networkrequest.proto @@ -21,11 +21,14 @@ package android.net;  option java_multiple_files = true;  import "frameworks/base/core/proto/android/net/networkcapabilities.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto";  /**   * An android.net.NetworkRequest object.   */  message NetworkRequestProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      enum Type {          TYPE_UNKNOWN = 0;          // Only used by applications. When an application creates a diff --git a/core/proto/android/os/bundle.proto b/core/proto/android/os/bundle.proto index 69902816ae7d..5556936c3c78 100644 --- a/core/proto/android/os/bundle.proto +++ b/core/proto/android/os/bundle.proto @@ -19,10 +19,14 @@ package android.os;  option java_multiple_files = true; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; +  // An android.os.Bundle object.  message BundleProto {      oneof data { -        int32 parcelled_data_size = 1; -        string map_data = 2; +        int32 parcelled_data_size = 1 [ +            (.android.privacy).dest = DEST_AUTOMATIC +        ]; +        string map_data = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];      }  } diff --git a/core/proto/android/os/persistablebundle.proto b/core/proto/android/os/persistablebundle.proto index 75ff78718cbc..712f87c9b147 100644 --- a/core/proto/android/os/persistablebundle.proto +++ b/core/proto/android/os/persistablebundle.proto @@ -19,10 +19,14 @@ package android.os;  option java_multiple_files = true; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; +  // An android.os.PersistableBundle object.  message PersistableBundleProto {      oneof data { -        int32 parcelled_data_size = 1; -        string map_data = 2; +        int32 parcelled_data_size = 1 [ +            (.android.privacy).dest = DEST_AUTOMATIC +        ]; +        string map_data = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];      }  } diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 39c5ec713c13..55e6a74804ee 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -19,6 +19,7 @@ syntax = "proto2";  package com.android.server.am.proto;  import "frameworks/base/core/proto/android/app/activitymanager.proto"; +import "frameworks/base/core/proto/android/app/enums.proto";  import "frameworks/base/core/proto/android/app/notification.proto";  import "frameworks/base/core/proto/android/app/profilerinfo.proto";  import "frameworks/base/core/proto/android/content/component_name.proto"; @@ -797,7 +798,7 @@ message UidRecordProto {    optional string hex_hash = 1;    optional int32 uid = 2; -  optional .android.app.ProcessState current = 3; +  optional .android.app.ProcessStateEnum current = 3;    optional bool ephemeral = 4;    optional bool fg_services = 5;    optional bool whilelist = 6; @@ -855,7 +856,7 @@ message ProcessOomProto {      bool services = 6;    } -  optional .android.app.ProcessState state = 7; +  optional .android.app.ProcessStateEnum state = 7;    optional int32 trim_memory_level = 8;    optional ProcessRecordProto proc = 9;    optional string adj_type = 10; @@ -878,8 +879,8 @@ message ProcessOomProto {      optional int32 set_raw_adj = 3;      optional int32 cur_adj = 4;      optional int32 set_adj = 5; -    optional .android.app.ProcessState current_state = 7; -    optional .android.app.ProcessState set_state = 8; +    optional .android.app.ProcessStateEnum current_state = 7; +    optional .android.app.ProcessStateEnum set_state = 8;      optional string last_pss = 9;      optional string last_swap_pss = 10;      optional string last_cached_pss = 11; diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto index c9f7d52ae83f..5657f9668578 100644 --- a/core/proto/android/server/forceappstandbytracker.proto +++ b/core/proto/android/server/forceappstandbytracker.proto @@ -20,8 +20,12 @@ package com.android.server;  option java_multiple_files = true; -// Dump from ForceAppStandbyTracker. +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + +// Dump from com.android.server.ForceAppStandbyTracker.  message ForceAppStandbyTrackerProto { +  option (.android.msg_privacy).dest = DEST_AUTOMATIC; +    // Whether all apps are forced standby or not.    optional bool force_all_apps_standby = 1; @@ -35,10 +39,11 @@ message ForceAppStandbyTrackerProto {    repeated int32 temp_power_save_whitelist_app_ids = 4;    message RunAnyInBackgroundRestrictedPackages { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      optional int32 uid = 1;      optional string package_name = 2;    } -    // Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.    repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5; diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 739fca3ceb1d..304e63f28151 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -29,13 +29,18 @@ import "frameworks/base/core/proto/android/net/networkrequest.proto";  import "frameworks/base/core/proto/android/os/bundle.proto";  import "frameworks/base/core/proto/android/os/persistablebundle.proto";  import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto";  message JobSchedulerServiceDumpProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      optional ConstantsProto settings = 1;      repeated int32 started_users = 2;      message RegisteredJob { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional JobStatusShortInfoProto info = 1;          optional JobStatusDumpProto dump = 2; @@ -56,6 +61,8 @@ message JobSchedulerServiceDumpProto {      // Which uids are currently in the foreground.      message PriorityOverride { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional int32 uid = 1;          // Use sint32 instead of an enum since priorities can technically be          // negative. @@ -71,6 +78,8 @@ message JobSchedulerServiceDumpProto {      optional JobPackageTrackerDumpProto package_tracker = 8;      message PendingJob { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional JobStatusShortInfoProto info = 1;          optional JobStatusDumpProto dump = 2;          optional sint32 evaluated_priority = 3; @@ -81,12 +90,18 @@ message JobSchedulerServiceDumpProto {      // From a service that has currently active or pending jobs.      message ActiveJob { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          message InactiveJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional int64 time_since_stopped_ms = 1;              // This is not always provided.              optional string stopped_reason = 2;          }          message RunningJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              // How long this job has been running for.              optional int64 running_duration_ms = 2; @@ -119,6 +134,8 @@ message JobSchedulerServiceDumpProto {  // A com.android.server.job.JobSchedulerService.Constants object.  message ConstantsProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      // Minimum # of idle jobs that must be ready in order to force the JMS to      // schedule things early.      optional int32 min_idle_count = 1; @@ -187,10 +204,16 @@ message ConstantsProto {  }  message StateControllerProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      message AppIdleController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional bool is_parole_on = 1;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;              optional string source_package_name = 3; @@ -201,9 +224,13 @@ message StateControllerProto {          repeated TrackedJob tracked_jobs = 2;      }      message BackgroundJobsController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional com.android.server.ForceAppStandbyTrackerProto force_app_standby_tracker = 1;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;              optional string source_package_name = 3; @@ -217,6 +244,8 @@ message StateControllerProto {          repeated TrackedJob tracked_jobs = 2;      }      message BatteryController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional bool is_on_stable_power = 1;          optional bool is_battery_not_low = 2; @@ -226,15 +255,21 @@ message StateControllerProto {          optional int32 last_broadcast_sequence_number = 4;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;          }          repeated TrackedJob tracked_jobs = 5;      }      message ConnectivityController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional bool is_connected = 1;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;              optional .android.net.NetworkRequestProto required_network = 3; @@ -242,31 +277,47 @@ message StateControllerProto {          repeated TrackedJob tracked_jobs = 2;      }      message ContentObserverController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;          }          repeated TrackedJob tracked_jobs = 1;          message Observer { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional int32 user_id = 1;              message TriggerContentData { -                optional string uri = 1; +                option (.android.msg_privacy).dest = DEST_AUTOMATIC; + +                optional string uri = 1 [ +                    (.android.privacy).dest = DEST_EXPLICIT +                ];                  optional int32 flags = 2;                  // A                  // com.android.server.job.controllers.ContentObserverController.JobInstance                  // object.                  message JobInstance { +                    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +                      optional JobStatusShortInfoProto info = 1;                      optional int32 source_uid = 2;                      optional int64 trigger_content_update_delay_ms = 3;                      optional int64 trigger_content_max_delay_ms = 4; -                    repeated string changed_authorities = 5; -                    repeated string changed_uris = 6; +                    repeated string changed_authorities = 5 [ +                        (.android.privacy).dest = DEST_EXPLICIT +                    ]; +                    repeated string changed_uris = 6 [ +                        (.android.privacy).dest = DEST_EXPLICIT +                    ];                  }                  repeated JobInstance jobs = 3;              } @@ -275,10 +326,14 @@ message StateControllerProto {          repeated Observer observers = 2;      }      message DeviceIdleJobsController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          // True when in device idle mode.          optional bool is_device_idle_mode = 1;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;              optional string source_package_name = 3; @@ -293,30 +348,42 @@ message StateControllerProto {          repeated TrackedJob tracked_jobs = 2;      }      message IdleController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional bool is_idle = 1;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;          }          repeated TrackedJob tracked_jobs = 2;      }      message StorageController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional bool is_storage_not_low = 1;          optional int32 last_broadcast_sequence_number = 2;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2;          }          repeated TrackedJob tracked_jobs = 3;      }      message TimeController { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional int64 now_elapsed_realtime = 1;          optional int64 time_until_next_delay_alarm_ms = 2;          optional int64 time_until_next_deadline_alarm_ms = 3;          message TrackedJob { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional JobStatusShortInfoProto info = 1;              optional int32 source_uid = 2; @@ -347,6 +414,8 @@ message StateControllerProto {  // A com.android.server.job.JobPackageTracker.DataSet object.  message DataSetProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      optional int64 start_clock_time_ms = 1;      // How much time has elapsed since the DataSet was instantiated.      optional int64 elapsed_time_ms = 2; @@ -355,10 +424,14 @@ message DataSetProto {      // Represents a com.android.server.job.JobPackageTracker.PackageEntry      // object, but with some extra data.      message PackageEntryProto { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional int32 uid = 1;          optional string package_name = 2;          message State { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional int64 duration_ms = 1;              optional int32 count = 2;          } @@ -377,6 +450,8 @@ message DataSetProto {          optional bool active_top = 8;          message StopReasonCount { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              optional .android.app.JobParametersProto.CancelReason reason = 1;              optional int32 count = 2;          } @@ -390,19 +465,27 @@ message DataSetProto {  // Dump from com.android.server.job.GrantedUriPermissions.  message GrantedUriPermissionsDumpProto { -    optional int32 flags = 1; -    optional int32 source_user_id = 2; +    option (.android.msg_privacy).dest = DEST_EXPLICIT; + +    optional int32 flags = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ]; +    optional int32 source_user_id = 2 [ +        (.android.privacy).dest = DEST_AUTOMATIC +    ];      optional string tag = 3;      optional string permission_owner = 4;      repeated string uris = 5;  }  message JobPackageTrackerDumpProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      repeated DataSetProto historical_stats = 1;      optional DataSetProto current_stats = 2;  }  message JobPackageHistoryProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      enum Event {          UNKNOWN = 0;          START_JOB = 1; @@ -411,12 +494,14 @@ message JobPackageHistoryProto {          STOP_PERIODIC_JOB = 4;      }      message HistoryEvent { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional Event event = 1;          optional int64 time_since_event_ms = 2;          optional int32 uid = 3;          // Job IDs can technically be negative.          optional int32 job_id = 4; -        optional string tag = 5; +        optional string tag = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];          // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events.          optional .android.app.JobParametersProto.CancelReason stop_reason = 6;      } @@ -424,17 +509,23 @@ message JobPackageHistoryProto {  }  message JobStatusShortInfoProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      optional int32 calling_uid = 1;      // Job IDs can technically be negative.      optional int32 job_id = 2; -    optional string battery_name = 3; +    optional string battery_name = 3 [ +        (.android.privacy).dest = DEST_EXPLICIT +    ];  }  // Dump from a com.android.server.job.controllers.JobStatus object.  message JobStatusDumpProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; +      // The UID that scheduled the job.      optional int32 calling_uid = 1; -    optional string tag = 2; +    optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];      // The UID for which the job is being run.      optional int32 source_uid = 3; @@ -444,6 +535,8 @@ message JobStatusDumpProto {      // Custom dump of android.app.job.JobInfo object.      message JobInfo { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional .android.content.ComponentNameProto service = 1;          optional bool is_periodic = 2; @@ -461,8 +554,10 @@ message JobStatusDumpProto {          optional bool requires_device_idle = 10;          message TriggerContentUri { -            optional int32 flags = 1; -            optional string uri = 2; +            optional int32 flags = 1 [ +                (.android.privacy).dest = DEST_AUTOMATIC +            ]; +            optional string uri = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];          }          repeated TriggerContentUri trigger_content_uris = 11;          optional int64 trigger_content_update_delay_ms = 12; @@ -482,6 +577,8 @@ message JobStatusDumpProto {          optional int64 max_execution_delay_ms = 21;          message Backoff { +            option (.android.msg_privacy).dest = DEST_AUTOMATIC; +              enum Policy {                  BACKOFF_POLICY_LINEAR = 0;                  BACKOFF_POLICY_EXPONENTIAL = 1; @@ -524,13 +621,19 @@ message JobStatusDumpProto {      // Controllers that are currently tracking the job.      repeated TrackingController tracking_controllers = 11; -    repeated string changed_authorities = 12; -    repeated string changed_uris = 13; +    repeated string changed_authorities = 12 [ +        (.android.privacy).dest = DEST_EXPLICIT +    ]; +    repeated string changed_uris = 13 [ +        (.android.privacy).dest = DEST_EXPLICIT +    ];      optional .android.net.NetworkProto network = 14;      // Only the desired data from an android.app.job.JobWorkItem object.      message JobWorkItem { +        option (.android.msg_privacy).dest = DEST_AUTOMATIC; +          optional int32 work_id = 1;          optional int32 delivery_count = 2;          optional .android.content.IntentProto intent = 3; diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto index f3ebd4144b89..babbef06fa8d 100644 --- a/core/proto/android/server/powermanagerservice.proto +++ b/core/proto/android/server/powermanagerservice.proto @@ -19,7 +19,7 @@ package com.android.server.power;  option java_multiple_files = true; -import "frameworks/base/core/proto/android/app/activitymanager.proto"; +import "frameworks/base/core/proto/android/app/enums.proto";  import "frameworks/base/core/proto/android/content/intent.proto";  import "frameworks/base/core/proto/android/os/batterymanager.proto";  import "frameworks/base/core/proto/android/os/looper.proto"; @@ -67,8 +67,7 @@ message PowerManagerServiceDumpProto {          optional string uid_string = 2;          optional bool is_active = 3;          optional int32 num_wake_locks = 4; -        optional bool is_process_state_unknown = 5; -        optional .android.app.ProcessState process_state = 6; +        optional .android.app.ProcessStateEnum process_state = 5;      }      optional ConstantsProto constants = 1; diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java index 416ea98d71d4..5c05ce4f7aeb 100644 --- a/media/java/android/media/update/VideoView2Provider.java +++ b/media/java/android/media/update/VideoView2Provider.java @@ -18,6 +18,7 @@ package android.media.update;  import android.media.AudioAttributes;  import android.media.MediaPlayerBase; +import android.media.session.MediaController;  import android.net.Uri;  import android.widget.MediaControlView2;  import android.widget.VideoView2; @@ -41,20 +42,14 @@ import java.util.Map;  // TODO @SystemApi  public interface VideoView2Provider extends ViewProvider {      void setMediaControlView2_impl(MediaControlView2 mediaControlView); +    MediaController getMediaController_impl();      MediaControlView2 getMediaControlView2_impl(); -    void start_impl(); -    void pause_impl(); -    int getDuration_impl(); -    int getCurrentPosition_impl(); -    void seekTo_impl(int msec); -    boolean isPlaying_impl(); -    int getBufferPercentage_impl();      int getAudioSessionId_impl();      void showSubtitle_impl();      void hideSubtitle_impl();      void setFullScreen_impl(boolean fullScreen); +    // TODO: remove setSpeed_impl once MediaController2 is ready.      void setSpeed_impl(float speed); -    float getSpeed_impl();      void setAudioFocusRequest_impl(int focusGain);      void setAudioAttributes_impl(AudioAttributes attributes);      void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerBase player); @@ -63,7 +58,6 @@ public interface VideoView2Provider extends ViewProvider {      void setVideoURI_impl(Uri uri, Map<String, String> headers);      void setViewType_impl(int viewType);      int getViewType_impl(); -    void stopPlayback_impl();      void setOnPreparedListener_impl(VideoView2.OnPreparedListener l);      void setOnCompletionListener_impl(VideoView2.OnCompletionListener l);      void setOnErrorListener_impl(VideoView2.OnErrorListener l); diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 74f3acad74fd..051c802dcbd4 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -108,6 +108,9 @@ cc_library_shared {          "libhidlbase",  // VNDK???          "libmediandk",  // NDK          "libpowermanager",  // for JWakeLock. to be removed + +        "libutils",  // Have to use shared lib to make libandroid_runtime behave correctly. +                     // Otherwise, AndroidRuntime::getJNIEnv() will return NULL.      ],      header_libs: ["libhardware_headers"], @@ -141,7 +144,6 @@ cc_library_shared {          "libstagefright_rtsp",          "libstagefright_timedtext",          "libunwindstack", -        "libutils",          "libutilscallstack",          "libvndksupport",          "libz", diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index 3bf0b37f407b..90ee8a6814d5 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -1165,51 +1165,6 @@ android_media_MediaPlayer2_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject      ;  } -// Pass through the arguments to the MediaServer player implementation. -static jint android_media_MediaPlayer2_applyVolumeShaper(JNIEnv *env, jobject thiz, -        jobject jconfig, jobject joperation) { -    // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java -    const int VOLUME_SHAPER_INVALID_OPERATION = -38; - -    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); -    if (mp == nullptr) { -        return (jint)VOLUME_SHAPER_INVALID_OPERATION; -    } - -    sp<VolumeShaper::Configuration> configuration; -    sp<VolumeShaper::Operation> operation; -    if (jconfig != nullptr) { -        configuration = VolumeShaperHelper::convertJobjectToConfiguration( -                env, gVolumeShaperFields, jconfig); -        ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str()); -    } -    if (joperation != nullptr) { -        operation = VolumeShaperHelper::convertJobjectToOperation( -                env, gVolumeShaperFields, joperation); -        ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str()); -    } -    VolumeShaper::Status status = mp->applyVolumeShaper(configuration, operation); -    if (status == INVALID_OPERATION) { -        status = VOLUME_SHAPER_INVALID_OPERATION; -    } -    return (jint)status; // if status < 0 an error, else a VolumeShaper id -} - -// Pass through the arguments to the MediaServer player implementation. -static jobject android_media_MediaPlayer2_getVolumeShaperState(JNIEnv *env, jobject thiz, -        jint id) { -    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); -    if (mp == nullptr) { -        return (jobject)nullptr; -    } - -    sp<VolumeShaper::State> state = mp->getVolumeShaperState((int)id); -    if (state.get() == nullptr) { -        return (jobject)nullptr; -    } -    return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state); -} -  /////////////////////////////////////////////////////////////////////////////////////  // Modular DRM begin @@ -1465,12 +1420,6 @@ static const JNINativeMethod gMethods[] = {      {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer2_attachAuxEffect},      {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer2_setRetransmitEndpoint},      {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer2;)V",  (void *)android_media_MediaPlayer2_setNextMediaPlayer}, -    {"native_applyVolumeShaper", -                            "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I", -                                                                (void *)android_media_MediaPlayer2_applyVolumeShaper}, -    {"native_getVolumeShaperState", -                            "(I)Landroid/media/VolumeShaper$State;", -                                                                (void *)android_media_MediaPlayer2_getVolumeShaperState},      // Modular DRM      { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer2_prepareDrm },      { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer2_releaseDrm }, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 9ff681555706..cb732c4c3b2c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -51,6 +51,8 @@ import java.util.function.Consumer;  import androidx.app.slice.Slice;  import androidx.app.slice.SliceItem;  import androidx.app.slice.core.SliceQuery; +import androidx.app.slice.widget.ListContent; +import androidx.app.slice.widget.RowContent;  import androidx.app.slice.widget.SliceLiveData;  /** @@ -115,25 +117,17 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe      private void showSlice(Slice slice) { -        // Main area -        SliceItem mainItem = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_SLICE, -                null /* hints */, new String[]{android.app.slice.Slice.HINT_LIST_ITEM}); -        mHasHeader = mainItem != null; - -        List<SliceItem> subItems = SliceQuery.findAll(slice, -                android.app.slice.SliceItem.FORMAT_SLICE, -                new String[]{android.app.slice.Slice.HINT_LIST_ITEM}, -                null /* nonHints */); - +        ListContent lc = new ListContent(slice); +        mHasHeader = lc.hasHeader(); +        List<SliceItem> subItems = lc.getRowItems();          if (!mHasHeader) {              mTitle.setVisibility(GONE);          } else {              mTitle.setVisibility(VISIBLE); -            SliceItem mainTitle = SliceQuery.find(mainItem.getSlice(), -                    android.app.slice.SliceItem.FORMAT_TEXT, -                    new String[]{android.app.slice.Slice.HINT_TITLE}, -                    null /* nonHints */); -            CharSequence title = mainTitle.getText(); +            // If there's a header it'll be the first subitem +            RowContent header = new RowContent(subItems.get(0), true /* showStartItem */); +            SliceItem mainTitle = header.getTitleItem(); +            CharSequence title = mainTitle != null ? mainTitle.getText() : null;              mTitle.setText(title);              // Check if we're already ellipsizing the text. @@ -152,9 +146,10 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe          mClickActions.clear();          final int subItemsCount = subItems.size();          final int blendedColor = getTextColor(); - -        for (int i = 0; i < subItemsCount; i++) { +        final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it +        for (int i = startIndex; i < subItemsCount; i++) {              SliceItem item = subItems.get(i); +            RowContent rc = new RowContent(item, true /* showStartItem */);              final Uri itemTag = item.getSlice().getUri();              // Try to reuse the view if already exists in the layout              KeyguardSliceButton button = mRow.findViewWithTag(itemTag); @@ -168,20 +163,13 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe              button.setHasDivider(i < subItemsCount - 1);              mRow.addView(button, i); -            PendingIntent pendingIntent; -            try { -                pendingIntent = item.getAction(); -            } catch (RuntimeException e) { -                Log.w(TAG, "Cannot retrieve action from keyguard slice", e); -                pendingIntent = null; +            PendingIntent pendingIntent = null; +            if (rc.getContentIntent() != null) { +                pendingIntent = rc.getContentIntent().getAction();              }              mClickActions.put(button, pendingIntent); -            SliceItem title = SliceQuery.find(item.getSlice(), -                    android.app.slice.SliceItem.FORMAT_TEXT, -                    new String[]{android.app.slice.Slice.HINT_TITLE}, -                    null /* nonHints */); -            button.setText(title.getText()); +            button.setText(rc.getTitleItem().getText());              Drawable iconDrawable = null;              SliceItem icon = SliceQuery.find(item.getSlice(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java index dec5303ff7bb..918b6edc0c30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -137,8 +137,12 @@ public class TransformState {          final View transformedView = mTransformedView;          boolean transformX = (transformationFlags & TRANSFORM_X) != 0;          boolean transformY = (transformationFlags & TRANSFORM_Y) != 0; -        boolean differentHeight = otherState.getViewHeight() != getViewHeight(); -        boolean differentWidth = otherState.getViewWidth() != getViewWidth(); +        int viewHeight = getViewHeight(); +        int otherHeight = otherState.getViewHeight(); +        boolean differentHeight = otherHeight != viewHeight && otherHeight != 0 && viewHeight != 0; +        int viewWidth = getViewWidth(); +        int otherWidth = otherState.getViewWidth(); +        boolean differentWidth = otherWidth != viewWidth && otherWidth != 0 && viewWidth != 0;          boolean transformScale = transformScale(otherState) && (differentHeight || differentWidth);          // lets animate the positions correctly          if (transformationAmount == 0.0f @@ -165,15 +169,15 @@ public class TransformState {                  // we also want to animate the scale if we're the same                  View otherView = otherState.getTransformedView();                  if (transformScale && differentWidth) { -                    setTransformationStartScaleX(otherState.getViewWidth() * otherView.getScaleX() -                            / (float) getViewWidth()); +                    setTransformationStartScaleX(otherWidth * otherView.getScaleX() +                            / (float) viewWidth);                      transformedView.setPivotX(0);                  } else {                      setTransformationStartScaleX(UNDEFINED);                  }                  if (transformScale && differentHeight) { -                    setTransformationStartScaleY(otherState.getViewHeight() * otherView.getScaleY() -                            / (float) getViewHeight()); +                    setTransformationStartScaleY(otherHeight * otherView.getScaleY() +                            / (float) viewHeight);                      transformedView.setPivotY(0);                  } else {                      setTransformationStartScaleY(UNDEFINED); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 61c8027eb800..5401e744f3ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -300,7 +300,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {              boolean showImeSwitcher) {          boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;          int hints = mNavigationIconHints; -        if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) { +        if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) {              hints |= NAVIGATION_HINT_BACK_ALT;          } else {              hints &= ~NAVIGATION_HINT_BACK_ALT; diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java index de99d71351c7..c18ed732f244 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java @@ -28,11 +28,12 @@ import static org.mockito.Mockito.when;  import android.bluetooth.BluetoothProfile;  import android.net.wifi.WifiManager; -import android.support.test.annotation.UiThreadTest;  import android.support.test.filters.SmallTest;  import android.support.test.runner.AndroidJUnit4;  import android.support.v7.media.MediaRouter;  import android.telecom.TelecomManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper;  import android.widget.TextView;  import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -49,7 +50,8 @@ import org.mockito.Mock;  import org.mockito.MockitoAnnotations;  @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper  public class OutputChooserDialogTest extends SysuiTestCase {      OutputChooserDialog mDialog; @@ -68,7 +70,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      @Before -    @UiThreadTest      public void setup() throws Exception {          MockitoAnnotations.initMocks(this); @@ -82,8 +83,12 @@ public class OutputChooserDialogTest extends SysuiTestCase {          mDialog = new OutputChooserDialog(getContext(), mRouter);      } +    @After +    public void tearDown() throws Exception { +        TestableLooper.get(this).processAllMessages(); +    } +      @Test -    @UiThreadTest      public void testClickMediaRouterItemConnectsMedia() {          mDialog.show(); @@ -100,7 +105,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testClickBtItemConnectsBt() {          mDialog.show(); @@ -116,7 +120,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testTitleNotInCall() {          mDialog.show(); @@ -126,7 +129,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testTitleInCall() {          mDialog.setIsInCall(true);          mDialog.show(); @@ -137,7 +139,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testNoMediaScanIfInCall() {          mDialog.setIsInCall(true);          mDialog.onAttachedToWindow(); @@ -146,7 +147,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testMediaScanIfNotInCall() {          mDialog.setIsInCall(false);          mDialog.onAttachedToWindow(); @@ -155,7 +155,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testRegisterCallbacks() {          mDialog.setIsInCall(false);          mDialog.onAttachedToWindow(); @@ -166,7 +165,6 @@ public class OutputChooserDialogTest extends SysuiTestCase {      }      @Test -    @UiThreadTest      public void testUnregisterCallbacks() {          mDialog.setIsInCall(false);          mDialog.onDetachedFromWindow(); diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index c1cda985a9ba..48b5a582f74e 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -73,6 +73,17 @@ public class VibratorService extends IVibratorService.Stub      private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 }; +    private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f; +    private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f; +    private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f; +    private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f; + +    private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255 +    private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255 + +    // If a vibration is playing for longer than 5s, it's probably not haptic feedback. +    private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000; +      private final LinkedList<VibrationInfo> mPreviousVibrations;      private final int mPreviousVibrationsLimit;      private final boolean mAllowPriorityVibrationsInLowPowerMode; @@ -89,6 +100,8 @@ public class VibratorService extends IVibratorService.Stub      private final IBatteryStats mBatteryStatsService;      private PowerManagerInternal mPowerManagerInternal;      private InputManager mIm; +    private Vibrator mVibrator; +    private SettingsObserver mSettingObserver;      private volatile VibrateThread mThread; @@ -101,7 +114,8 @@ public class VibratorService extends IVibratorService.Stub      private Vibration mCurrentVibration;      private int mCurVibUid = -1;      private boolean mLowPowerMode; -    private SettingsObserver mSettingObserver; +    private int mHapticFeedbackIntensity; +    private int mNotificationIntensity;      native static boolean vibratorExists();      native static void vibratorInit(); @@ -112,27 +126,33 @@ public class VibratorService extends IVibratorService.Stub      native static long vibratorPerformEffect(long effect, long strength);      private class Vibration implements IBinder.DeathRecipient { -        private final IBinder mToken; -        private final VibrationEffect mEffect; +        public final IBinder token;          // Start time in CLOCK_BOOTTIME base. -        private final long mStartTime; +        public final long startTime;          // Start time in unix epoch time. Only to be used for debugging purposes and to correlate -        // with other system events, any duration calculations should be done use mStartTime so as +        // with other system events, any duration calculations should be done use startTime so as          // not to be affected by discontinuities created by RTC adjustments. -        private final long mStartTimeDebug; -        private final int mUsageHint; -        private final int mUid; -        private final String mOpPkg; +        public final long startTimeDebug; +        public final int usageHint; +        public final int uid; +        public final String opPkg; + +        // The actual effect to be played. +        public VibrationEffect effect; +        // The original effect that was requested. This is non-null only when the original effect +        // differs from the effect that's being played. Typically these two things differ because +        // the effect was scaled based on the users vibration intensity settings. +        public VibrationEffect originalEffect;          private Vibration(IBinder token, VibrationEffect effect,                  int usageHint, int uid, String opPkg) { -            mToken = token; -            mEffect = effect; -            mStartTime = SystemClock.elapsedRealtime(); -            mStartTimeDebug = System.currentTimeMillis(); -            mUsageHint = usageHint; -            mUid = uid; -            mOpPkg = opPkg; +            this.token = token; +            this.effect = effect; +            this.startTime = SystemClock.elapsedRealtime(); +            this.startTimeDebug = System.currentTimeMillis(); +            this.usageHint = usageHint; +            this.uid = uid; +            this.opPkg = opPkg;          }          public void binderDied() { @@ -143,43 +163,68 @@ public class VibratorService extends IVibratorService.Stub              }          } -        public boolean hasLongerTimeout(long millis) { -            // If the current effect is a one shot vibration that will end after the given timeout -            // for the new one shot vibration, then just let the current vibration finish. All -            // other effect types will get pre-empted. -            if (mEffect instanceof VibrationEffect.OneShot) { -                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect; -                return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis; -            } -            return false; +        public boolean hasTimeoutLongerThan(long millis) { +            final long duration = effect.getDuration(); +            return duration >= 0 && duration > millis;          } -        public boolean isSystemHapticFeedback() { -            boolean repeating = false; -            if (mEffect instanceof VibrationEffect.Waveform) { -                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect; -                repeating = (waveform.getRepeatIndex() < 0); +        public boolean isHapticFeedback() { +            if (effect instanceof VibrationEffect.Prebaked) { +                VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; +                switch (prebaked.getId()) { +                    case VibrationEffect.EFFECT_CLICK: +                    case VibrationEffect.EFFECT_DOUBLE_CLICK: +                    case VibrationEffect.EFFECT_TICK: +                        return true; +                    default: +                        Slog.w(TAG, "Unknown prebaked vibration effect, " +                                + "assuming it isn't haptic feedback."); +                        return false; +                } +            } +            final long duration = effect.getDuration(); +            return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION; +        } + +        public boolean isNotification() { +            switch (usageHint) { +                case AudioAttributes.USAGE_NOTIFICATION: +                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: +                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: +                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: +                    return true; +                default: +                    return false;              } -            return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg)) -                    && !repeating; +        } + +        public boolean isRingtone() { +            return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE; +        } + +        public boolean isFromSystem() { +            return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);          }          public VibrationInfo toInfo() { -            return new VibrationInfo(mStartTimeDebug, mEffect, mUsageHint, mUid, mOpPkg); +            return new VibrationInfo( +                    startTimeDebug, effect, originalEffect, usageHint, uid, opPkg);          }      }      private static class VibrationInfo {          private final long mStartTimeDebug;          private final VibrationEffect mEffect; +        private final VibrationEffect mOriginalEffect;          private final int mUsageHint;          private final int mUid;          private final String mOpPkg;          public VibrationInfo(long startTimeDebug, VibrationEffect effect, -                int usageHint, int uid, String opPkg) { +                VibrationEffect originalEffect, int usageHint, int uid, String opPkg) {              mStartTimeDebug = startTimeDebug;              mEffect = effect; +            mOriginalEffect = originalEffect;              mUsageHint = usageHint;              mUid = uid;              mOpPkg = opPkg; @@ -192,6 +237,8 @@ public class VibratorService extends IVibratorService.Stub                      .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))                      .append(", effect: ")                      .append(mEffect) +                    .append(", originalEffect: ") +                    .append(mOriginalEffect)                      .append(", usageHint: ")                      .append(mUsageHint)                      .append(", uid: ") @@ -245,6 +292,7 @@ public class VibratorService extends IVibratorService.Stub          VibrationEffect tickEffect = createEffect(tickEffectTimings);          mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect }; +      }      private static VibrationEffect createEffect(long[] timings) { @@ -259,6 +307,7 @@ public class VibratorService extends IVibratorService.Stub      public void systemReady() {          mIm = mContext.getSystemService(InputManager.class); +        mVibrator = mContext.getSystemService(Vibrator.class);          mSettingObserver = new SettingsObserver(mH);          mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); @@ -279,6 +328,14 @@ public class VibratorService extends IVibratorService.Stub                  Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),                  true, mSettingObserver, UserHandle.USER_ALL); +        mContext.getContentResolver().registerContentObserver( +                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY), +                true, mSettingObserver, UserHandle.USER_ALL); + +        mContext.getContentResolver().registerContentObserver( +                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY), +                true, mSettingObserver, UserHandle.USER_ALL); +          mContext.registerReceiver(new BroadcastReceiver() {              @Override              public void onReceive(Context context, Intent intent) { @@ -380,11 +437,11 @@ public class VibratorService extends IVibratorService.Stub          // then just let the current one finish.          if (effect instanceof VibrationEffect.OneShot                  && mCurrentVibration != null -                && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) { +                && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {              VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;              VibrationEffect.OneShot currentOneShot = -                    (VibrationEffect.OneShot) mCurrentVibration.mEffect; -            if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming()) +                    (VibrationEffect.OneShot) mCurrentVibration.effect; +            if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())                      && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {                  if (DEBUG) {                      Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration"); @@ -398,7 +455,7 @@ public class VibratorService extends IVibratorService.Stub          // to grab the attention of the user, like ringtones and alarms, in favor of one-shot          // vibrations that are likely quite short.          if (!isRepeatingVibration(effect) -                && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.mEffect)) { +                && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.effect)) {              if (DEBUG) {                  Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");              } @@ -421,13 +478,7 @@ public class VibratorService extends IVibratorService.Stub      }      private static boolean isRepeatingVibration(VibrationEffect effect) { -        if (effect instanceof VibrationEffect.Waveform) { -            final VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; -            if (waveform.getRepeatIndex() >= 0) { -                return true; -            } -        } -        return false; +        return effect.getDuration() == Long.MAX_VALUE;      }      private void addToPreviousVibrationsLocked(Vibration vib) { @@ -444,7 +495,7 @@ public class VibratorService extends IVibratorService.Stub                  "cancelVibrate");          synchronized (mLock) { -            if (mCurrentVibration != null && mCurrentVibration.mToken == token) { +            if (mCurrentVibration != null && mCurrentVibration.token == token) {                  if (DEBUG) {                      Slog.d(TAG, "Canceling vibration.");                  } @@ -488,15 +539,16 @@ public class VibratorService extends IVibratorService.Stub      }      private void startVibrationLocked(final Vibration vib) { -        if (!isAllowedToVibrate(vib)) { -            if (DEBUG) { -                Slog.e(TAG, "Vibrate ignored, low power mode"); -            } +        if (!isAllowedToVibrateLocked(vib)) { +            return; +        } + +        final int intensity = getCurrentIntensityLocked(vib); +        if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {              return;          } -        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE && -                !shouldVibrateForRingtone()) { +        if (vib.isRingtone() && !shouldVibrateForRingtone()) {              if (DEBUG) {                  Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");              } @@ -508,26 +560,27 @@ public class VibratorService extends IVibratorService.Stub              if (mode == AppOpsManager.MODE_ERRORED) {                  // We might be getting calls from within system_server, so we don't actually want                  // to throw a SecurityException here. -                Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid); +                Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);              }              return;          } +        applyVibrationIntensityScalingLocked(vib, intensity);          startVibrationInnerLocked(vib);      }      private void startVibrationInnerLocked(Vibration vib) {          mCurrentVibration = vib; -        if (vib.mEffect instanceof VibrationEffect.OneShot) { -            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect; -            doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint); -            mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming()); -        } else if (vib.mEffect instanceof VibrationEffect.Waveform) { +        if (vib.effect instanceof VibrationEffect.OneShot) { +            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; +            doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint); +            mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration()); +        } else if (vib.effect instanceof VibrationEffect.Waveform) {              // mThread better be null here. doCancelVibrate should always be              // called before startNextVibrationLocked or startVibrationLocked. -            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect; -            mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint); +            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; +            mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);              mThread.start(); -        } else if (vib.mEffect instanceof VibrationEffect.Prebaked) { +        } else if (vib.effect instanceof VibrationEffect.Prebaked) {              long timeout = doVibratorPrebakedEffectLocked(vib);              if (timeout > 0) {                  mH.postDelayed(mVibrationEndRunnable, timeout); @@ -537,28 +590,91 @@ public class VibratorService extends IVibratorService.Stub          }      } -    private boolean isAllowedToVibrate(Vibration vib) { +    private boolean isAllowedToVibrateLocked(Vibration vib) {          if (!mLowPowerMode) {              return true;          } -        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { + +        if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {              return true;          } -        if (!mAllowPriorityVibrationsInLowPowerMode) { -            return false; -        } -        if (vib.mUsageHint == AudioAttributes.USAGE_ALARM || -            vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY || -            vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) { +        if (vib.usageHint == AudioAttributes.USAGE_ALARM || +                vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY || +                vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {              return true;          }          return false;      } +    private int getCurrentIntensityLocked(Vibration vib) { +        if (vib.isNotification() || vib.isRingtone()){ +            return mNotificationIntensity; +        } else if (vib.isHapticFeedback()) { +            return mHapticFeedbackIntensity; +        } else { +            return Vibrator.VIBRATION_INTENSITY_MEDIUM; +        } +    } + +    /** +     * Scale the vibration effect by the intensity as appropriate based its intent. +     */ +    private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) { +        if (vib.effect instanceof VibrationEffect.Prebaked) { +            // Prebaked effects are always just a direct translation from intensity to +            // EffectStrength. +            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect; +            prebaked.setEffectStrength(intensityToEffectStrength(intensity)); +            return; +        } + +        final float gamma; +        final int maxAmplitude; +        if (vib.isNotification() || vib.isRingtone()) { +            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) { +                gamma = GAMMA_SCALE_FACTOR_MINIMUM; +                maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY; +            } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) { +                gamma = GAMMA_SCALE_FACTOR_LOW; +                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY; +            } else { +                gamma = GAMMA_SCALE_FACTOR_NONE; +                maxAmplitude = VibrationEffect.MAX_AMPLITUDE; +            } +        } else { +            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) { +                gamma = GAMMA_SCALE_FACTOR_LOW; +                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY; +            } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) { +                gamma = GAMMA_SCALE_FACTOR_HIGH; +                maxAmplitude = VibrationEffect.MAX_AMPLITUDE; +            } else { +                gamma = GAMMA_SCALE_FACTOR_NONE; +                maxAmplitude = VibrationEffect.MAX_AMPLITUDE; +            } +        } + +        VibrationEffect scaledEffect = null; +        if (vib.effect instanceof VibrationEffect.OneShot) { +            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; +            scaledEffect = oneShot.scale(gamma, maxAmplitude); +        } else if (vib.effect instanceof VibrationEffect.Waveform) { +            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; +            scaledEffect = waveform.scale(gamma, maxAmplitude); +        } else { +            Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type"); +        } + +        if (scaledEffect != null) { +            vib.originalEffect = vib.effect; +            vib.effect = scaledEffect; +        } +    } +      private boolean shouldVibrateForRingtone() { -        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); +        AudioManager audioManager = mContext.getSystemService(AudioManager.class);          int ringerMode = audioManager.getRingerModeInternal();          // "Also vibrate for calls" Setting in Sound          if (Settings.System.getInt( @@ -573,10 +689,10 @@ public class VibratorService extends IVibratorService.Stub          int mode;          try {              mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE, -                    vib.mUsageHint, vib.mUid, vib.mOpPkg); +                    vib.usageHint, vib.uid, vib.opPkg);              if (mode == AppOpsManager.MODE_ALLOWED) {                  mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), -                    AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg); +                    AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);              }          } catch (RemoteException e) {              Slog.e(TAG, "Failed to get appop mode for vibration!", e); @@ -589,8 +705,8 @@ public class VibratorService extends IVibratorService.Stub          if (mCurrentVibration != null) {              try {                  mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), -                        AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, -                        mCurrentVibration.mOpPkg); +                        AppOpsManager.OP_VIBRATE, mCurrentVibration.uid, +                        mCurrentVibration.opPkg);              } catch (RemoteException e) { }              unlinkVibration(mCurrentVibration);              mCurrentVibration = null; @@ -600,9 +716,9 @@ public class VibratorService extends IVibratorService.Stub      private void linkVibration(Vibration vib) {          // Only link against waveforms since they potentially don't have a finish if          // they're repeating. Let other effects just play out until they're done. -        if (vib.mEffect instanceof VibrationEffect.Waveform) { +        if (vib.effect instanceof VibrationEffect.Waveform) {              try { -                vib.mToken.linkToDeath(vib, 0); +                vib.token.linkToDeath(vib, 0);              } catch (RemoteException e) {                  return;              } @@ -610,8 +726,8 @@ public class VibratorService extends IVibratorService.Stub      }      private void unlinkVibration(Vibration vib) { -        if (vib.mEffect instanceof VibrationEffect.Waveform) { -            vib.mToken.unlinkToDeath(vib, 0); +        if (vib.effect instanceof VibrationEffect.Waveform) { +            vib.token.unlinkToDeath(vib, 0);          }      } @@ -619,6 +735,7 @@ public class VibratorService extends IVibratorService.Stub          synchronized (mLock) {              boolean devicesUpdated = updateInputDeviceVibratorsLocked();              boolean lowPowerModeUpdated = updateLowPowerModeLocked(); +            updateVibrationIntensityLocked();              if (devicesUpdated || lowPowerModeUpdated) {                  // If the state changes out from under us then just reset. @@ -678,6 +795,15 @@ public class VibratorService extends IVibratorService.Stub          return false;      } +    private void updateVibrationIntensityLocked() { +        mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), +                Settings.System.HAPTIC_FEEDBACK_INTENSITY, +                mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT); +        mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), +                Settings.System.NOTIFICATION_VIBRATION_INTENSITY, +                mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT); +    } +      @Override      public void onInputDeviceAdded(int deviceId) {          updateVibrators(); @@ -755,28 +881,32 @@ public class VibratorService extends IVibratorService.Stub      }      private long doVibratorPrebakedEffectLocked(Vibration vib) { +        final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; +        final boolean usingInputDeviceVibrators;          synchronized (mInputDeviceVibrators) { -            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect; -            // Input devices don't support prebaked effect, so skip trying it with them. -            if (mInputDeviceVibrators.isEmpty()) { -                long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM); -                if (timeout > 0) { -                    noteVibratorOnLocked(vib.mUid, timeout); -                    return timeout; -                } -            } -            if (!prebaked.shouldFallback()) { -                return 0; -            } -            VibrationEffect effect = getFallbackEffect(prebaked.getId()); -            if (effect == null) { -                Slog.w(TAG, "Failed to play prebaked effect, no fallback"); -                return 0; +            usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty(); +        } +        // Input devices don't support prebaked effect, so skip trying it with them. +        if (!usingInputDeviceVibrators) { +            long timeout = vibratorPerformEffect(prebaked.getId(), prebaked.getEffectStrength()); +            if (timeout > 0) { +                noteVibratorOnLocked(vib.uid, timeout); +                return timeout;              } -            Vibration fallbackVib = -                    new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg); -            startVibrationInnerLocked(fallbackVib);          } +        if (!prebaked.shouldFallback()) { +            return 0; +        } +        VibrationEffect effect = getFallbackEffect(prebaked.getId()); +        if (effect == null) { +            Slog.w(TAG, "Failed to play prebaked effect, no fallback"); +            return 0; +        } +        Vibration fallbackVib = +                new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg); +        final int intensity = getCurrentIntensityLocked(fallbackVib); +        applyVibrationIntensityScalingLocked(fallbackVib, intensity); +        startVibrationInnerLocked(fallbackVib);          return 0;      } @@ -787,6 +917,25 @@ public class VibratorService extends IVibratorService.Stub          return mFallbackEffects[effectId];      } +    /** +     * Return the current desired effect strength. +     * +     * If the returned value is < 0 then the vibration shouldn't be played at all. +     */ +    private static int intensityToEffectStrength(int intensity) { +        switch (intensity) { +            case Vibrator.VIBRATION_INTENSITY_LOW: +                return EffectStrength.LIGHT; +            case Vibrator.VIBRATION_INTENSITY_MEDIUM: +                return EffectStrength.MEDIUM; +            case Vibrator.VIBRATION_INTENSITY_HIGH: +                return EffectStrength.STRONG; +            default: +                Slog.w(TAG, "Got unexpected vibration intensity: " + intensity); +                return EffectStrength.STRONG; +        } +    } +      private void noteVibratorOnLocked(int uid, long millis) {          try {              mBatteryStatsService.noteVibratorOn(uid, millis); @@ -945,7 +1094,8 @@ public class VibratorService extends IVibratorService.Stub                      // haptic feedback as part of the transition.  So we don't cancel                      // system vibrations.                      if (mCurrentVibration != null -                            && !mCurrentVibration.isSystemHapticFeedback()) { +                            && !(mCurrentVibration.isHapticFeedback() +                                && mCurrentVibration.isFromSystem())) {                          doCancelVibrateLocked();                      }                  } @@ -957,10 +1107,21 @@ public class VibratorService extends IVibratorService.Stub      protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {          if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; -        pw.println("Previous vibrations:"); +        pw.println("Vibrator Service:");          synchronized (mLock) { +            pw.print("  mCurrentVibration="); +            if (mCurrentVibration != null) { +                pw.println(mCurrentVibration.toInfo().toString()); +            } else { +                pw.println("null"); +            } +            pw.println("  mLowPowerMode=" + mLowPowerMode); +            pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity); +            pw.println("  mNotificationIntensity=" + mNotificationIntensity); +            pw.println(""); +            pw.println("  Previous vibrations:");              for (VibrationInfo info : mPreviousVibrations) { -                pw.print("  "); +                pw.print("    ");                  pw.println(info.toString());              }          } diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index aa8d56b3f6c6..220014fff4ab 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -424,7 +424,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>              }          } finally {              final ActivityStack topFullscreenStack = -                    getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); +                    getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);              if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {                  // Whenever split-screen is dismissed we want the home stack directly behind the                  // current top fullscreen stack so it shows up when the top stack is finished. @@ -580,6 +580,16 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>          return false;      } +    ActivityStack getTopStackInWindowingMode(int windowingMode) { +        for (int i = mStacks.size() - 1; i >= 0; --i) { +            final ActivityStack current = mStacks.get(i); +            if (windowingMode == current.getWindowingMode()) { +                return current; +            } +        } +        return null; +    } +      int getIndexOf(ActivityStack stack) {          return mStacks.indexOf(stack);      } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f4bf88438499..796290f26305 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -47,6 +47,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;  import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;  import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;  import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;  import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;  import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;  import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -1637,6 +1638,14 @@ public class ActivityManagerService extends IActivityManager.Stub      String mProfileApp = null;      ProcessRecord mProfileProc = null;      ProfilerInfo mProfilerInfo = null; + +    /** +     * Stores a map of process name -> agent string. When a process is started and mAgentAppMap +     * is not null, this map is checked and the mapped agent installed during bind-time. Note: +     * A non-null agent in mProfileInfo overrides this. +     */ +    private @Nullable Map<String, String> mAppAgentMap = null; +      int mProfileType = 0;      final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();      String mMemWatchDumpProcName; @@ -7456,25 +7465,6 @@ public class ActivityManagerService extends IActivityManager.Stub                  }              } -            ProfilerInfo profilerInfo = null; -            String preBindAgent = null; -            if (mProfileApp != null && mProfileApp.equals(processName)) { -                mProfileProc = app; -                if (mProfilerInfo != null) { -                    // Send a profiler info object to the app if either a file is given, or -                    // an agent should be loaded at bind-time. -                    boolean needsInfo = mProfilerInfo.profileFile != null -                            || mProfilerInfo.attachAgentDuringBind; -                    profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null; -                    if (!mProfilerInfo.attachAgentDuringBind) { -                        preBindAgent = mProfilerInfo.agent; -                    } -                } -            } else if (app.instr != null && app.instr.mProfileFile != null) { -                profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false, -                        null, false); -            } -              boolean enableTrackAllocation = false;              if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {                  enableTrackAllocation = true; @@ -7499,6 +7489,39 @@ public class ActivityManagerService extends IActivityManager.Stub              ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;              app.compat = compatibilityInfoForPackageLocked(appInfo); +            ProfilerInfo profilerInfo = null; +            String preBindAgent = null; +            if (mProfileApp != null && mProfileApp.equals(processName)) { +                mProfileProc = app; +                if (mProfilerInfo != null) { +                    // Send a profiler info object to the app if either a file is given, or +                    // an agent should be loaded at bind-time. +                    boolean needsInfo = mProfilerInfo.profileFile != null +                            || mProfilerInfo.attachAgentDuringBind; +                    profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null; +                    if (mProfilerInfo.agent != null) { +                        preBindAgent = mProfilerInfo.agent; +                    } +                } +            } else if (app.instr != null && app.instr.mProfileFile != null) { +                profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false, +                        null, false); +            } +            if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) { +                // We need to do a debuggable check here. See setAgentApp for why the check is +                // postponed to here. +                if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { +                    String agent = mAppAgentMap.get(processName); +                    // Do not overwrite already requested agent. +                    if (profilerInfo == null) { +                        profilerInfo = new ProfilerInfo(null, null, 0, false, false, +                                mAppAgentMap.get(processName), true); +                    } else if (profilerInfo.agent == null) { +                        profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true); +                    } +                } +            } +              if (profilerInfo != null && profilerInfo.profileFd != null) {                  profilerInfo.profileFd = profilerInfo.profileFd.dup();              } @@ -11045,8 +11068,20 @@ public class ActivityManagerService extends IActivityManager.Stub                  }                  if (toTop) { +                    // Caller wants the current split-screen primary stack to be the top stack after +                    // it goes fullscreen, so move it to the front.                      stack.moveToFront("dismissSplitScreenMode"); +                } else if (mStackSupervisor.isFocusedStack(stack)) { +                    // In this case the current split-screen primary stack shouldn't be the top +                    // stack after it goes fullscreen, but it current has focus, so we move the +                    // focus to the top-most split-screen secondary stack next to it. +                    final ActivityStack otherStack = stack.getDisplay().getTopStackInWindowingMode( +                            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); +                    if (otherStack != null) { +                        otherStack.moveToFront("dismissSplitScreenMode_other"); +                    }                  } +                  stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);              }          } finally { @@ -13155,6 +13190,52 @@ public class ActivityManagerService extends IActivityManager.Stub          }      } +    /** +     * Set or remove an agent to be run whenever an app with the given process name starts. +     * +     * This method will not check whether the given process name matches a debuggable app. That +     * would require scanning all current packages, and a rescan when new packages are installed +     * or updated. +     * +     * Instead, do the check when an application is started and matched to a stored agent. +     * +     * @param packageName the process name of the app. +     * @param agent the agent string to be used, or null to remove any previously set agent. +     */ +    @Override +    public void setAgentApp(@NonNull String packageName, @Nullable String agent) { +        synchronized (this) { +            // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to +            // its own permission. +            if (checkCallingPermission( +                    android.Manifest.permission.SET_ACTIVITY_WATCHER) != +                        PackageManager.PERMISSION_GRANTED) { +                throw new SecurityException( +                        "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER); +            } + +            if (agent == null) { +                if (mAppAgentMap != null) { +                    mAppAgentMap.remove(packageName); +                    if (mAppAgentMap.isEmpty()) { +                        mAppAgentMap = null; +                    } +                } +            } else { +                if (mAppAgentMap == null) { +                    mAppAgentMap = new HashMap<>(); +                } +                if (mAppAgentMap.size() >= 100) { +                    // Limit the size of the map, to avoid OOMEs. +                    Slog.e(TAG, "App agent map has too many entries, cannot add " + packageName +                            + "/" + agent); +                    return; +                } +                mAppAgentMap.put(packageName, agent); +            } +        } +    } +      void setTrackAllocationApp(ApplicationInfo app, String processName) {          synchronized (this) {              boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); @@ -25545,11 +25626,14 @@ public class ActivityManagerService extends IActivityManager.Stub              // "= 0" is needed because otherwise catch(RemoteException) would make it look like              // packageUid may not be initialized.              int packageUid = 0; +            final long ident = Binder.clearCallingIdentity();              try {                  packageUid = AppGlobals.getPackageManager().getPackageUid(                          packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);              } catch (RemoteException e) {                  // Shouldn't happen. +            } finally { +                Binder.restoreCallingIdentity(ident);              }              synchronized (ActivityManagerService.this) { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 1240f5e664aa..f0c90e0f1fab 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -160,6 +160,8 @@ final class ActivityManagerShellCommand extends ShellCommand {                      return runDumpHeap(pw);                  case "set-debug-app":                      return runSetDebugApp(pw); +                case "set-agent-app": +                    return runSetAgentApp(pw);                  case "clear-debug-app":                      return runClearDebugApp(pw);                  case "set-watch-heap": @@ -873,6 +875,13 @@ final class ActivityManagerShellCommand extends ShellCommand {          return 0;      } +    int runSetAgentApp(PrintWriter pw) throws RemoteException { +        String pkg = getNextArgRequired(); +        String agent = getNextArg(); +        mInterface.setAgentApp(pkg, agent); +        return 0; +    } +      int runClearDebugApp(PrintWriter pw) throws RemoteException {          mInterface.setDebugApp(null, false, true);          return 0; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 6b380f1101eb..0d96468761be 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -16,6 +16,7 @@  package com.android.server.am; +import android.app.ActivityManager;  import android.bluetooth.BluetoothActivityEnergyInfo;  import android.content.Context;  import android.content.pm.ApplicationInfo; @@ -353,10 +354,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub          }      } +    /** @param state Process state from ActivityManager.java. */      void noteUidProcessState(int uid, int state) {          synchronized (mStats) {              // TODO: remove this once we figure out properly where and how -            StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid, state); +            StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid, +                    ActivityManager.processStateAmToProto(state));              mStats.noteUidProcessStateLocked(uid, state);          } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 29bfebe631c7..a50d069f4fef 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -24,7 +24,7 @@ import java.io.OutputStream;  import java.nio.ByteBuffer;  import android.app.ActivityManager; -import android.app.ActivityManagerProto; +import android.app.AppProtoEnums;  import android.os.Build;  import android.os.SystemClock;  import com.android.internal.util.MemInfoReader; @@ -420,47 +420,49 @@ public final class ProcessList {      public static int makeProcStateProtoEnum(int curProcState) {          switch (curProcState) {              case ActivityManager.PROCESS_STATE_PERSISTENT: -                return ActivityManagerProto.PROCESS_STATE_PERSISTENT; +                return AppProtoEnums.PROCESS_STATE_PERSISTENT;              case ActivityManager.PROCESS_STATE_PERSISTENT_UI: -                return ActivityManagerProto.PROCESS_STATE_PERSISTENT_UI; +                return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;              case ActivityManager.PROCESS_STATE_TOP: -                return ActivityManagerProto.PROCESS_STATE_TOP; +                return AppProtoEnums.PROCESS_STATE_TOP;              case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE: -                return ActivityManagerProto.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; +                return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;              case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE: -                return ActivityManagerProto.PROCESS_STATE_FOREGROUND_SERVICE; +                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;              case ActivityManager.PROCESS_STATE_TOP_SLEEPING: -                return ActivityManagerProto.PROCESS_STATE_TOP_SLEEPING; +                return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;              case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: -                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_FOREGROUND; +                return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;              case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: -                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_BACKGROUND; +                return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;              case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND: -                return ActivityManagerProto.PROCESS_STATE_TRANSIENT_BACKGROUND; +                return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;              case ActivityManager.PROCESS_STATE_BACKUP: -                return ActivityManagerProto.PROCESS_STATE_BACKUP; +                return AppProtoEnums.PROCESS_STATE_BACKUP;              case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: -                return ActivityManagerProto.PROCESS_STATE_HEAVY_WEIGHT; +                return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;              case ActivityManager.PROCESS_STATE_SERVICE: -                return ActivityManagerProto.PROCESS_STATE_SERVICE; +                return AppProtoEnums.PROCESS_STATE_SERVICE;              case ActivityManager.PROCESS_STATE_RECEIVER: -                return ActivityManagerProto.PROCESS_STATE_RECEIVER; +                return AppProtoEnums.PROCESS_STATE_RECEIVER;              case ActivityManager.PROCESS_STATE_HOME: -                return ActivityManagerProto.PROCESS_STATE_HOME; +                return AppProtoEnums.PROCESS_STATE_HOME;              case ActivityManager.PROCESS_STATE_LAST_ACTIVITY: -                return ActivityManagerProto.PROCESS_STATE_LAST_ACTIVITY; +                return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;              case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: -                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY; +                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;              case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: -                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; +                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;              case ActivityManager.PROCESS_STATE_CACHED_RECENT: -                return ActivityManagerProto.PROCESS_STATE_CACHED_RECENT; +                return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;              case ActivityManager.PROCESS_STATE_CACHED_EMPTY: -                return ActivityManagerProto.PROCESS_STATE_CACHED_EMPTY; +                return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;              case ActivityManager.PROCESS_STATE_NONEXISTENT: -                return ActivityManagerProto.PROCESS_STATE_NONEXISTENT; +                return AppProtoEnums.PROCESS_STATE_NONEXISTENT; +            case ActivityManager.PROCESS_STATE_UNKNOWN: +                return AppProtoEnums.PROCESS_STATE_UNKNOWN;              default: -                return -1; +                return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;          }      } diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java index 979beed520c3..57258a8ca0bc 100644 --- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java +++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java @@ -257,6 +257,29 @@ public class NetdEventListenerService extends INetdEventListener.Stub {                  uid, iface, ethertype, dstMac, srcIp, dstIp, ipNextHeader, srcPort, dstPort);      } +    @Override +    public synchronized void onTcpSocketStatsEvent(int[] networkIds, +            int[] sentPackets, int[] lostPackets, int[] rttsUs, int[] sentAckDiffsMs) { +        if (networkIds.length != sentPackets.length +                || networkIds.length != lostPackets.length +                || networkIds.length != rttsUs.length +                || networkIds.length != sentAckDiffsMs.length) { +            Log.e(TAG, "Mismatched lengths of TCP socket stats data arrays"); +            return; +        } + +        long timestamp = System.currentTimeMillis(); +        for (int i = 0; i < networkIds.length; i++) { +            int netId = networkIds[i]; +            int sent = sentPackets[i]; +            int lost = lostPackets[i]; +            int rttUs = rttsUs[i]; +            int sentAckDiffMs = sentAckDiffsMs[i]; +            getMetricsForNetwork(timestamp, netId) +                    .addTcpStatsResult(sent, lost, rttUs, sentAckDiffMs); +        } +    } +      private void addWakeupEvent(WakeupEvent event) {          String iface = event.iface;          mWakeupEvents.append(event); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index ad2cf6c18d92..422d0cbe5594 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -20,6 +20,8 @@ import android.accounts.Account;  import android.accounts.AccountAndUser;  import android.accounts.AccountManager;  import android.accounts.AccountManagerInternal; +import android.annotation.NonNull; +import android.annotation.UserIdInt;  import android.app.ActivityManager;  import android.app.AppGlobals;  import android.app.Notification; @@ -32,6 +34,7 @@ import android.content.ComponentName;  import android.content.ContentResolver;  import android.content.Context;  import android.content.ISyncAdapter; +import android.content.ISyncAdapterUnsyncableAccountCallback;  import android.content.ISyncContext;  import android.content.Intent;  import android.content.IntentFilter; @@ -212,6 +215,10 @@ public class SyncManager {      private static final int SYNC_OP_STATE_INVALID = 1;      private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2; +    /** Flags used when connecting to a sync adapter service */ +    private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE +            | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT; +      private Context mContext;      private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0]; @@ -876,7 +883,7 @@ public class SyncManager {      public void scheduleSync(Account requestedAccount, int userId, int reason,                               String requestedAuthority, Bundle extras, int targetSyncState) {          scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState, -                0 /* min delay */); +                0 /* min delay */, true /* checkIfAccountReady */);      }      /** @@ -884,7 +891,7 @@ public class SyncManager {       */      private void scheduleSync(Account requestedAccount, int userId, int reason,                               String requestedAuthority, Bundle extras, int targetSyncState, -                             final long minDelayMillis) { +                             final long minDelayMillis, boolean checkIfAccountReady) {          final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);          if (extras == null) {              extras = new Bundle(); @@ -963,7 +970,8 @@ public class SyncManager {              }              for (String authority : syncableAuthorities) { -                int isSyncable = computeSyncable(account.account, account.userId, authority); +                int isSyncable = computeSyncable(account.account, account.userId, authority, +                        !checkIfAccountReady);                  if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {                      continue; @@ -1000,7 +1008,8 @@ public class SyncManager {                                  if (result != null                                          && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {                                      scheduleSync(account.account, userId, reason, authority, -                                            finalExtras, targetSyncState, minDelayMillis); +                                            finalExtras, targetSyncState, minDelayMillis, +                                            true /* checkIfAccountReady */);                                  }                              }                          )); @@ -1009,7 +1018,7 @@ public class SyncManager {                  final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();                  final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable(); -                if (isSyncable < 0 && isAlwaysSyncable) { +                if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {                      mSyncStorageEngine.setIsSyncable(                              account.account, account.userId, authority, AuthorityInfo.SYNCABLE);                      isSyncable = AuthorityInfo.SYNCABLE; @@ -1045,25 +1054,34 @@ public class SyncManager {                  final String owningPackage = syncAdapterInfo.componentName.getPackageName();                  if (isSyncable == AuthorityInfo.NOT_INITIALIZED) { -                    // Initialisation sync. -                    Bundle newExtras = new Bundle(); -                    newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); -                    if (isLoggable) { -                        Slog.v(TAG, "schedule initialisation Sync:" -                                + ", delay until " + delayUntil -                                + ", run by " + 0 -                                + ", flexMillis " + 0 -                                + ", source " + source -                                + ", account " + account -                                + ", authority " + authority -                                + ", extras " + newExtras); +                    if (checkIfAccountReady) { +                        Bundle finalExtras = new Bundle(extras); + +                        sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId, +                                () -> scheduleSync(account.account, account.userId, reason, +                                        authority, finalExtras, targetSyncState, minDelayMillis, +                                        false)); +                    } else { +                        // Initialisation sync. +                        Bundle newExtras = new Bundle(); +                        newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); +                        if (isLoggable) { +                            Slog.v(TAG, "schedule initialisation Sync:" +                                    + ", delay until " + delayUntil +                                    + ", run by " + 0 +                                    + ", flexMillis " + 0 +                                    + ", source " + source +                                    + ", account " + account +                                    + ", authority " + authority +                                    + ", extras " + newExtras); +                        } +                        postScheduleSyncMessage( +                                new SyncOperation(account.account, account.userId, +                                        owningUid, owningPackage, reason, source, +                                        authority, newExtras, allowParallelSyncs), +                                minDelayMillis +                        );                      } -                    postScheduleSyncMessage( -                            new SyncOperation(account.account, account.userId, -                                    owningUid, owningPackage, reason, source, -                                    authority, newExtras, allowParallelSyncs), -                            minDelayMillis -                    );                  } else if (targetSyncState == AuthorityInfo.UNDEFINED                          || targetSyncState == isSyncable) {                      if (isLoggable) { @@ -1085,10 +1103,6 @@ public class SyncManager {          }      } -    private int computeSyncable(Account account, int userId, String authority) { -        return computeSyncable(account, userId, authority, true); -    } -      public int computeSyncable(Account account, int userId, String authority,              boolean checkAccountAccess) {          final int status = getIsSyncable(account, userId, authority); @@ -1198,7 +1212,7 @@ public class SyncManager {          final Bundle extras = new Bundle();          extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);          scheduleSync(account, userId, reason, authority, extras, -                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY); +                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */);      }      public SyncAdapterType[] getSyncAdapterTypes(int userId) { @@ -1706,6 +1720,28 @@ public class SyncManager {      }      /** +     * Construct intent used to bind to an adapter. +     * +     * @param context Context to create intent for +     * @param syncAdapterComponent The adapter description +     * @param userId The user the adapter belongs to +     * +     * @return The intent required to bind to the adapter +     */ +    static @NonNull Intent getAdapterBindIntent(@NonNull Context context, +            @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) { +        final Intent intent = new Intent(); +        intent.setAction("android.content.SyncAdapter"); +        intent.setComponent(syncAdapterComponent); +        intent.putExtra(Intent.EXTRA_CLIENT_LABEL, +                com.android.internal.R.string.sync_binding_label); +        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0, +                new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId))); + +        return intent; +    } + +    /**       * @hide       */      class ActiveSyncContext extends ISyncContext.Stub @@ -1793,19 +1829,11 @@ public class SyncManager {              if (Log.isLoggable(TAG, Log.VERBOSE)) {                  Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);              } -            Intent intent = new Intent(); -            intent.setAction("android.content.SyncAdapter"); -            intent.setComponent(serviceComponent); -            intent.putExtra(Intent.EXTRA_CLIENT_LABEL, -                    com.android.internal.R.string.sync_binding_label); -            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser( -                    mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0, -                    null, new UserHandle(userId))); +            Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId); +              mBound = true;              final boolean bindResult = mContext.bindServiceAsUser(intent, this, -                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND -                            | Context.BIND_ALLOW_OOM_MANAGEMENT, -                    new UserHandle(mSyncOperation.target.userId)); +                    SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));              mLogger.log("bindService() returned=", mBound, " for ", this);              if (!bindResult) {                  mBound = false; @@ -2528,6 +2556,92 @@ public class SyncManager {          }      } +    interface OnReadyCallback { +        void onReady(); +    } + +    static void sendOnUnsyncableAccount(@NonNull Context context, +            @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo, +            @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) { +        OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo, +                onReadyCallback); + +        boolean isBound = context.bindServiceAsUser( +                getAdapterBindIntent(context, syncAdapterInfo.componentName, userId), +                connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId)); + +        if (isBound) { +            // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection. +            (new Handler(Looper.getMainLooper())).postDelayed( +                    () -> context.unbindService(connection), +                    OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS); +        } else { +                /* +                 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if +                 * there the service cannot be bound, assume the default behavior. +                 */ +            connection.onReady(); +        } +    } + + +    /** +     * Helper class for calling ISyncAdapter.onUnsyncableAccountDone. +     * +     * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens. +     */ +    private static class OnUnsyncableAccountCheck implements ServiceConnection { +        static final long SERVICE_BOUND_TIME_MILLIS = 5000; + +        private final @NonNull OnReadyCallback mOnReadyCallback; +        private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> +                mSyncAdapterInfo; + +        OnUnsyncableAccountCheck( +                @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo, +                @NonNull OnReadyCallback onReadyCallback) { +            mSyncAdapterInfo = syncAdapterInfo; +            mOnReadyCallback = onReadyCallback; +        } + +        private void onReady() { +            long identity = Binder.clearCallingIdentity(); +            try { +                mOnReadyCallback.onReady(); +            } finally { +                Binder.restoreCallingIdentity(identity); +            } +        } + +        @Override +        public void onServiceConnected(ComponentName name, IBinder service) { +            final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service); + +            try { +                adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() { +                    @Override +                    public void onUnsyncableAccountDone(boolean isReady) { +                        if (isReady) { +                            onReady(); +                        } +                    } +                }); +            } catch (RemoteException e) { +                Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e); +                /* +                 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if +                 * there is a crash in the implementation, assume the default behavior. +                 */ +                onReady(); +            } +        } + +        @Override +        public void onServiceDisconnected(ComponentName name) { +            // Wait until the service connects again +        } +    } +      /**       * A helper object to keep track of the time we have spent syncing since the last boot       */ @@ -3199,7 +3313,7 @@ public class SyncManager {                  return SYNC_OP_STATE_INVALID;              }              // Drop this sync request if it isn't syncable. -            state = computeSyncable(target.account, target.userId, target.provider); +            state = computeSyncable(target.account, target.userId, target.provider, true);              if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {                  if (isLoggable) {                      Slog.v(TAG, "    Dropping sync operation: " diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java index 4e7490858fc8..569e9ec995d7 100644 --- a/services/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java @@ -16,6 +16,7 @@  package com.android.server.job; +import android.annotation.UserIdInt;  import android.app.job.JobInfo;  import java.util.List; @@ -39,6 +40,14 @@ public interface JobSchedulerInternal {      long nextHeartbeatForBucket(int bucket);      /** +     * Heartbeat ordinal for the given app.  This is typically the heartbeat at which +     * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run +     * jobs in a long time is immediately runnable even if the app is bucketed into +     * an infrequent time allocation. +     */ +    public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket); + +    /**       * Returns a list of pending jobs scheduled by the system service.       */      List<JobInfo> getSystemScheduledPendingJobs(); diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 5da470e68875..2066f2af46dd 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -19,6 +19,7 @@ package com.android.server.job;  import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;  import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; +import android.annotation.UserIdInt;  import android.app.Activity;  import android.app.ActivityManager;  import android.app.ActivityManagerInternal; @@ -39,6 +40,7 @@ import android.content.ContentResolver;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter; +import android.content.Intent.UriFlags;  import android.content.pm.IPackageManager;  import android.content.pm.PackageManager;  import android.content.pm.PackageManagerInternal; @@ -2065,6 +2067,33 @@ public final class JobSchedulerService extends com.android.server.SystemService          }          /** +         * Heartbeat ordinal for the given app.  This is typically the heartbeat at which +         * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run +         * jobs in a long time is immediately runnable even if the app is bucketed into +         * an infrequent time allocation. +         */ +        public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, +                final int appStandbyBucket) { +            if (appStandbyBucket == 0 || +                    appStandbyBucket >= mConstants.STANDBY_BEATS.length) { +                // ACTIVE => everything can be run right away +                // NEVER => we won't run them anyway, so let them go in the future +                // as soon as the app enters normal use +                return 0; +            } + +            final long timeSinceLastJob = mStandbyTracker.getTimeSinceLastJobRun( +                    packageName, userId); +            final long bucketLength = mConstants.STANDBY_BEATS[appStandbyBucket]; +            final long bucketsAgo = timeSinceLastJob / bucketLength; + +            // If we haven't run any jobs for more than the app's current bucket period, just +            // consider anything new to be immediately runnable.  Otherwise, base it on the +            // bucket at which we last ran jobs. +            return (bucketsAgo > bucketLength) ? 0 : (getCurrentHeartbeat() - bucketsAgo); +        } + +        /**           * Returns a list of all pending jobs. A running job is not considered pending. Periodic           * jobs are always considered pending.           */ @@ -2139,10 +2168,14 @@ public final class JobSchedulerService extends com.android.server.SystemService              mUsageStats = usageStats;          } +        public long getTimeSinceLastJobRun(String packageName, final @UserIdInt int userId) { +            return mUsageStats.getTimeSinceLastJobRun(packageName, userId); +        } +          // AppIdleStateChangeListener interface for live updates          @Override -        public void onAppIdleStateChanged(final String packageName, final int userId, +        public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,                  boolean idle, int bucket) {              final int uid = mLocalPM.getPackageUid(packageName,                      PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index d9a5ff675475..08ff7bdb0eb8 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -414,8 +414,9 @@ public final class JobStatus {          int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,                  sourceUserId, elapsedNow);          JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); -        long currentHeartbeat = js != null ? js.currentHeartbeat() : 0; - +        long currentHeartbeat = js != null +                ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket) +                : 0;          return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,                  standbyBucket, currentHeartbeat, tag, 0,                  earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index e1e769cdfb16..db46c3d4df3d 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -305,7 +305,7 @@ public class KeySyncTask implements Runnable {              NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,              InvalidKeyException, InvalidAlgorithmParameterException {          PlatformKeyManager platformKeyManager = mPlatformKeyManagerFactory.newInstance(); -        PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId); +        PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId);;          Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys(                  mUserId, recoveryAgentUid, decryptKey.getGenerationId());          return WrappedKey.unwrapKeys(decryptKey, wrappedKeys); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java index 7005de5a6dd5..ee6a89312988 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java @@ -131,6 +131,7 @@ public class PlatformKeyManager {      /**       * Generates a new key and increments the generation ID. Should be invoked if the platform key       * is corrupted and needs to be rotated. +     * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}.       *       * @param userId The ID of the user to whose lock screen the platform key must be bound.       * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. @@ -158,6 +159,7 @@ public class PlatformKeyManager {      /**       * Returns the platform key used for encryption. +     * Tries to regenerate key one time if it is permanently invalid.       *       * @param userId The ID of the user to whose lock screen the platform key must be bound.       * @throws KeyStoreException if there was an AndroidKeyStore error. @@ -170,6 +172,30 @@ public class PlatformKeyManager {      public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException,             UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {          init(userId); +        try { +            return getEncryptKeyInternal(userId); +        } catch (UnrecoverableKeyException e) { +            Log.i(TAG, String.format(Locale.US, +                    "Regenerating permanently invalid Platform key for user %d.", +                    userId)); +            regenerate(userId); +            return getEncryptKeyInternal(userId); +        } +    } + +    /** +     * Returns the platform key used for encryption. +     * +     * @param userId The ID of the user to whose lock screen the platform key must be bound. +     * @throws KeyStoreException if there was an AndroidKeyStore error. +     * @throws UnrecoverableKeyException if the key could not be recovered. +     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. +     * @throws InsecureUserException if the user does not have a lock screen set. +     * +     * @hide +     */ +    private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException, +           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {          int generationId = getGenerationId(userId);          AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(                  getEncryptAlias(userId, generationId), /*password=*/ null); @@ -178,6 +204,7 @@ public class PlatformKeyManager {      /**       * Returns the platform key used for decryption. Only works after a recent screen unlock. +     * Tries to regenerate key one time if it is permanently invalid.       *       * @param userId The ID of the user to whose lock screen the platform key must be bound.       * @throws KeyStoreException if there was an AndroidKeyStore error. @@ -190,6 +217,30 @@ public class PlatformKeyManager {      public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,             UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {          init(userId); +        try { +            return getDecryptKeyInternal(userId); +        } catch (UnrecoverableKeyException e) { +            Log.i(TAG, String.format(Locale.US, +                    "Regenerating permanently invalid Platform key for user %d.", +                    userId)); +            regenerate(userId); +            return getDecryptKeyInternal(userId); +        } +    } + +    /** +     * Returns the platform key used for decryption. Only works after a recent screen unlock. +     * +     * @param userId The ID of the user to whose lock screen the platform key must be bound. +     * @throws KeyStoreException if there was an AndroidKeyStore error. +     * @throws UnrecoverableKeyException if the key could not be recovered. +     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. +     * @throws InsecureUserException if the user does not have a lock screen set. +     * +     * @hide +     */ +    private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException, +           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {          int generationId = getGenerationId(userId);          AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(                  getDecryptAlias(userId, generationId), /*password=*/ null); @@ -294,13 +345,7 @@ public class PlatformKeyManager {          String decryptAlias = getDecryptAlias(userId, generationId);          SecretKey secretKey = generateAesKey(); -        mKeyStore.setEntry( -                encryptAlias, -                new KeyStore.SecretKeyEntry(secretKey), -                new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) -                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM) -                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) -                    .build()); +        // Store Since decryption key first since it is more likely to fail.          mKeyStore.setEntry(                  decryptAlias,                  new KeyStore.SecretKeyEntry(secretKey), @@ -313,6 +358,14 @@ public class PlatformKeyManager {                      .setBoundToSpecificSecureUserId(userId)                      .build()); +        mKeyStore.setEntry( +                encryptAlias, +                new KeyStore.SecretKeyEntry(secretKey), +                new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) +                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM) +                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) +                    .build()); +          setGenerationId(userId, generationId);          try { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java index f2e71b37b7f9..b96208d66b01 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java @@ -22,6 +22,7 @@ import android.content.ContentValues;  import android.content.Context;  import android.database.Cursor;  import android.database.sqlite.SQLiteDatabase; +import android.security.keystore.recovery.RecoveryController;  import android.text.TextUtils;  import android.util.Log; @@ -289,8 +290,27 @@ public class RecoverableKeyStoreDb {          ContentValues values = new ContentValues();          values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId);          values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID, generationId); -        return db.replace( +        long result = db.replace(                  UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values); +        if (result != -1) { +            invalidateKeysWithOldGenerationId(userId, generationId); +        } +        return result; +    } + +    /** +     * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}. +     */ +    public void invalidateKeysWithOldGenerationId(int userId, int newGenerationId) { +        SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); +        ContentValues values = new ContentValues(); +        values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, +                RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); +        String selection = +                KeysEntry.COLUMN_NAME_USER_ID + " = ? AND " +                + KeysEntry.COLUMN_NAME_GENERATION_ID + " < ?"; +        db.update(KeysEntry.TABLE_NAME, values, selection, +            new String[] {String.valueOf(userId), String.valueOf(newGenerationId)});      }      /** diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index cf36166757e2..db831581c791 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -3763,12 +3763,8 @@ public final class PowerManagerService extends SystemService                  proto.write(PowerManagerServiceDumpProto.UidStateProto.UID_STRING, UserHandle.formatUid(uid));                  proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_ACTIVE, state.mActive);                  proto.write(PowerManagerServiceDumpProto.UidStateProto.NUM_WAKE_LOCKS, state.mNumWakeLocks); -                if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) { -                    proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_PROCESS_STATE_UNKNOWN, true); -                } else { -                    proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE, -                            ActivityManager.processStateAmToProto(state.mProcState)); -                } +                proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE, +                        ActivityManager.processStateAmToProto(state.mProcState));                  proto.end(uIDToken);              } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java index 7e05e46a2637..61a3c0951f64 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdater.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java @@ -507,22 +507,16 @@ class WebViewUpdater {          if (systemInterface.systemIsDebuggable()) {              return true;          } -        Signature[] packageSignatures;          // If no signature is declared, instead check whether the package is included in the          // system.          if (provider.signatures == null || provider.signatures.length == 0) {              return packageInfo.applicationInfo.isSystemApp();          } -        packageSignatures = packageInfo.signatures; -        if (packageSignatures.length != 1) -            return false; +        if (packageInfo.signatures.length != 1) return false; -        final byte[] packageSignature = packageSignatures[0].toByteArray();          // Return whether the package signature matches any of the valid signatures -        for (String signature : provider.signatures) { -            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT); -            if (Arrays.equals(packageSignature, validSignature)) -                return true; +        for (Signature signature : provider.signatures) { +            if (signature.equals(packageInfo.signatures[0])) return true;          }          return false;      } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index f79719c2cfdc..212a0d70927a 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -223,6 +223,27 @@ class TaskSnapshotController {              return null;          } +        if (top.hasCommittedReparentToAnimationLeash()) { +            if (DEBUG_SCREENSHOT) { +                Slog.w(TAG_WM, "Failed to take screenshot. App is animating " + top); +            } +            return null; +        } + +        final boolean hasVisibleChild = top.forAllWindows( +                // Ensure at least one window for the top app is visible before attempting to take +                // a screenshot. Visible here means that the WSA surface is shown and has an alpha +                // greater than 0. +                ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown() +                        && ws.mWinAnimator.mLastAlpha > 0f, true); + +        if (!hasVisibleChild) { +            if (DEBUG_SCREENSHOT) { +                Slog.w(TAG_WM, "Failed to take screenshot. No visible windows for " + task); +            } +            return null; +        } +          final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();          final float scaleFraction = isLowRamDevice ? REDUCED_SCALE : 1f;          task.getBounds(mTmpRect); @@ -233,7 +254,7 @@ class TaskSnapshotController {          if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {              if (DEBUG_SCREENSHOT) { -                Slog.w(TAG_WM, "Failed to take screenshot"); +                Slog.w(TAG_WM, "Failed to take screenshot for " + task);              }              return null;          } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a0b59efe6ced..1f9255a2b20f 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -100,6 +100,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<      /** Total number of elements in this subtree, including our own hierarchy element. */      private int mTreeWeight = 1; +    /** +     * Indicates whether we are animating and have committed the transaction to reparent our  +     * surface to the animation leash +     */ +    private boolean mCommittedReparentToAnimationLeash; +      WindowContainer(WindowManagerService service) {          mService = service;          mPendingTransaction = service.mTransactionFactory.make(); @@ -1025,12 +1031,24 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<       */      void prepareSurfaces() {          SurfaceControl.mergeToGlobalTransaction(getPendingTransaction()); + +        // If a leash has been set when the transaction was committed, then the leash reparent has +        // been committed. +        mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();          for (int i = 0; i < mChildren.size(); i++) {              mChildren.get(i).prepareSurfaces();          }      }      /** +     * @return true if the reparent to animation leash transaction has been committed, false +     * otherwise. +     */ +    boolean hasCommittedReparentToAnimationLeash() { +        return mCommittedReparentToAnimationLeash; +    } + +    /**       * Trigger a call to prepareSurfaces from the animation thread, such that       * mPendingTransaction will be applied.       */ diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 67bad0fab7c5..8fd5be2a45ff 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -358,6 +358,7 @@ struct GnssCallback : public IGnssCallback {      Return<void> gnssAcquireWakelockCb() override;      Return<void> gnssReleaseWakelockCb() override;      Return<void> gnssRequestTimeCb() override; +    Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;      Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;      // New in 1.1 @@ -472,6 +473,11 @@ Return<void> GnssCallback::gnssRequestTimeCb() {      return Void();  } +Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) { +    // TODO(b/72405645): call into java implementation +    return Void(); +} +  Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) {      ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java index b1bff70422d4..6fc9e082bb7c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyString;  import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow;  import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; @@ -48,6 +49,7 @@ import org.mockito.MockitoAnnotations;  import java.io.File;  import java.security.KeyStore; +import java.security.UnrecoverableKeyException;  import java.util.List;  @SmallTest @@ -258,6 +260,40 @@ public class PlatformKeyManagerTest {      }      @Test +    public void getEncryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception { +        doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( +                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), +                any()); + +        mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); + +        verify(mKeyStoreProxy).getKey( +                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), +                any()); +        // Attempt to get regenerated key. +        verify(mKeyStoreProxy).getKey( +                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), +                any()); +    } + +    @Test +    public void getDecryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception { +        doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( +                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), +                any()); + +        mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); + +        verify(mKeyStoreProxy).getKey( +                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), +                any()); +        // Attempt to get regenerated key. +        verify(mKeyStoreProxy).getKey( +                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), +                any()); +    } + +    @Test      public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {          mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index f0254c6d5dfe..097d2141d9e0 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -315,6 +315,29 @@ public class RecoverableKeyStoreDbTest {          assertThat(statuses).hasSize(0);      } +    public void testInvalidateKeysWithOldGenerationId_withSingleKey() { +        int userId = 12; +        int uid = 1009; +        int generationId = 6; +        int status = 120; +        int status2 = 121; +        String alias = "test"; +        byte[] nonce = getUtf8Bytes("nonce"); +        byte[] keyMaterial = getUtf8Bytes("keymaterial"); +        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status); +        mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey); + +        WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); +        assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status); + +        mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2); +        mRecoverableKeyStoreDb.invalidateKeysWithOldGenerationId(userId, generationId + 1); + +        retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); +        assertThat(retrievedKey.getRecoveryStatus()) +                .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); +    } +      @Test      public void setRecoveryServicePublicKey_replaceOldKey() throws Exception {          int userId = 12; diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index 88bae336b695..a1a6a5a4d5bb 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -110,6 +110,9 @@ public class EuiccCardManager {      /** Result code of execution with no error. */      public static final int RESULT_OK = 0; +    /** Result code of an unknown error. */ +    public static final int RESULT_UNKNOWN_ERROR = -1; +      /**       * Callback to receive the result of an eUICC card API.       *  |