diff options
39 files changed, 315 insertions, 145 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index bc6e9cd0ab7e..0ff3215e1271 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6416,17 +6416,7 @@ public class Activity extends ContextThemeWrapper       */      @Deprecated      public boolean requestVisibleBehind(boolean visible) { -        if (!mResumed) { -            // Do not permit paused or stopped activities to do this. -            visible = false; -        } -        try { -            mVisibleBehind = ActivityManager.getService() -                    .requestVisibleBehind(mToken, visible) && visible; -        } catch (RemoteException e) { -            mVisibleBehind = false; -        } -        return mVisibleBehind; +        return false;      }      /** diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index f398c8dc9d6a..aca2d9177835 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -360,6 +360,13 @@ public class ActivityManager {              FIRST_START_NON_FATAL_ERROR_CODE + 1;      /** +     * Result for IActivityManaqer.startActivity: a new activity start was aborted. Never returned +     * externally. +     * @hide +     */ +    public static final int START_ABORTED = FIRST_START_NON_FATAL_ERROR_CODE + 2; + +    /**       * Flag for IActivityManaqer.startActivity: do special start mode where       * a new activity is launched only if it is needed.       * @hide diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java index 8ec9622ebe34..8a083ebcd7e9 100644 --- a/core/java/android/app/ProgressDialog.java +++ b/core/java/android/app/ProgressDialog.java @@ -42,8 +42,12 @@ import java.text.NumberFormat;   *   * <p>The progress range is 0 to {@link #getMax() max}.</p>   * - * @deprecated Use a progress indicator such as ProgressBar inline inside of - * an activity rather than using this modal dialog. + * @deprecated <code>ProgressDialog</code> is a modal dialog, which prevents the + * user from interacting with the app. Instead of using this class, you should + * use a progress indicator like {@link android.widget.ProgressBar}, which can + * be embedded in your app's UI. Alternatively, you can use a + * <a href="/guide/topics/ui/notifiers/notifications.html">notification</a> + * to inform the user of the task's progress.   */  @Deprecated  public class ProgressDialog extends AlertDialog { diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java index 358787e66428..e9c958857d5c 100644 --- a/core/java/android/content/pm/LauncherActivityInfo.java +++ b/core/java/android/content/pm/LauncherActivityInfo.java @@ -20,12 +20,10 @@ import android.content.ComponentName;  import android.content.Context;  import android.content.pm.PackageManager.NameNotFoundException;  import android.content.res.Resources; -import android.graphics.drawable.BitmapDrawable;  import android.graphics.drawable.Drawable;  import android.os.UserHandle;  import android.os.UserManager;  import android.util.DisplayMetrics; -import android.util.Log;  /**   * A representation of an activity that can belong to this user or a managed @@ -173,12 +171,6 @@ public class LauncherActivityInfo {      public Drawable getBadgedIcon(int density) {          Drawable originalIcon = getIcon(density); -        if (originalIcon instanceof BitmapDrawable) { -            // TODO: Go through LauncherAppsService -            return mPm.getUserBadgedIcon(originalIcon, mUser); -        } else { -            Log.e(TAG, "Unable to create badged icon for " + mActivityInfo); -        } -        return originalIcon; +        return mPm.getUserBadgedIcon(originalIcon, mUser);      }  } diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 951aa8df9ea3..8691136dfedc 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -30,8 +30,9 @@ import java.net.UnknownHostException;  /**   * API for sending log output.   * - * <p>Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e() - * methods. + * <p>Generally, you should use the {@link #v Log.v()}, {@link #d Log.d()}, + * {@link #i Log.i()}, {@link #w Log.w()}, and {@link #e Log.e()} methods to write logs. + * You can then <a href="{@docRoot}studio/debug/am-logcat.html">view the logs in logcat</a>.   *   * <p>The order in terms of verbosity, from least to most is   * ERROR, WARN, INFO, DEBUG, VERBOSE.  Verbose should never be compiled diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index b035b7fd53ed..a19f05c6ae38 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -491,10 +491,10 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb          if (myHeight <= 0) myHeight = getHeight();          final boolean formatChanged = mFormat != mRequestedFormat; -        final boolean creating = (mSurfaceControl == null || formatChanged) +        final boolean visibleChanged = mVisible != mRequestedVisible; +        final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)                  && mRequestedVisible;          final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight; -        final boolean visibleChanged = mVisible != mRequestedVisible;          final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;          boolean redrawNeeded = false; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 488216595a3e..25c02d17f046 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -724,6 +724,8 @@ import java.util.function.Predicate;   * @attr ref android.R.styleable#View_nextFocusUp   * @attr ref android.R.styleable#View_onClick   * @attr ref android.R.styleable#View_padding + * @attr ref android.R.styleable#View_paddingHorizontal + * @attr ref android.R.styleable#View_paddingVertical   * @attr ref android.R.styleable#View_paddingBottom   * @attr ref android.R.styleable#View_paddingLeft   * @attr ref android.R.styleable#View_paddingRight diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 66df335f07da..1dbc1aca88c5 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -7608,6 +7608,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager       * See       * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}       * for a list of all child view attributes that this class supports. +     * +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart +     * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd       */      public static class MarginLayoutParams extends ViewGroup.LayoutParams {          /** diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 5b04f41c7ee2..e1e8317d8ccb 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -741,7 +741,8 @@ public final class AutofillManager {      }      /** -     * Returns {@code true} if Autofill is supported for this user. +     * Returns {@code true} if autofill is supported by the current device and +     * is supported for this user.       *       * <p>Autofill is typically supported, but it could be unsupported in cases like:       * <ol> diff --git a/core/java/com/android/internal/backup/package.html b/core/java/com/android/internal/backup/package.html new file mode 100644 index 000000000000..db6f78bbf628 --- /dev/null +++ b/core/java/com/android/internal/backup/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/core/java/com/android/internal/inputmethod/package.html b/core/java/com/android/internal/inputmethod/package.html new file mode 100644 index 000000000000..db6f78bbf628 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/core/java/com/android/internal/logging/package.html b/core/java/com/android/internal/logging/package.html new file mode 100644 index 000000000000..db6f78bbf628 --- /dev/null +++ b/core/java/com/android/internal/logging/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/core/java/com/android/internal/os/package.html b/core/java/com/android/internal/os/package.html new file mode 100644 index 000000000000..db6f78bbf628 --- /dev/null +++ b/core/java/com/android/internal/os/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 8fe9100d2011..544afd993b37 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -3103,12 +3103,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {      }      /** +     * Check if Setup or Post-Setup update is completed on TV +     * @return true if completed +     */ +    private boolean isTvUserSetupComplete() { +        boolean isTvSetupComplete = Settings.Secure.getInt(getContext().getContentResolver(), +                Settings.Secure.USER_SETUP_COMPLETE, 0) != 0; +        isTvSetupComplete &= Settings.Secure.getInt(getContext().getContentResolver(), +                Settings.Secure.TV_USER_SETUP_COMPLETE, 0) != 0; +        return isTvSetupComplete; +    } + +    /**       * Helper method for adding launch-search to most applications. Opens the       * search window using default settings.       *       * @return true if search window opened       */      private boolean launchDefaultSearch(KeyEvent event) { +        if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK) +                && !isTvUserSetupComplete()) { +            // If we are in Setup or Post-Setup update mode on TV, consume the search key +            return false; +        }          boolean result;          final Callback cb = getCallback();          if (cb == null || isDestroyed()) { diff --git a/core/java/com/android/internal/statusbar/package.html b/core/java/com/android/internal/statusbar/package.html new file mode 100644 index 000000000000..db6f78bbf628 --- /dev/null +++ b/core/java/com/android/internal/statusbar/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/core/java/com/android/internal/widget/package.html b/core/java/com/android/internal/widget/package.html new file mode 100644 index 000000000000..db6f78bbf628 --- /dev/null +++ b/core/java/com/android/internal/widget/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index 2e9a6e895d8a..c19c1a11e3e2 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -457,11 +457,13 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {      return *this;  } -GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) { +GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform, +        bool requiresFilter) {      TRIGGER_STAGE(kFillStage);      REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); -    mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, &textureTransform }; +    GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST; +    mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, &textureTransform };      setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap,              nullptr, nullptr); diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 87b1568ed72b..6d11da19e138 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -75,7 +75,8 @@ public:      GlopBuilder& setFillTextureLayer(GlLayer& layer, float alpha);      // TODO: setFillLayer normally forces its own wrap & filter mode,      // which isn't always correct. -    GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform); +    GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform, +            bool requiresFilter);      GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags); diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp index c460c0d2dfd4..51927d5a2c61 100644 --- a/libs/hwui/OpenGLReadback.cpp +++ b/libs/hwui/OpenGLReadback.cpp @@ -191,6 +191,7 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,              GL_TEXTURE_2D, texture, 0);      { +        bool requiresFilter;          // Draw & readback          renderState.setViewport(destWidth, destHeight);          renderState.scissor().setEnabled(false); @@ -208,12 +209,17 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,              croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),                      srcRect.getHeight() / sourceTexture.height(), 1);              croppedTexTransform.multiply(sFlipV); +            requiresFilter = srcRect.getWidth() != (float) destWidth +                    || srcRect.getHeight() != (float) destHeight; +        } else { +            requiresFilter = sourceTexture.width() != (uint32_t) destWidth +                    || sourceTexture.height() != (uint32_t) destHeight;          }          Glop glop;          GlopBuilder(renderState, caches, &glop)                  .setRoundRectClipState(nullptr)                  .setMeshTexturedUnitQuad(nullptr) -                .setFillExternalTexture(sourceTexture, croppedTexTransform) +                .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter)                  .setTransform(Matrix4::identity(), TransformFlags::None)                  .setModelViewMapUnitToRect(Rect(destWidth, destHeight))                  .build(); diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index 3b29a6cd7b6c..1e262314284d 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -77,7 +77,7 @@ public class DeviceDiscoveryService extends Service {      private BluetoothAdapter mBluetoothAdapter;      private WifiManager mWifiManager; -    private BluetoothLeScanner mBLEScanner; +    @Nullable private BluetoothLeScanner mBLEScanner;      private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();      private List<DeviceFilter<?>> mFilters; @@ -185,7 +185,7 @@ public class DeviceDiscoveryService extends Service {              mBluetoothAdapter.startDiscovery();          } -        if (shouldScan(mBLEFilters)) { +        if (shouldScan(mBLEFilters) && mBLEScanner != null) {              mBLEScanCallback = new BLEScanCallback();              mBLEScanner.startScan(mBLEScanFilters, mDefaultScanSettings, mBLEScanCallback);          } @@ -224,7 +224,7 @@ public class DeviceDiscoveryService extends Service {              unregisterReceiver(mBluetoothBroadcastReceiver);              mBluetoothBroadcastReceiver = null;          } -        mBLEScanner.stopScan(mBLEScanCallback); +        if (mBLEScanner != null) mBLEScanner.stopScan(mBLEScanCallback);          if (mWifiBroadcastReceiver != null) {              unregisterReceiver(mWifiBroadcastReceiver);              mWifiBroadcastReceiver = null; diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f66a09e04192..4245b1183e08 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -776,7 +776,4 @@      <dimen name="qs_gutter_height">6dp</dimen> -    <!-- Width of the hollow triangle for empty signal state --> -    <dimen name="mobile_signal_empty_strokewidth">2dp</dimen> -  </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java index c43820d5a8fc..f5c82a778eb6 100644 --- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java +++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java @@ -28,10 +28,8 @@ import android.graphics.Rect;  import android.graphics.Typeface;  import android.os.PowerManager;  import android.os.SystemClock; -import android.os.UserHandle;  import android.provider.Settings;  import android.text.InputType; -import android.text.TextUtils;  import android.util.AttributeSet;  import android.view.Gravity;  import android.view.View; @@ -248,9 +246,9 @@ public class PasswordTextView extends View {              mText = mText.substring(0, length - 1);              CharState charState = mTextChars.get(length - 1);              charState.startRemoveAnimation(0, 0); +            sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);          }          userActivity(); -        sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);      }      public String getText() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java index c09da2183076..bd4a1df246f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java @@ -417,7 +417,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl      @Override      public void onHeightUpdate() { -        if (mParent == null || mMenuItems.size() == 0) { +        if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {              return;          }          int parentHeight = mParent.getCollapsedHeight(); @@ -477,7 +477,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl      private void setMenuLocation() {          boolean showOnLeft = mTranslation > 0; -        if ((mIconsPlaced && showOnLeft == mOnLeft) || mSnapping +        if ((mIconsPlaced && showOnLeft == mOnLeft) || mSnapping || mMenuContainer == null                  || !mMenuContainer.isAttachedToWindow()) {              // Do nothing              return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java index 983a79615304..1c34b7de2d4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java @@ -85,12 +85,8 @@ public class SignalDrawable extends Drawable {              {-1.9f / VIEWPORT, -1.9f / VIEWPORT},      }; -    // The easiest way to understand this is as if we set Style.STROKE and draw the triangle, -    // but that is only theoretically right. Instead, draw the triangle and clip out a smaller -    // one inset by this amount. -    private final float mEmptyStrokeWidth;      private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f); -    private final float mEmptyDiagInset;  // == mEmptyStrokeWidth * INV_TAN +    private static final float CUT_WIDTH_DP = 1f / 12f;      private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);      private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -126,11 +122,6 @@ public class SignalDrawable extends Drawable {                  Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill);          mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size); -        // mCutPath parameters -        mEmptyStrokeWidth = context.getResources() -                .getDimensionPixelSize(R.dimen.mobile_signal_empty_strokewidth); -        mEmptyDiagInset = mEmptyStrokeWidth * INV_TAN; -          mHandler = new Handler();          setDarkIntensity(0);      } @@ -262,20 +253,22 @@ public class SignalDrawable extends Drawable {          }          if (mState == STATE_EMPTY) { +            final float cutWidth = CUT_WIDTH_DP * height; +            final float cutDiagInset = cutWidth * INV_TAN; +              // Cut out a smaller triangle from the center of mFullPath              mCutPath.reset();              mCutPath.setFillType(FillType.WINDING); -            mCutPath.moveTo(width - padding - mEmptyStrokeWidth, -                    height - padding - mEmptyStrokeWidth); -            mCutPath.lineTo(width - padding - mEmptyStrokeWidth, padding + mEmptyDiagInset); -            mCutPath.lineTo(padding + mEmptyDiagInset, height - padding - mEmptyStrokeWidth); -            mCutPath.lineTo(width - padding - mEmptyStrokeWidth, -                    height - padding - mEmptyStrokeWidth); - -            // In empty state, draw the full path as the foreground paint -            mForegroundPath.set(mFullPath); -            mFullPath.reset(); -            mForegroundPath.op(mCutPath, Path.Op.DIFFERENCE); +            mCutPath.moveTo(width - padding - cutWidth, +                    height - padding - cutWidth); +            mCutPath.lineTo(width - padding - cutWidth, padding + cutDiagInset); +            mCutPath.lineTo(padding + cutDiagInset, height - padding - cutWidth); +            mCutPath.lineTo(width - padding - cutWidth, +                    height - padding - cutWidth); + +            // Draw empty state as only background +            mForegroundPath.reset(); +            mFullPath.op(mCutPath, Path.Op.DIFFERENCE);          } else if (mState == STATE_AIRPLANE) {              // Airplane mode is slashed, full-signal              mForegroundPath.set(mFullPath); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index efce87177faa..14868e07d446 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -334,6 +334,10 @@ public class MobileSignalController extends SignalController<      }      private boolean isRoaming() { +        // During a carrier change, roaming indications need to be supressed. +        if (isCarrierNetworkChangeActive()) { +            return false; +        }          if (isCdma()) {              final int iconMode = mServiceState.getCdmaEriIconMode();              return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java index e0d8042238d2..4aa987738572 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java @@ -57,4 +57,10 @@ public class NotificationMenuRowTest extends LeakCheckedTest {          row.createMenu(null);          assertTrue(row.getMenuView() != null);      } + +    @Test +    public void testResetUncreatedMenu() { +        NotificationMenuRowPlugin row = new NotificationMenuRow(mContext); +        row.resetMenu(); +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 1627925ae1bc..15186dc2c701 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -496,6 +496,79 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {                DEFAULT_ICON /* typeIcon */);      } +    @Test +    public void testCarrierNetworkChange_roamingBeforeNetworkChange() { +      int strength = SignalStrength.SIGNAL_STRENGTH_GREAT; + +      setupDefaultSignal(); +      setLevel(strength); +      setGsmRoaming(true); + +      // Verify baseline +      verifyLastMobileDataIndicators(true /* visible */, +              strength /* strengthIcon */, +              DEFAULT_ICON /* typeIcon */, +              true /* roaming */); + +      // API call is made +      setCarrierNetworkChange(true /* enabled */); + +      // Carrier network change is true, show special indicator, no roaming. +      verifyLastMobileDataIndicators(true /* visible */, +              SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), +              0 /* typeIcon */, +              false /* roaming */); + +      // Revert back +      setCarrierNetworkChange(false /* enabled */); + +      // Verify back in previous state +      verifyLastMobileDataIndicators(true /* visible */, +              strength /* strengthIcon */, +              DEFAULT_ICON /* typeIcon */, +              true /* roaming */); +    } + +    @Test +    public void testCarrierNetworkChange_roamingAfterNetworkChange() { +      int strength = SignalStrength.SIGNAL_STRENGTH_GREAT; + +      setupDefaultSignal(); +      setLevel(strength); + +      // Verify baseline +      verifyLastMobileDataIndicators(true /* visible */, +              strength /* strengthIcon */, +              DEFAULT_ICON /* typeIcon */, +              false /* roaming */); + +      // API call is made +      setCarrierNetworkChange(true /* enabled */); + +      // Carrier network change is true, show special indicator, no roaming. +      verifyLastMobileDataIndicators(true /* visible */, +              SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), +              0 /* typeIcon */, +              false /* roaming */); + +      setGsmRoaming(true); + +      // Roaming should not show. +      verifyLastMobileDataIndicators(true /* visible */, +              SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), +              0 /* typeIcon */, +              false /* roaming */); + +      // Revert back +      setCarrierNetworkChange(false /* enabled */); + +      // Verify back in previous state +      verifyLastMobileDataIndicators(true /* visible */, +              strength /* strengthIcon */, +              DEFAULT_ICON /* typeIcon */, +              true /* roaming */); +    } +      private void verifyEmergencyOnly(boolean isEmergencyOnly) {          ArgumentCaptor<Boolean> emergencyOnly = ArgumentCaptor.forClass(Boolean.class);          Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setEmergencyCallsOnly( diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 9e4d89cbc9c5..0e42e6d6a83d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -271,6 +271,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo      private void processKeyEvent(EventStreamState state, KeyEvent event, int policyFlags) {          if (!state.shouldProcessKeyEvent(event)) { +            super.onInputEvent(event, policyFlags);              return;          }          mEventHandler.onKeyEvent(event, policyFlags); diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 30de4baf3460..6f6e1b721487 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -5666,13 +5666,15 @@ public class BackupManagerService {                  PerformFullTransportBackupTask pftbt = null;                  synchronized (mQueueLock) {                      if (mRunningFullBackupTask != null) { -                        if (DEBUG_SCHEDULING) { -                            Slog.i(TAG, "Telling running backup to stop"); -                        }                          pftbt = mRunningFullBackupTask;                      }                  } -                pftbt.handleCancel(true); +                if (pftbt != null) { +                    if (DEBUG_SCHEDULING) { +                        Slog.i(TAG, "Telling running backup to stop"); +                    } +                    pftbt.handleCancel(true); +                }              }          };          new Thread(endFullBackupRunnable, "end-full-backup").start(); diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 4810f4fe8c82..f47b0d3c6e73 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -383,7 +383,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind                                      findDeviceCallback,                                      getServiceCallback());                  } catch (RemoteException e) { -                    throw new RuntimeException(e); +                    Log.e(LOG_TAG, "Error while initiating device discovery", e);                  }              } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 61057dd25444..75206e48aa8b 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -86,6 +86,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {      private static final int ACTIVE_LOG_MAX_SIZE = 20;      private static final int CRASH_LOG_MAX_SIZE = 100;      private static final String REASON_AIRPLANE_MODE = "airplane mode"; +    private static final String REASON_DISALLOWED = "disallowed by system"; +    private static final String REASON_SHARING_DISALLOWED = "sharing disallowed by system";      private static final String REASON_RESTARTED = "automatic restart";      private static final String REASON_START_CRASH = "turn-on crash";      private static final String REASON_SYSTEM_BOOT = "system boot"; @@ -227,25 +229,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub {          @Override          public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,                  Bundle prevRestrictions) { -            if (!UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, -                    UserManager.DISALLOW_BLUETOOTH, UserManager.DISALLOW_BLUETOOTH_SHARING)) { -                return; // No relevant changes, nothing to do. -            } -            final boolean disallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH); +            if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, +                    UserManager.DISALLOW_BLUETOOTH_SHARING)) { +                updateOppLauncherComponentState(userId, newRestrictions.getBoolean( +                        UserManager.DISALLOW_BLUETOOTH_SHARING)); +            } -            // DISALLOW_BLUETOOTH is a global restriction that can only be set by DO or PO on the -            // system user, so we only look at the system user. -            if (userId == UserHandle.USER_SYSTEM && disallowed && (mEnable || mEnableExternal)) { -                try { -                    disable(null /* packageName */, true /* persist */); -                } catch (RemoteException e) { -                    Slog.w(TAG, "Exception when disabling Bluetooth", e); +            // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user. +            if (userId == UserHandle.USER_SYSTEM && +                UserRestrictionsUtils.restrictionsChanged( +                    prevRestrictions, newRestrictions, UserManager.DISALLOW_BLUETOOTH)) { +                if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean( +                        UserManager.DISALLOW_BLUETOOTH)) { +                    updateOppLauncherComponentState(userId, true); // Sharing disallowed +                    sendDisableMsg(REASON_DISALLOWED); +                } else { +                    updateOppLauncherComponentState(userId, newRestrictions.getBoolean( +                            UserManager.DISALLOW_BLUETOOTH_SHARING));                  }              } -            final boolean sharingDisallowed = disallowed -                    || newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING); -            updateOppLauncherComponentState(userId, sharingDisallowed);          }      }; @@ -2118,7 +2121,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {                  : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;          try {              final IPackageManager imp = AppGlobals.getPackageManager(); -            imp.setComponentEnabledSetting(oppLauncherComponent, newState, 0 /* flags */, userId); +            imp.setComponentEnabledSetting(oppLauncherComponent, newState, +                    PackageManager.DONT_KILL_APP, userId);          } catch (Exception e) {              // The component was not found, do nothing.          } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 607b84c4658e..186d0f40f43a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.CHANGE_CONFIGURATION;  import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;  import static android.Manifest.permission.INTERACT_ACROSS_USERS;  import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;  import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;  import static android.Manifest.permission.READ_FRAME_BUFFER;  import static android.Manifest.permission.START_TASKS_FROM_RECENTS; @@ -10228,7 +10229,7 @@ public class ActivityManagerService extends IActivityManager.Stub      @Override      public void moveStackToDisplay(int stackId, int displayId) { -        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveStackToDisplay()"); +        enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");          synchronized (this) {              final long ident = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index fe0e07efe9bc..3de203669032 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -16,6 +16,7 @@  package com.android.server.am; +import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;  import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;  import static android.Manifest.permission.START_ANY_ACTIVITY;  import static android.Manifest.permission.START_TASKS_FROM_RECENTS; @@ -38,11 +39,13 @@ import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCRE  import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;  import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;  import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Process.SYSTEM_UID;  import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;  import static android.view.Display.DEFAULT_DISPLAY;  import static android.view.Display.FLAG_PRIVATE;  import static android.view.Display.INVALID_DISPLAY;  import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT; +import static android.view.Display.TYPE_VIRTUAL;  import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN;  import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; @@ -1678,6 +1681,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D              return false;          } +        // Check if the caller can manage activity stacks. +        final int startAnyPerm = mService.checkPermission(INTERNAL_SYSTEM_WINDOW, callingPid, +                callingUid); +        if (startAnyPerm == PERMISSION_GRANTED) { +            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" +                    + " allow launch any on display"); +            return true; +        } + +        if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL +                && activityDisplay.mDisplay.getOwnerUid() != SYSTEM_UID) { +            // Limit launching on virtual displays, because their contents can be read from Surface +            // by apps that created them. +            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" +                    + " disallow launch on virtual display for not-embedded activity"); +            return false; +        } +          if (!activityDisplay.isPrivate()) {              // Anyone can launch on a public display.              if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" @@ -1699,15 +1720,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D              return true;          } -        // Check if the caller can manage activity stacks. -        final int startAnyPerm = mService.checkPermission(MANAGE_ACTIVITY_STACKS, callingPid, -                callingUid); -        if (startAnyPerm == PERMISSION_GRANTED) { -            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" -                    + " allow launch any on display"); -            return true; -        } -          Slog.w(TAG, "Launch on display check: denied");          return false;      } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index a145435976fa..a31c33e4ab91 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -17,6 +17,7 @@  package com.android.server.am;  import static android.app.Activity.RESULT_CANCELED; +import static android.app.ActivityManager.START_ABORTED;  import static android.app.ActivityManager.START_CANCELED;  import static android.app.ActivityManager.START_CLASS_NOT_FOUND;  import static android.app.ActivityManager.START_DELIVERED_TO_TOP; @@ -279,7 +280,9 @@ class ActivityStarter {              // mLastStartActivityRecord[0] is set in the call to startActivity above.              outActivity[0] = mLastStartActivityRecord[0];          } -        return mLastStartActivityResult; + +        // Aborted results are treated as successes externally, but we must track them internally. +        return mLastStartActivityResult != START_ABORTED ? mLastStartActivityResult : START_SUCCESS;      }      /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */ @@ -465,7 +468,7 @@ class ActivityStarter {              // We pretend to the caller that it was really started, but              // they will just get a cancel result.              ActivityOptions.abort(options); -            return START_SUCCESS; +            return START_ABORTED;          }          // If permissions need a review before any of the app components can run, we diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index f3a292b7e1e0..20d7b28c55e1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1018,7 +1018,7 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            ResolveInfo ri = mInterface.resolveIntent(intent, null, 0, mTargetUser); +            ResolveInfo ri = mInterface.resolveIntent(intent, intent.getType(), 0, mTargetUser);              PrintWriter pw = getOutPrintWriter();              if (ri == null) {                  pw.println("No activity found"); @@ -1040,7 +1040,7 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, null, 0, +            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, intent.getType(), 0,                      mTargetUser).getList();              PrintWriter pw = getOutPrintWriter();              if (result == null || result.size() <= 0) { @@ -1074,7 +1074,7 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            List<ResolveInfo> result = mInterface.queryIntentServices(intent, null, 0, +            List<ResolveInfo> result = mInterface.queryIntentServices(intent, intent.getType(), 0,                      mTargetUser).getList();              PrintWriter pw = getOutPrintWriter();              if (result == null || result.size() <= 0) { @@ -1108,7 +1108,7 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, null, 0, +            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, intent.getType(), 0,                      mTargetUser).getList();              PrintWriter pw = getOutPrintWriter();              if (result == null || result.size() <= 0) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8112f9998c58..4477e5a0f173 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1689,8 +1689,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {      }      boolean isUserSetupComplete() { -        return Settings.Secure.getIntForUser(mContext.getContentResolver(), +        boolean isSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),                  Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; +        if (mHasFeatureLeanback) { +            isSetupComplete &= isTvUserSetupComplete(); +        } +        return isSetupComplete; +    } + +    private boolean isTvUserSetupComplete() { +        return Settings.Secure.getIntForUser(mContext.getContentResolver(), +                Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;      }      private void handleShortPressOnHome() { diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 5f34c6067997..4e4398ee9d91 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -614,7 +614,7 @@ public class AppWindowContainerController              return STARTING_WINDOW_TYPE_SPLASH_SCREEN;          } else if (taskSwitch && allowTaskSnapshot) {              return snapshot == null ? STARTING_WINDOW_TYPE_NONE -                    : snapshotOrientationSameAsDisplay(snapshot) || fromRecents +                    : snapshotOrientationSameAsTask(snapshot) || fromRecents                              ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;          } else {              return STARTING_WINDOW_TYPE_NONE; @@ -640,24 +640,11 @@ public class AppWindowContainerController          return true;      } -    private boolean snapshotOrientationSameAsDisplay(TaskSnapshot snapshot) { +    private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {          if (snapshot == null) {              return false;          } -        final Rect rect = new Rect(0, 0, snapshot.getSnapshot().getWidth(), -                snapshot.getSnapshot().getHeight()); -        rect.inset(snapshot.getContentInsets()); -        final Rect taskBoundsWithoutInsets = new Rect(); -        mContainer.getTask().getBounds(taskBoundsWithoutInsets); -        final DisplayInfo di = mContainer.getDisplayContent().getDisplayInfo(); -        final Rect displayBounds = new Rect(0, 0, di.logicalWidth, di.logicalHeight); -        final Rect stableInsets = new Rect(); -        mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, -                stableInsets); -        displayBounds.inset(stableInsets); -        final boolean snapshotInLandscape = rect.width() >= rect.height(); -        final boolean displayInLandscape = displayBounds.width() >= displayBounds.height(); -        return snapshotInLandscape == displayInLandscape; +        return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();      }      public void removeStartingWindow() { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java index 70c7e586d3fe..608635491849 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java @@ -25,8 +25,8 @@ import android.os.Handler;  import android.os.Looper;  import android.os.Message;  import android.os.SystemClock; -import android.util.Log;  import android.util.LongSparseArray; +import android.util.Slog;  import com.android.internal.annotations.GuardedBy; @@ -60,16 +60,21 @@ final class NetworkLoggingHandler extends Handler {      /** Delay after which older batches get discarded after a retrieval. */      private static final long RETRIEVED_BATCH_DISCARD_DELAY_MS = 5 * 60 * 1000; // 5m +    /** Do not call into mDpm with locks held */      private final DevicePolicyManagerService mDpm;      private final AlarmManager mAlarmManager;      private final OnAlarmListener mBatchTimeoutAlarmListener = new OnAlarmListener() {          @Override          public void onAlarm() { -            Log.d(TAG, "Received a batch finalization timeout alarm, finalizing " +            Slog.d(TAG, "Received a batch finalization timeout alarm, finalizing "                      + mNetworkEvents.size() + " pending events."); +            Bundle notificationExtras = null;              synchronized (NetworkLoggingHandler.this) { -                finalizeBatchAndNotifyDeviceOwnerLocked(); +                notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked(); +            } +            if (notificationExtras != null) { +                notifyDeviceOwner(notificationExtras);              }          }      }; @@ -110,17 +115,21 @@ final class NetworkLoggingHandler extends Handler {              case LOG_NETWORK_EVENT_MSG: {                  final NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);                  if (networkEvent != null) { +                    Bundle notificationExtras = null;                      synchronized (NetworkLoggingHandler.this) {                          mNetworkEvents.add(networkEvent);                          if (mNetworkEvents.size() >= MAX_EVENTS_PER_BATCH) { -                            finalizeBatchAndNotifyDeviceOwnerLocked(); +                            notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked();                          }                      } +                    if (notificationExtras != null) { +                        notifyDeviceOwner(notificationExtras); +                    }                  }                  break;              }              default: { -                Log.d(TAG, "NetworkLoggingHandler received an unknown of message."); +                Slog.d(TAG, "NetworkLoggingHandler received an unknown of message.");                  break;              }          } @@ -133,40 +142,48 @@ final class NetworkLoggingHandler extends Handler {          mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when,                  BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS, NETWORK_LOGGING_TIMEOUT_ALARM_TAG,                  mBatchTimeoutAlarmListener, this); -        Log.d(TAG, "Scheduled a new batch finalization alarm " + BATCH_FINALIZATION_TIMEOUT_MS +        Slog.d(TAG, "Scheduled a new batch finalization alarm " + BATCH_FINALIZATION_TIMEOUT_MS                  + "ms from now.");      }      synchronized void pause() { -        Log.d(TAG, "Paused network logging"); +        Slog.d(TAG, "Paused network logging");          mPaused = true;      } -    synchronized void resume() { -        if (!mPaused) { -            Log.d(TAG, "Attempted to resume network logging, but logging is not paused."); -            return; -        } +    void resume() { +        Bundle notificationExtras = null; +        synchronized (this) { +            if (!mPaused) { +                Slog.d(TAG, "Attempted to resume network logging, but logging is not paused."); +                return; +            } -        Log.d(TAG, "Resumed network logging. Current batch=" + mCurrentBatchToken -                + ", LastRetrievedBatch=" + mLastRetrievedBatchToken); -        mPaused = false; +            Slog.d(TAG, "Resumed network logging. Current batch=" + mCurrentBatchToken +                    + ", LastRetrievedBatch=" + mLastRetrievedBatchToken); +            mPaused = false; -        // If there is a batch ready that the device owner hasn't been notified about, do it now. -        if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) { -            scheduleBatchFinalization(); -            notifyDeviceOwnerLocked(); +            // If there is a batch ready that the device owner hasn't been notified about, do it now. +            if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) { +                scheduleBatchFinalization(); +                notificationExtras = buildDeviceOwnerMessageLocked(); +            } +        } +        if (notificationExtras != null) { +            notifyDeviceOwner(notificationExtras);          }      }      synchronized void discardLogs() {          mBatches.clear();          mNetworkEvents = new ArrayList<>(); -        Log.d(TAG, "Discarded all network logs"); +        Slog.d(TAG, "Discarded all network logs");      }      @GuardedBy("this") -    private void finalizeBatchAndNotifyDeviceOwnerLocked() { +    /** @returns extras if a message should be sent to the device owner */ +    private Bundle finalizeBatchAndBuildDeviceOwnerMessageLocked() { +        Bundle notificationExtras = null;          if (mNetworkEvents.size() > 0) {              // Finalize the batch and start a new one from scratch.              if (mBatches.size() >= MAX_BATCHES) { @@ -177,27 +194,39 @@ final class NetworkLoggingHandler extends Handler {              mBatches.append(mCurrentBatchToken, mNetworkEvents);              mNetworkEvents = new ArrayList<>();              if (!mPaused) { -                notifyDeviceOwnerLocked(); +                notificationExtras = buildDeviceOwnerMessageLocked();              }          } else {              // Don't notify the DO, since there are no events; DPC can still retrieve              // the last full batch if not paused. -            Log.d(TAG, "Was about to finalize the batch, but there were no events to send to" +            Slog.d(TAG, "Was about to finalize the batch, but there were no events to send to"                      + " the DPC, the batchToken of last available batch: " + mCurrentBatchToken);          }          // Regardless of whether the batch was non-empty schedule a new finalization after timeout.          scheduleBatchFinalization(); +        return notificationExtras;      } -    /** Sends a notification to the DO. Should only be called when there is a batch available. */      @GuardedBy("this") -    private void notifyDeviceOwnerLocked() { +    /** Build extras notification to the DO. Should only be called when there +        is a batch available. */ +    private Bundle buildDeviceOwnerMessageLocked() {          final Bundle extras = new Bundle();          final int lastBatchSize = mBatches.valueAt(mBatches.size() - 1).size();          extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentBatchToken);          extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, lastBatchSize); -        Log.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: " -                + mCurrentBatchToken); +        return extras; +    } + +    /** Sends a notification to the DO. Should not hold locks as DevicePolicyManagerService may +        call into NetworkLoggingHandler. */ +    private void notifyDeviceOwner(Bundle extras) { +        Slog.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: " +                + extras.getLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, -1)); +        if (Thread.holdsLock(this)) { +            Slog.wtfStack(TAG, "Shouldn't be called with NetworkLoggingHandler lock held"); +            return; +        }          mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras);      } diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 2c43598b9af7..a21422394ab1 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -406,7 +406,7 @@ public class TetheringTest {          when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);          // Emulate pressing the WiFi tethering button. -        mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false); +        mTethering.startTethering(TETHERING_WIFI, null, false);          mLooper.dispatchAll();          verify(mWifiManager, times(1)).startSoftAp(null);          verifyNoMoreInteractions(mWifiManager);  |