Merge "Remove stack scroller references from StatusBar"
diff --git a/Android.bp b/Android.bp
index 1586440..07b3018 100644
--- a/Android.bp
+++ b/Android.bp
@@ -495,6 +495,8 @@
"telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl",
"telephony/java/android/telephony/data/IDataService.aidl",
"telephony/java/android/telephony/data/IDataServiceCallback.aidl",
+ "telephony/java/android/telephony/data/IQualifiedNetworksService.aidl",
+ "telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl",
"telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl",
"telephony/java/android/telephony/ims/aidl/IImsCapabilityCallback.aidl",
"telephony/java/android/telephony/ims/aidl/IImsConfig.aidl",
@@ -1524,6 +1526,10 @@
api_file: "api/current.txt",
removed_api_file: "api/removed.txt",
},
+ last_released: {
+ api_file: ":last-released-public-api",
+ removed_api_file: "api/removed.txt",
+ },
},
}
@@ -1544,6 +1550,10 @@
api_file: "api/system-current.txt",
removed_api_file: "api/system-removed.txt",
},
+ last_released: {
+ api_file: ":last-released-system-api",
+ removed_api_file: "api/system-removed.txt",
+ },
},
}
diff --git a/api/current.txt b/api/current.txt
index fc595ac..e9f5756 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14726,6 +14726,22 @@
method public void setColorFilter(android.graphics.ColorFilter);
}
+ public class ColorStateListDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+ ctor public ColorStateListDrawable();
+ ctor public ColorStateListDrawable(android.content.res.ColorStateList);
+ method public void clearAlpha();
+ method public void draw(android.graphics.Canvas);
+ method public android.content.res.ColorStateList getColorStateList();
+ method public int getOpacity();
+ method public boolean hasFocusStateSpecified();
+ method public void invalidateDrawable(android.graphics.drawable.Drawable);
+ method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+ method public void setAlpha(int);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setColorStateList(android.content.res.ColorStateList);
+ method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+ }
+
public abstract class Drawable {
ctor public Drawable();
method public void applyTheme(android.content.res.Resources.Theme);
@@ -41948,9 +41964,10 @@
field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+ field public static final java.lang.String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
- field public static final java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
+ field public static final deprecated java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
field public static final java.lang.String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
@@ -53001,6 +53018,7 @@
method public int getWidth();
method public float getZoom();
method public void show(float, float);
+ method public void show(float, float, float, float);
method public void update();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index d9befc7..72cf0c7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4725,6 +4725,7 @@
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+ method public void onNotificationsSeen(java.util.List<java.lang.String>);
method public final void unsnoozeNotification(java.lang.String);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -4733,6 +4734,7 @@
ctor public NotificationStats();
ctor protected NotificationStats(android.os.Parcel);
method public int describeContents();
+ method public int getDismissalSentiment();
method public int getDismissalSurface();
method public boolean hasDirectReplied();
method public boolean hasExpanded();
@@ -4741,6 +4743,7 @@
method public boolean hasSnoozed();
method public boolean hasViewedSettings();
method public void setDirectReplied();
+ method public void setDismissalSentiment(int);
method public void setDismissalSurface(int);
method public void setExpanded();
method public void setSeen();
@@ -4753,6 +4756,10 @@
field public static final int DISMISSAL_OTHER = 0; // 0x0
field public static final int DISMISSAL_PEEK = 1; // 0x1
field public static final int DISMISSAL_SHADE = 3; // 0x3
+ field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0
+ field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1
+ field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2
+ field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18
}
public final class SnoozeCriterion implements android.os.Parcelable {
@@ -5546,6 +5553,19 @@
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public abstract class QualifiedNetworksService extends android.app.Service {
+ ctor public QualifiedNetworksService();
+ method public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int);
+ field public static final java.lang.String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService";
+ }
+
+ public abstract class QualifiedNetworksService.NetworkAvailabilityUpdater implements java.lang.AutoCloseable {
+ ctor public QualifiedNetworksService.NetworkAvailabilityUpdater(int);
+ method public abstract void close();
+ method public final int getSlotIndex();
+ method public final void updateQualifiedNetworkTypes(int, int[]);
+ }
+
}
package android.telephony.euicc {
@@ -6206,6 +6226,10 @@
field public static final int STATE_UNAVAILABLE = 0; // 0x0
}
+ public static class ImsFeature.Capabilities {
+ field protected int mCapabilities;
+ }
+
protected static class ImsFeature.CapabilityCallbackProxy {
method public void onChangeCapabilityConfigurationError(int, int, int);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 1657de5..f6cda32 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5,11 +5,11 @@
field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
+ field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+ field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
- field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
- field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
}
}
@@ -28,11 +28,11 @@
public class ActivityManager {
method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
+ method public void forceStopPackage(java.lang.String);
method public int getPackageImportance(java.lang.String);
method public long getTotalRam();
method public int getUidImportance(int);
method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
- method public void forceStopPackage(java.lang.String);
method public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
}
@@ -53,21 +53,21 @@
}
public class ActivityTaskManager {
+ method public java.lang.String listAllStacks();
+ method public void moveTaskToStack(int, int, boolean);
+ method public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect);
method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
+ method public void resizeDockedStack(android.graphics.Rect, android.graphics.Rect);
method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
- method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
- method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
- method public static boolean supportsMultiWindow(android.content.Context);
- method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
- method public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect);
- method public void startSystemLockTaskMode(int);
- method public void stopSystemLockTaskMode();
- method public void moveTaskToStack(int, int, boolean);
method public void resizeStack(int, android.graphics.Rect, boolean);
method public void resizeTask(int, android.graphics.Rect);
- method public void resizeDockedStack(android.graphics.Rect,android.graphics.Rect);
- method public java.lang.String listAllStacks();
+ method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
+ method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
+ method public void startSystemLockTaskMode(int);
+ method public void stopSystemLockTaskMode();
+ method public static boolean supportsMultiWindow(android.content.Context);
+ method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
field public static final int INVALID_STACK_ID = -1; // 0xffffffff
field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
@@ -1025,10 +1025,12 @@
public abstract class InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
ctor public InternalSanitizer();
+ method public abstract android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
}
public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
ctor public InternalTransformation();
+ method public static boolean batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer, android.service.autofill.InternalTransformation>>);
}
public abstract class InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
@@ -1092,6 +1094,7 @@
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+ method public void onNotificationsSeen(java.util.List<java.lang.String>);
method public final void unsnoozeNotification(java.lang.String);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -1104,6 +1107,7 @@
ctor public NotificationStats();
ctor protected NotificationStats(android.os.Parcel);
method public int describeContents();
+ method public int getDismissalSentiment();
method public int getDismissalSurface();
method public boolean hasDirectReplied();
method public boolean hasExpanded();
@@ -1112,6 +1116,7 @@
method public boolean hasSnoozed();
method public boolean hasViewedSettings();
method public void setDirectReplied();
+ method public void setDismissalSentiment(int);
method public void setDismissalSurface(int);
method public void setExpanded();
method public void setSeen();
@@ -1124,6 +1129,10 @@
field public static final int DISMISSAL_OTHER = 0; // 0x0
field public static final int DISMISSAL_PEEK = 1; // 0x1
field public static final int DISMISSAL_SHADE = 3; // 0x3
+ field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0
+ field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1
+ field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2
+ field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18
}
public final class SnoozeCriterion implements android.os.Parcelable {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 048fb43..e915cc8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -302,6 +302,7 @@
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
+ mTargetInset = -1;
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
@@ -942,6 +943,7 @@
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
}
+ handleViewport(frameDuration);
eglSwapBuffers(mDisplay, mSurface);
@@ -966,7 +968,7 @@
usleep(part.pause * ns2us(frameDuration));
// For infinite parts, we've now played them at least once, so perhaps exit
- if(exitPending() && !part.count)
+ if(exitPending() && !part.count && mCurrentInset >= mTargetInset)
break;
}
@@ -986,6 +988,51 @@
return true;
}
+void BootAnimation::handleViewport(nsecs_t timestep) {
+ if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
+ return;
+ }
+ if (mTargetInset < 0) {
+ // Poll the amount for the top display inset. This will return -1 until persistent properties
+ // have been loaded.
+ mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top",
+ -1 /* default */, -1 /* min */, mHeight / 2 /* max */);
+ }
+ if (mTargetInset <= 0) {
+ return;
+ }
+
+ if (mCurrentInset < mTargetInset) {
+ // After the device boots, the inset will effectively be cropped away. We animate this here.
+ float fraction = static_cast<float>(mCurrentInset) / mTargetInset;
+ int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset;
+
+ SurfaceComposerClient::Transaction()
+ .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight))
+ .apply();
+ } else {
+ // At the end of the animation, we switch to the viewport that DisplayManager will apply
+ // later. This changes the coordinate system, and means we must move the surface up by
+ // the inset amount.
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+
+ Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
+ Rect displayRect(0, mTargetInset, mWidth, mHeight);
+
+ SurfaceComposerClient::Transaction t;
+ t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
+ .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
+ t.setDisplayProjection(dtoken, 0 /* orientation */, layerStackRect, displayRect);
+ t.apply();
+
+ mTargetInset = mCurrentInset = 0;
+ }
+
+ int delta = timestep * mTargetInset / ms2ns(200);
+ mCurrentInset += delta;
+}
+
void BootAnimation::releaseAnimation(Animation* animation) const
{
for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index dffbfde..498eebc 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -158,11 +158,15 @@
void checkExit();
+ void handleViewport(nsecs_t timestep);
+
sp<SurfaceComposerClient> mSession;
AssetManager mAssets;
Texture mAndroid[2];
int mWidth;
int mHeight;
+ int mCurrentInset;
+ int mTargetInset;
bool mUseNpotTextures = false;
EGLDisplay mDisplay;
EGLDisplay mContext;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a010c72..9120701 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -149,6 +149,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -5324,6 +5325,16 @@
}
}
+ /**
+ * Updates the application info.
+ *
+ * This only works in the system process. Must be called on the main thread.
+ */
+ public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) {
+ Preconditions.checkState(mSystemThread, "Must only be called in the system process");
+ handleApplicationInfoChanged(ai);
+ }
+
void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
// Updates triggered by package installation go through a package update
// receiver. Here we try to capture ApplicationInfo changes that are
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java
index 9e23de1..e5f3dfb 100644
--- a/core/java/android/service/notification/NotificationStats.java
+++ b/core/java/android/service/notification/NotificationStats.java
@@ -52,7 +52,7 @@
/**
* Notification has not been dismissed yet.
*/
- public static final int DISMISSAL_NOT_DISMISSED = -1000;
+ public static final int DISMISSAL_NOT_DISMISSED = -1;
/**
* Notification has been dismissed from a {@link NotificationListenerService} or the app
* itself.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 23fc4d5..1351f6f1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
@@ -1212,13 +1213,30 @@
// Get new instance of display based on current display adjustments. It may be updated later
// if moving between the displays also involved a configuration change.
- mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
- mView.getResources());
+ updateInternalDisplay(displayId, mView.getResources());
mAttachInfo.mDisplayState = mDisplay.getState();
// Internal state updated, now notify the view hierarchy.
mView.dispatchMovedToDisplay(mDisplay, config);
}
+ /**
+ * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}.
+ * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding
+ * to {@param displayId}.
+ */
+ private void updateInternalDisplay(int displayId, Resources resources) {
+ final Display preferredDisplay =
+ ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources);
+ if (preferredDisplay == null) {
+ // Fallback to use default display.
+ Slog.w(TAG, "Cannot get desired display with Id: " + displayId);
+ mDisplay = ResourcesManager.getInstance()
+ .getAdjustedDisplay(DEFAULT_DISPLAY, resources);
+ } else {
+ mDisplay = preferredDisplay;
+ }
+ }
+
void pokeDrawLockIfNeeded() {
final int displayState = mAttachInfo.mDisplayState;
if (mView != null && mAdded && mTraversalScheduled
@@ -3944,8 +3962,7 @@
// Handle configuration change.
if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
// Update the display with new DisplayAdjustments.
- mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
- mDisplay.getDisplayId(), localResources);
+ updateInternalDisplay(mDisplay.getDisplayId(), localResources);
final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
final int currentLayoutDirection = config.getLayoutDirection();
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 11054c8..5734171 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -76,10 +76,10 @@
private final int mWindowHeight;
// The zoom applied to the view region copied to the magnifier window.
private final float mZoom;
- // The width of the bitmaps where the magnifier content is copied.
- private final int mBitmapWidth;
- // The height of the bitmaps where the magnifier content is copied.
- private final int mBitmapHeight;
+ // The width of the content that will be copied to the magnifier.
+ private final int mSourceWidth;
+ // The height of the content that will be copied to the magnifier.
+ private final int mSourceHeight;
// The elevation of the window containing the magnifier.
private final float mWindowElevation;
// The corner radius of the window containing the magnifier.
@@ -91,15 +91,14 @@
// The center coordinates of the window containing the magnifier.
private final Point mWindowCoords = new Point();
// The center coordinates of the content to be magnified,
- // which can potentially contain a region outside the magnified view.
- private final Point mCenterZoomCoords = new Point();
- // The center coordinates of the content to be magnified,
// clamped inside the visible region of the magnified view.
private final Point mClampedCenterZoomCoords = new Point();
// Variables holding previous states, used for detecting redundant calls and invalidation.
private final Point mPrevStartCoordsInSurface = new Point(
NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE);
- private final PointF mPrevPosInView = new PointF(
+ private final PointF mPrevShowSourceCoords = new PointF(
+ NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE);
+ private final PointF mPrevShowWindowCoords = new PointF(
NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE);
// Rectangle defining the view surface area we pixel copy content from.
private final Rect mPixelCopyRequestRect = new Rect();
@@ -120,8 +119,8 @@
mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
mWindowCornerRadius = getDeviceDefaultDialogCornerRadius();
mZoom = context.getResources().getFloat(R.dimen.magnifier_zoom_scale);
- mBitmapWidth = Math.round(mWindowWidth / mZoom);
- mBitmapHeight = Math.round(mWindowHeight / mZoom);
+ mSourceWidth = Math.round(mWindowWidth / mZoom);
+ mSourceHeight = Math.round(mWindowHeight / mZoom);
// The view's surface coordinates will not be updated until the magnifier is first shown.
mViewCoordinatesInSurface = new int[2];
}
@@ -148,25 +147,50 @@
/**
* Shows the magnifier on the screen.
*
- * @param xPosInView horizontal coordinate of the center point of the magnifier source relative
- * to the view. The lower end is clamped to 0 and the higher end is clamped to the view
- * width.
- * @param yPosInView vertical coordinate of the center point of the magnifier source
- * relative to the view. The lower end is clamped to 0 and the higher end is clamped to
- * the view height.
+ * @param sourceCenterX horizontal coordinate of the center point of the source rectangle that
+ * will be magnified and copied to the magnifier, relative to the view.
+ * The parameter is clamped such that the copy rectangle fits inside [0, view width].
+ * @param sourceCenterY vertical coordinate of the center point of the source rectangle that
+ * will be magnified and copied to the magnifier, relative to the view.
+ * The parameter is clamped such that the copy rectangle fits inside [0, view height].
*/
- public void show(@FloatRange(from = 0) float xPosInView,
- @FloatRange(from = 0) float yPosInView) {
- xPosInView = Math.max(0, Math.min(xPosInView, mView.getWidth()));
- yPosInView = Math.max(0, Math.min(yPosInView, mView.getHeight()));
+ public void show(@FloatRange(from = 0) float sourceCenterX,
+ @FloatRange(from = 0) float sourceCenterY) {
+ final int verticalOffset = mView.getContext().getResources()
+ .getDimensionPixelSize(R.dimen.magnifier_offset);
+ show(sourceCenterX, sourceCenterY, sourceCenterX, sourceCenterY - verticalOffset);
+ }
+
+ /**
+ * Shows the magnifier on the screen at a position
+ * that is independent from its content position.
+ *
+ * @param sourceCenterX horizontal coordinate of the center point of the source rectangle that
+ * will be magnified and copied to the magnifier, relative to the view.
+ * The parameter is clamped such that the copy rectangle fits inside [0, view width].
+ * @param sourceCenterY vertical coordinate of the center point of the source rectangle that
+ * will be magnified and copied to the magnifier, relative to the view.
+ * The parameter is clamped such that the copy rectangle fits inside [0, view height].
+ * @param magnifierCenterX horizontal coordinate of the center point of the magnifier window
+ * relative to the view. As the magnifier can be arbitrarily positioned, this can be
+ * negative or larger than the view width.
+ * @param magnifierCenterY vertical coordinate of the center point of the magnifier window
+ * relative to the view. As the magnifier can be arbitrarily positioned, this can be
+ * negative or larger than the view height.
+ */
+ public void show(@FloatRange(from = 0) float sourceCenterX,
+ @FloatRange(from = 0) float sourceCenterY,
+ float magnifierCenterX, float magnifierCenterY) {
+ sourceCenterX = Math.max(0, Math.min(sourceCenterX, mView.getWidth()));
+ sourceCenterY = Math.max(0, Math.min(sourceCenterY, mView.getHeight()));
obtainSurfaces();
- obtainContentCoordinates(xPosInView, yPosInView);
- obtainWindowCoordinates();
+ obtainContentCoordinates(sourceCenterX, sourceCenterY);
+ obtainWindowCoordinates(magnifierCenterX, magnifierCenterY);
- final int startX = mClampedCenterZoomCoords.x - mBitmapWidth / 2;
- final int startY = mClampedCenterZoomCoords.y - mBitmapHeight / 2;
- if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) {
+ final int startX = mClampedCenterZoomCoords.x - mSourceWidth / 2;
+ final int startY = mClampedCenterZoomCoords.y - mSourceHeight / 2;
+ if (sourceCenterX != mPrevShowSourceCoords.x || sourceCenterY != mPrevShowSourceCoords.y) {
if (mWindow == null) {
synchronized (mLock) {
mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
@@ -177,9 +201,24 @@
}
}
performPixelCopy(startX, startY, true /* update window position */);
- mPrevPosInView.x = xPosInView;
- mPrevPosInView.y = yPosInView;
+ } else if (magnifierCenterX != mPrevShowWindowCoords.x
+ || magnifierCenterY != mPrevShowWindowCoords.y) {
+ final Point windowCoords = getCurrentClampedWindowCoordinates();
+ final InternalPopupWindow currentWindowInstance = mWindow;
+ sPixelCopyHandlerThread.getThreadHandler().post(() -> {
+ if (mWindow != currentWindowInstance) {
+ // The magnifier was dismissed (and maybe shown again) in the meantime.
+ return;
+ }
+ synchronized (mLock) {
+ mWindow.setContentPositionForNextDraw(windowCoords.x, windowCoords.y);
+ }
+ });
}
+ mPrevShowSourceCoords.x = sourceCenterX;
+ mPrevShowSourceCoords.y = sourceCenterY;
+ mPrevShowWindowCoords.x = magnifierCenterX;
+ mPrevShowWindowCoords.y = magnifierCenterY;
}
/**
@@ -191,8 +230,10 @@
mWindow.destroy();
mWindow = null;
}
- mPrevPosInView.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
- mPrevPosInView.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevShowSourceCoords.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevShowSourceCoords.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevShowWindowCoords.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevShowWindowCoords.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
mPrevStartCoordsInSurface.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
mPrevStartCoordsInSurface.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
}
@@ -296,19 +337,17 @@
* magnifier. These are relative to the surface the content is copied from.
*/
private void obtainContentCoordinates(final float xPosInView, final float yPosInView) {
- final float posX;
- final float posY;
mView.getLocationInSurface(mViewCoordinatesInSurface);
+ final int zoomCenterX;
+ final int zoomCenterY;
if (mView instanceof SurfaceView) {
// No offset required if the backing Surface matches the size of the SurfaceView.
- posX = xPosInView;
- posY = yPosInView;
+ zoomCenterX = Math.round(xPosInView);
+ zoomCenterY = Math.round(yPosInView);
} else {
- posX = xPosInView + mViewCoordinatesInSurface[0];
- posY = yPosInView + mViewCoordinatesInSurface[1];
+ zoomCenterX = Math.round(xPosInView + mViewCoordinatesInSurface[0]);
+ zoomCenterY = Math.round(yPosInView + mViewCoordinatesInSurface[1]);
}
- mCenterZoomCoords.x = Math.round(posX);
- mCenterZoomCoords.y = Math.round(posY);
// Clamp the x location to avoid magnifying content which does not belong
// to the magnified view. This will not take into account overlapping views.
@@ -323,18 +362,29 @@
// If we copy content from a SurfaceView, clamp coordinates relative to it.
viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]);
}
- mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mBitmapWidth / 2, Math.min(
- mCenterZoomCoords.x, viewVisibleRegion.right - mBitmapWidth / 2));
- mClampedCenterZoomCoords.y = mCenterZoomCoords.y;
+ mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mSourceWidth / 2, Math.min(
+ zoomCenterX, viewVisibleRegion.right - mSourceWidth / 2));
+ mClampedCenterZoomCoords.y = zoomCenterY;
}
- private void obtainWindowCoordinates() {
- // Compute the position of the magnifier window. Again, this has to be relative to the
- // surface of the magnified view, as this surface is the parent of the magnifier surface.
- final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.magnifier_offset);
- mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
- mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset;
+ /**
+ * Computes the coordinates of the top left corner of the magnifier window.
+ * These are relative to the surface the magnifier window is attached to.
+ */
+ private void obtainWindowCoordinates(final float xWindowPos, final float yWindowPos) {
+ final int windowCenterX;
+ final int windowCenterY;
+ if (mView instanceof SurfaceView) {
+ // No offset required if the backing Surface matches the size of the SurfaceView.
+ windowCenterX = Math.round(xWindowPos);
+ windowCenterY = Math.round(yWindowPos);
+ } else {
+ windowCenterX = Math.round(xWindowPos + mViewCoordinatesInSurface[0]);
+ windowCenterY = Math.round(yWindowPos + mViewCoordinatesInSurface[1]);
+ }
+
+ mWindowCoords.x = windowCenterX - mWindowWidth / 2;
+ mWindowCoords.y = windowCenterY - mWindowHeight / 2;
if (mParentSurface != mContentCopySurface) {
mWindowCoords.x += mViewCoordinatesInSurface[0];
mWindowCoords.y += mViewCoordinatesInSurface[1];
@@ -348,34 +398,21 @@
}
// Clamp copy coordinates inside the surface to avoid displaying distorted content.
final int clampedStartXInSurface = Math.max(0,
- Math.min(startXInSurface, mContentCopySurface.mWidth - mBitmapWidth));
+ Math.min(startXInSurface, mContentCopySurface.mWidth - mSourceWidth));
final int clampedStartYInSurface = Math.max(0,
- Math.min(startYInSurface, mContentCopySurface.mHeight - mBitmapHeight));
-
+ Math.min(startYInSurface, mContentCopySurface.mHeight - mSourceHeight));
// Clamp window coordinates inside the parent surface, to avoid displaying
// the magnifier out of screen or overlapping with system insets.
- final Rect windowBounds;
- if (mParentSurface.mIsMainWindowSurface) {
- final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
- windowBounds = new Rect(systemInsets.left, systemInsets.top,
- mParentSurface.mWidth - systemInsets.right,
- mParentSurface.mHeight - systemInsets.bottom);
- } else {
- windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight);
- }
- final int windowCoordsX = Math.max(windowBounds.left,
- Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x));
- final int windowCoordsY = Math.max(windowBounds.top,
- Math.min(windowBounds.bottom - mWindowHeight, mWindowCoords.y));
+ final Point windowCoords = getCurrentClampedWindowCoordinates();
// Perform the pixel copy.
mPixelCopyRequestRect.set(clampedStartXInSurface,
clampedStartYInSurface,
- clampedStartXInSurface + mBitmapWidth,
- clampedStartYInSurface + mBitmapHeight);
+ clampedStartXInSurface + mSourceWidth,
+ clampedStartYInSurface + mSourceHeight);
final InternalPopupWindow currentWindowInstance = mWindow;
final Bitmap bitmap =
- Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888);
+ Bitmap.createBitmap(mSourceWidth, mSourceHeight, Bitmap.Config.ARGB_8888);
PixelCopy.request(mContentCopySurface.mSurface, mPixelCopyRequestRect, bitmap,
result -> {
synchronized (mLock) {
@@ -385,7 +422,7 @@
}
if (updateWindowPosition) {
// TODO: pull the position update outside #performPixelCopy
- mWindow.setContentPositionForNextDraw(windowCoordsX, windowCoordsY);
+ mWindow.setContentPositionForNextDraw(windowCoords.x, windowCoords.y);
}
mWindow.updateContent(bitmap);
}
@@ -396,6 +433,28 @@
}
/**
+ * Clamp window coordinates inside the surface the magnifier is attached to, to avoid
+ * displaying the magnifier out of screen or overlapping with system insets.
+ * @return the current window coordinates, after they are clamped inside the parent surface
+ */
+ private Point getCurrentClampedWindowCoordinates() {
+ final Rect windowBounds;
+ if (mParentSurface.mIsMainWindowSurface) {
+ final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
+ windowBounds = new Rect(systemInsets.left, systemInsets.top,
+ mParentSurface.mWidth - systemInsets.right,
+ mParentSurface.mHeight - systemInsets.bottom);
+ } else {
+ windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight);
+ }
+ final int windowCoordsX = Math.max(windowBounds.left,
+ Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x));
+ final int windowCoordsY = Math.max(windowBounds.top,
+ Math.min(windowBounds.bottom - mWindowHeight, mWindowCoords.y));
+ return new Point(windowCoordsX, windowCoordsY);
+ }
+
+ /**
* Contains a surface and metadata corresponding to it.
*/
private static class SurfaceInfo {
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index e183a6b..aa78b0d 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -712,6 +712,12 @@
public abstract void setNextDataSources(@NonNull List<DataSourceDesc> dsds);
/**
+ * Removes all data sources pending to be played.
+ */
+ // This is an asynchronous call.
+ public abstract void clearNextDataSources();
+
+ /**
* Gets the current data source as described by a DataSourceDesc.
*
* @return the current DataSourceDesc
@@ -2066,6 +2072,11 @@
*/
public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29;
+ /** The player just completed a call {@link #clearNextDataSources}.
+ * @see EventCallback#onCallCompleted
+ */
+ public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30;
+
/** The player just completed a call {@link #setBufferingParams}.
* @see EventCallback#onCallCompleted
* @hide
@@ -2109,6 +2120,7 @@
CALL_COMPLETED_SET_SURFACE,
CALL_COMPLETED_SET_SYNC_PARAMS,
CALL_COMPLETED_SKIP_TO_NEXT,
+ CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
CALL_COMPLETED_SET_BUFFERING_PARAMS,
CALL_COMPLETED_SET_VIDEO_SCALING_MODE,
CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 95ba00f..c157251 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -451,6 +451,23 @@
}
@Override
+ public void clearNextDataSources() {
+ addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) {
+ @Override
+ void process() {
+ synchronized (mSrcLock) {
+ if (mNextDSDs != null) {
+ mNextDSDs.clear();
+ mNextDSDs = null;
+ }
+ mNextSrcId = mSrcIdGenerator++;
+ mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ }
+ }
+ });
+ }
+
+ @Override
public @NonNull DataSourceDesc getCurrentDataSource() {
synchronized (mSrcLock) {
return mCurrentDSD;
@@ -1646,6 +1663,14 @@
synchronized (mDrmEventCbLock) {
mDrmEventCallbackRecords.clear();
}
+ synchronized (mSrcLock) {
+ if (mNextDSDs != null) {
+ mNextDSDs.clear();
+ mNextDSDs = null;
+ }
+ mNextSrcId = mSrcIdGenerator++;
+ mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ }
stayAwake(false);
_reset();
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 9c58135..e67b100 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -266,6 +266,12 @@
if (MtpDatabase.this.mServer != null)
MtpDatabase.this.mServer.sendObjectRemoved(id);
}
+
+ @Override
+ public void sendObjectInfoChanged(int id) {
+ if (MtpDatabase.this.mServer != null)
+ MtpDatabase.this.mServer.sendObjectInfoChanged(id);
+ }
}, subDirectories == null ? null : Sets.newHashSet(subDirectories));
initDeviceProperties(context);
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 8af5ff7..a555d37 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -77,6 +77,10 @@
native_send_object_removed(handle);
}
+ public void sendObjectInfoChanged(int handle) {
+ native_send_object_info_changed(handle);
+ }
+
public void sendDevicePropertyChanged(int property) {
native_send_device_property_changed(property);
}
@@ -106,6 +110,7 @@
private native final void native_cleanup();
private native final void native_send_object_added(int handle);
private native final void native_send_object_removed(int handle);
+ private native final void native_send_object_info_changed(int handle);
private native final void native_send_device_property_changed(int property);
private native final void native_add_storage(MtpStorage storage);
private native final void native_remove_storage(int storageId);
diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java
index 756e942..f14e7d7 100644
--- a/media/java/android/mtp/MtpStorageManager.java
+++ b/media/java/android/mtp/MtpStorageManager.java
@@ -55,7 +55,8 @@
MtpObjectObserver(MtpObject object) {
super(object.getPath().toString(),
- MOVED_FROM | MOVED_TO | DELETE | CREATE | IN_ONLYDIR);
+ MOVED_FROM | MOVED_TO | DELETE | CREATE | IN_ONLYDIR
+ | CLOSE_WRITE);
mObject = object;
}
@@ -85,6 +86,10 @@
if (mObject.mObserver != null)
mObject.mObserver.stopWatching();
mObject.mObserver = null;
+ } else if ((event & CLOSE_WRITE) != 0) {
+ if (sDebug)
+ Log.i(TAG, "inotify for " + mObject.getPath() + " CLOSE_WRITE: " + path);
+ handleChangedObject(mObject, path);
} else {
Log.w(TAG, "Got unrecognized event " + path + " " + event);
}
@@ -302,6 +307,11 @@
* Called when an object is deleted.
*/
public abstract void sendObjectRemoved(int id);
+
+ /**
+ * Called when an object info is changed.
+ */
+ public abstract void sendObjectInfoChanged(int id);
}
private MtpNotifier mMtpNotifier;
@@ -733,6 +743,25 @@
Log.i(TAG, state + " transitioned to " + obj.getState() + " in op " + op);
}
+ private synchronized void handleChangedObject(MtpObject parent, String path) {
+ MtpOperation op = MtpOperation.NONE;
+ MtpObject obj = parent.getChild(path);
+ if (obj != null) {
+ // Only handle files for size change notification event
+ if ((!obj.isDir()) && (obj.getSize() > 0))
+ {
+ MtpObjectState state = obj.getState();
+ op = obj.getOperation();
+ MtpStorageManager.this.mMtpNotifier.sendObjectInfoChanged(obj.getId());
+ if (sDebug)
+ Log.d(TAG, "sendObjectInfoChanged: id=" + obj.getId() + ",size=" + obj.getSize());
+ }
+ } else {
+ if (sDebug)
+ Log.w(TAG, "object " + path + " null");
+ }
+ }
+
/**
* Block the caller until all events currently in the event queue have been
* read and processed. Used for testing purposes.
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index c60590a..39ff04a 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -135,6 +135,18 @@
}
static void
+android_mtp_MtpServer_send_object_info_changed(JNIEnv *env, jobject thiz, jint handle)
+{
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->sendObjectInfoChanged(handle);
+ else
+ ALOGE("server is null in send_object_info_changed");
+}
+
+static void
android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property)
{
Mutex::Autolock autoLock(sMutex);
@@ -202,6 +214,7 @@
{"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup},
{"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added},
{"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
+ {"native_send_object_info_changed", "(I)V", (void *)android_mtp_MtpServer_send_object_info_changed},
{"native_send_device_property_changed", "(I)V",
(void *)android_mtp_MtpServer_send_device_property_changed},
{"native_add_storage", "(Landroid/mtp/MtpStorage;)V",
diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
index d7833cc..566d1c6 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
@@ -58,6 +58,7 @@
private ArrayList<Integer> objectsAdded;
private ArrayList<Integer> objectsRemoved;
+ private ArrayList<Integer> objectsInfoChanged;
private File mainStorageDir;
private File secondaryStorageDir;
@@ -73,15 +74,42 @@
Log.d(TAG, Thread.currentThread().getStackTrace()[3].getMethodName());
}
+ private static void logMethodValue(String szVar, int iValue)
+ {
+ Log.d(TAG, szVar + "=" + iValue + ": " + Thread.currentThread().getStackTrace()[3].getMethodName());
+ }
+
+ private static void vWriteNewFile(File newFile) {
+ try {
+ new FileOutputStream(newFile).write(new byte[] {0, 0, 0});
+ } catch (IOException e) {
+ Assert.fail();
+ }
+ }
+
private static File createNewFile(File parent) {
- return createNewFile(parent, UUID.randomUUID().toString());
+ return createNewFile(parent, "file-" + UUID.randomUUID().toString());
+ }
+
+ private static File createNewFileNonZero(File parent) {
+ return createNewFileNonZero(parent, "file-" + UUID.randomUUID().toString());
}
private static File createNewFile(File parent, String name) {
+ return createNewFile(parent, name, false);
+ }
+
+ private static File createNewFileNonZero(File parent, String name) {
+ return createNewFile(parent, name, true);
+ }
+
+ private static File createNewFile(File parent, String name, boolean fgNonZero) {
try {
File ret = new File(parent, name);
if (!ret.createNewFile())
throw new AssertionError("Failed to create file");
+ if (fgNonZero)
+ vWriteNewFile(ret); // create non-zero size file
return ret;
} catch (IOException e) {
throw new AssertionError(e.getMessage());
@@ -96,11 +124,12 @@
}
private static File createNewDir(File parent) {
- return createNewDir(parent, UUID.randomUUID().toString());
+ return createNewDir(parent, "dir-" + UUID.randomUUID().toString());
}
@Before
public void before() {
+ FileUtils.deleteContentsAndDir(TEMP_DIR_FILE);
Assert.assertTrue(TEMP_DIR_FILE.mkdir());
mainStorageDir = createNewDir(TEMP_DIR_FILE);
secondaryStorageDir = createNewDir(TEMP_DIR_FILE);
@@ -112,17 +141,26 @@
objectsAdded = new ArrayList<>();
objectsRemoved = new ArrayList<>();
+ objectsInfoChanged = new ArrayList<>();
manager = new MtpStorageManager(new MtpStorageManager.MtpNotifier() {
@Override
public void sendObjectAdded(int id) {
+ Log.d(TAG, "sendObjectAdded " + id);
objectsAdded.add(id);
}
@Override
public void sendObjectRemoved(int id) {
+ Log.d(TAG, "sendObjectRemoved " + id);
objectsRemoved.add(id);
}
+
+ @Override
+ public void sendObjectInfoChanged(int id) {
+ Log.d(TAG, "sendObjectInfoChanged: " + id);
+ objectsInfoChanged.add(id);
+ }
}, null);
mainMtpStorage = manager.addMtpStorage(mainStorage);
@@ -469,11 +507,16 @@
mainMtpStorage.getStorageId());
Assert.assertEquals(stream.size(), 0);
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(),
newFile.getPath());
+
+ logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size());
+ if (objectsInfoChanged.size() > 0)
+ Assert.assertEquals(objectsAdded.get(0).intValue(), objectsInfoChanged.get(0).intValue());
+
Assert.assertTrue(manager.checkConsistency());
}
@@ -491,6 +534,7 @@
Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(),
newDir.getPath());
Assert.assertTrue(manager.getObject(objectsAdded.get(0)).isDir());
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -508,6 +552,7 @@
Assert.assertEquals(manager.getObject(objectsAdded.get(2)).getPath().toString(),
newDir.getPath());
Assert.assertTrue(manager.getObject(objectsAdded.get(2)).isDir());
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -531,7 +576,7 @@
@SmallTest
public void testObjectMoved() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
List<MtpStorageManager.MtpObject> stream = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId());
Assert.assertEquals(stream.size(), 1);
@@ -544,6 +589,7 @@
Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(),
toFile.getPath());
Assert.assertNull(manager.getObject(objectsRemoved.get(0)));
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -561,7 +607,7 @@
"newFile", MtpConstants.FORMAT_UNDEFINED);
Assert.assertEquals(id, 1);
- File newFile = createNewFile(mainStorageDir, "newFile");
+ File newFile = createNewFileNonZero(mainStorageDir, "newFile");
manager.flushEvents();
MtpStorageManager.MtpObject obj = manager.getObject(id);
Assert.assertTrue(manager.endSendObject(obj, true));
@@ -586,11 +632,12 @@
Assert.assertTrue(manager.endSendObject(obj, true));
Assert.assertEquals(obj.getPath().toString(), newFile.getPath());
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(obj.getFormat(), MtpConstants.FORMAT_ASSOCIATION);
Assert.assertTrue(manager.checkConsistency());
// Check that new dir receives events
- File newerFile = createNewFile(newFile);
+ File newerFile = createNewFileNonZero(newFile);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(),
@@ -609,7 +656,7 @@
MtpStorageManager.MtpObject obj = manager.getObject(id);
Assert.assertTrue(manager.endSendObject(obj, true));
- File newFile = createNewFile(mainStorageDir, "newFile");
+ File newFile = createNewFileNonZero(mainStorageDir, "newFile");
manager.flushEvents();
Assert.assertEquals(obj.getPath().toString(), newFile.getPath());
Assert.assertEquals(objectsAdded.size(), 0);
@@ -632,11 +679,12 @@
manager.flushEvents();
Assert.assertEquals(obj.getPath().toString(), newFile.getPath());
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(obj.getFormat(), MtpConstants.FORMAT_ASSOCIATION);
Assert.assertTrue(manager.checkConsistency());
// Check that new dir receives events
- File newerFile = createNewFile(newFile);
+ File newerFile = createNewFileNonZero(newFile);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(),
@@ -689,12 +737,13 @@
Assert.assertEquals(id, 1);
MtpStorageManager.MtpObject obj = manager.getObject(id);
- File newFile = createNewFile(mainStorageDir, "newFile");
+ File newFile = createNewFileNonZero(mainStorageDir, "newFile");
Assert.assertTrue(newFile.delete());
manager.flushEvents();
Assert.assertTrue(manager.endSendObject(obj, false));
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -713,15 +762,21 @@
manager.flushEvents();
Assert.assertTrue(manager.endSendObject(obj, false));
Assert.assertNotEquals(objectsAdded.get(0).intValue(), id);
+ logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size());
+ if (objectsInfoChanged.size() > 0)
+ Assert.assertNotEquals(objectsInfoChanged.get(0).intValue(), id);
Assert.assertNull(manager.getObject(id));
Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(),
newDir.getPath());
Assert.assertTrue(manager.checkConsistency());
// Expect events in new dir
- createNewFile(newDir);
+ createNewFileNonZero(newDir);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 2);
+ logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size());
+ if (objectsInfoChanged.size() == 1)
+ Assert.assertEquals(objectsAdded.get(1).intValue(), objectsInfoChanged.get(0).intValue());
Assert.assertTrue(manager.checkConsistency());
}
@@ -764,13 +819,13 @@
public void testRemoveObjectDir() {
logMethodName();
File newDir = createNewDir(mainStorageDir);
- createNewFile(createNewDir(newDir));
+ createNewFileNonZero(createNewDir(newDir));
MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
manager.getObjects(obj.getId(), 0, mainMtpStorage.getStorageId());
Assert.assertTrue(manager.beginRemoveObject(obj));
- createNewFile(newDir);
+ createNewFileNonZero(newDir);
Assert.assertTrue(FileUtils.deleteContentsAndDir(newDir));
manager.flushEvents();
Assert.assertTrue(manager.endRemoveObject(obj, true));
@@ -811,13 +866,16 @@
Assert.assertTrue(manager.beginRemoveObject(obj));
Assert.assertTrue(newFile.delete());
- createNewFile(mainStorageDir, newFile.getName());
+ createNewFileNonZero(mainStorageDir, newFile.getName());
manager.flushEvents();
Assert.assertTrue(manager.endRemoveObject(obj, true));
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertNull(manager.getObject(id));
Assert.assertNotEquals(objectsAdded.get(0).intValue(), id);
+ logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size());
+ if (objectsInfoChanged.size() > 0)
+ Assert.assertNotEquals(objectsInfoChanged.get(0).intValue(), objectsAdded.get(0).intValue());
Assert.assertTrue(manager.checkConsistency());
}
@@ -850,6 +908,7 @@
Assert.assertTrue(manager.endRemoveObject(obj, false));
Assert.assertEquals(manager.getObject(obj.getId()), obj);
Assert.assertEquals(objectsAdded.size(), 1);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -875,7 +934,7 @@
@SmallTest
public void testCopyObjectSuccess() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File newDir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId())
@@ -886,7 +945,7 @@
int id = manager.beginCopyObject(fileObj, dirObj);
Assert.assertNotEquals(id, -1);
- createNewFile(newDir, newFile.getName());
+ createNewFileNonZero(newDir, newFile.getName());
manager.flushEvents();
MtpStorageManager.MtpObject obj = manager.getObject(id);
Assert.assertTrue(manager.endCopyObject(obj, true));
@@ -900,9 +959,9 @@
logMethodName();
File newDirFrom = createNewDir(mainStorageDir);
File newDirFrom1 = createNewDir(newDirFrom);
- File newDirFrom2 = createNewFile(newDirFrom1);
- File delayedFile = createNewFile(newDirFrom);
- File deletedFile = createNewFile(newDirFrom);
+ File newDirFrom2 = createNewFileNonZero(newDirFrom1);
+ File delayedFile = createNewFileNonZero(newDirFrom);
+ File deletedFile = createNewFileNonZero(newDirFrom);
File newDirTo = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject toObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -916,9 +975,9 @@
Assert.assertNotEquals(id, -1);
File copiedDir = createNewDir(newDirTo, newDirFrom.getName());
File copiedDir1 = createNewDir(copiedDir, newDirFrom1.getName());
- createNewFile(copiedDir1, newDirFrom2.getName());
- createNewFile(copiedDir, "extraFile");
- File toDelete = createNewFile(copiedDir, deletedFile.getName());
+ createNewFileNonZero(copiedDir1, newDirFrom2.getName());
+ createNewFileNonZero(copiedDir, "extraFile");
+ File toDelete = createNewFileNonZero(copiedDir, deletedFile.getName());
manager.flushEvents();
Assert.assertTrue(toDelete.delete());
manager.flushEvents();
@@ -927,13 +986,13 @@
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertEquals(objectsRemoved.size(), 1);
- createNewFile(copiedDir, delayedFile.getName());
+ createNewFileNonZero(copiedDir, delayedFile.getName());
manager.flushEvents();
Assert.assertTrue(manager.checkConsistency());
// Expect events in the visited dir, but not the unvisited dir.
- createNewFile(copiedDir);
- createNewFile(copiedDir1);
+ createNewFileNonZero(copiedDir);
+ createNewFileNonZero(copiedDir1);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 2);
Assert.assertEquals(objectsAdded.size(), 2);
@@ -947,7 +1006,7 @@
@SmallTest
public void testCopyObjectFailed() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File newDir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -962,6 +1021,7 @@
MtpStorageManager.MtpObject obj = manager.getObject(id);
Assert.assertTrue(manager.endCopyObject(obj, false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -969,7 +1029,7 @@
@SmallTest
public void testCopyObjectFailedAdded() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File newDir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -989,7 +1049,7 @@
Assert.assertTrue(manager.checkConsistency());
// Expect events in new dir
- createNewFile(addedDir);
+ createNewFileNonZero(addedDir);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 2);
Assert.assertTrue(manager.checkConsistency());
@@ -999,7 +1059,7 @@
@SmallTest
public void testCopyObjectFailedDeleted() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File newDir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -1010,7 +1070,7 @@
int id = manager.beginCopyObject(fileObj, dirObj);
Assert.assertNotEquals(id, -1);
- Assert.assertTrue(createNewFile(newDir, newFile.getName()).delete());
+ Assert.assertTrue(createNewFileNonZero(newDir, newFile.getName()).delete());
manager.flushEvents();
MtpStorageManager.MtpObject obj = manager.getObject(id);
Assert.assertTrue(manager.endCopyObject(obj, false));
@@ -1022,7 +1082,7 @@
@SmallTest
public void testRenameObjectSuccess() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginRenameObject(obj, "renamed"));
@@ -1033,6 +1093,7 @@
Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(obj.getPath().toString(), renamed.getPath());
@@ -1054,6 +1115,7 @@
Assert.assertTrue(manager.endRenameObject(obj, newDir.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(obj.getPath().toString(), renamed.getPath());
@@ -1063,6 +1125,7 @@
createNewFile(renamed);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -1082,13 +1145,14 @@
Assert.assertTrue(manager.endRenameObject(obj, newDir.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(obj.getPath().toString(), renamed.getPath());
Assert.assertTrue(manager.checkConsistency());
// Expect events since the dir was visited
- createNewFile(renamed);
+ createNewFileNonZero(renamed);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1098,7 +1162,7 @@
@SmallTest
public void testRenameObjectDelayed() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginRenameObject(obj, "renamed"));
@@ -1109,6 +1173,7 @@
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(obj.getPath().toString(), renamed.getPath());
@@ -1131,13 +1196,14 @@
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(obj.getPath().toString(), renamed.getPath());
Assert.assertTrue(manager.checkConsistency());
// Expect events since the dir was visited
- createNewFile(renamed);
+ createNewFileNonZero(renamed);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1147,7 +1213,7 @@
@SmallTest
public void testRenameObjectFailed() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginRenameObject(obj, "renamed"));
@@ -1155,6 +1221,7 @@
Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertTrue(manager.checkConsistency());
@@ -1164,7 +1231,7 @@
@SmallTest
public void testRenameObjectFailedOldRemoved() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginRenameObject(obj, "renamed"));
@@ -1174,6 +1241,7 @@
Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1183,16 +1251,19 @@
@SmallTest
public void testRenameObjectFailedNewAdded() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginRenameObject(obj, "renamed"));
- createNewFile(mainStorageDir, "renamed");
+ createNewFileNonZero(mainStorageDir, "renamed");
manager.flushEvents();
Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 1);
+ logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size());
+ if (objectsInfoChanged.size() > 0)
+ Assert.assertNotEquals(objectsAdded.get(0).intValue(), objectsInfoChanged.get(0).intValue());
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertTrue(manager.checkConsistency());
@@ -1202,7 +1273,7 @@
@SmallTest
public void testMoveObjectSuccess() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File dir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -1220,6 +1291,7 @@
dirObj, newFile.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(fileObj.getPath().toString(), moved.getPath());
@@ -1248,6 +1320,7 @@
dirObj, movedDir.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(movedObj.getPath().toString(), renamed.getPath());
@@ -1257,6 +1330,7 @@
createNewFile(renamed);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -1283,13 +1357,14 @@
dirObj, movedDir.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(movedObj.getPath().toString(), renamed.getPath());
Assert.assertTrue(manager.checkConsistency());
// Expect events since the dir was visited
- createNewFile(renamed);
+ createNewFileNonZero(renamed);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1299,7 +1374,7 @@
@SmallTest
public void testMoveObjectDelayed() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File dir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -1348,13 +1423,14 @@
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(movedObj.getPath().toString(), renamed.getPath());
Assert.assertTrue(manager.checkConsistency());
// Expect events since the dir was visited
- createNewFile(renamed);
+ createNewFileNonZero(renamed);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1364,7 +1440,7 @@
@SmallTest
public void testMoveObjectFailed() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File dir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -1379,6 +1455,7 @@
dirObj, newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertTrue(manager.checkConsistency());
@@ -1388,7 +1465,7 @@
@SmallTest
public void testMoveObjectFailedOldRemoved() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File dir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -1405,6 +1482,7 @@
dirObj, newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1414,7 +1492,7 @@
@SmallTest
public void testMoveObjectFailedNewAdded() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
File dir = createNewDir(mainStorageDir);
MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).stream()
@@ -1424,7 +1502,7 @@
.filter(o -> !o.isDir()).findFirst().get();
Assert.assertTrue(manager.beginMoveObject(fileObj, dirObj));
- createNewFile(dir, newFile.getName());
+ createNewFileNonZero(dir, newFile.getName());
manager.flushEvents();
Assert.assertTrue(manager.endMoveObject(
manager.getStorageRoot(mainMtpStorage.getStorageId()),
@@ -1440,14 +1518,14 @@
@SmallTest
public void testMoveObjectXStorageSuccess() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginMoveObject(fileObj,
manager.getStorageRoot(secondaryMtpStorage.getStorageId())));
Assert.assertTrue(newFile.delete());
- File moved = createNewFile(secondaryStorageDir, newFile.getName());
+ File moved = createNewFileNonZero(secondaryStorageDir, newFile.getName());
manager.flushEvents();
Assert.assertTrue(manager.endMoveObject(
manager.getStorageRoot(mainMtpStorage.getStorageId()),
@@ -1481,6 +1559,7 @@
movedDir.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(manager.getObject(movedObj.getId()).getPath().toString(),
moved.getPath());
@@ -1491,6 +1570,7 @@
createNewFile(moved);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertTrue(manager.checkConsistency());
}
@@ -1514,6 +1594,7 @@
movedDir.getName(), true));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(manager.getObject(movedObj.getId()).getPath().toString(),
moved.getPath());
@@ -1521,7 +1602,7 @@
Assert.assertTrue(manager.checkConsistency());
// Expect events since the dir was visited
- createNewFile(moved);
+ createNewFileNonZero(moved);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1531,7 +1612,7 @@
@SmallTest
public void testMoveObjectXStorageDelayed() {
logMethodName();
- File movedFile = createNewFile(mainStorageDir);
+ File movedFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject movedObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginMoveObject(movedObj,
@@ -1543,7 +1624,7 @@
movedFile.getName(), true));
Assert.assertTrue(movedFile.delete());
- File moved = createNewFile(secondaryStorageDir, movedFile.getName());
+ File moved = createNewFileNonZero(secondaryStorageDir, movedFile.getName());
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
@@ -1575,6 +1656,7 @@
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertEquals(manager.getObject(movedObj.getId()).getPath().toString(),
moved.getPath());
@@ -1582,7 +1664,7 @@
Assert.assertTrue(manager.checkConsistency());
// Expect events since the dir was visited
- createNewFile(moved);
+ createNewFileNonZero(moved);
manager.flushEvents();
Assert.assertEquals(objectsAdded.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1592,7 +1674,7 @@
@SmallTest
public void testMoveObjectXStorageFailed() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginMoveObject(fileObj,
@@ -1604,6 +1686,7 @@
newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 0);
Assert.assertTrue(manager.checkConsistency());
@@ -1613,7 +1696,7 @@
@SmallTest
public void testMoveObjectXStorageFailedOldRemoved() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginMoveObject(fileObj,
@@ -1627,6 +1710,7 @@
newFile.getName(), false));
Assert.assertEquals(objectsAdded.size(), 0);
+ Assert.assertEquals(objectsInfoChanged.size(), 0);
Assert.assertEquals(objectsRemoved.size(), 1);
Assert.assertTrue(manager.checkConsistency());
@@ -1636,13 +1720,13 @@
@SmallTest
public void testMoveObjectXStorageFailedNewAdded() {
logMethodName();
- File newFile = createNewFile(mainStorageDir);
+ File newFile = createNewFileNonZero(mainStorageDir);
MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0,
mainMtpStorage.getStorageId()).get(0);
Assert.assertTrue(manager.beginMoveObject(fileObj,
manager.getStorageRoot(secondaryMtpStorage.getStorageId())));
- createNewFile(secondaryStorageDir, newFile.getName());
+ createNewFileNonZero(secondaryStorageDir, newFile.getName());
manager.flushEvents();
Assert.assertTrue(manager.endMoveObject(
manager.getStorageRoot(mainMtpStorage.getStorageId()),
@@ -1654,4 +1738,4 @@
Assert.assertTrue(manager.checkConsistency());
}
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 466d02b..0497618 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -106,7 +106,6 @@
new AudioModeChangedHandler());
mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
- mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
}
public void setReceiverHandler(android.os.Handler handler) {
@@ -150,8 +149,7 @@
for (BluetoothDevice device : bondedDevices) {
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
- cachedDevice = mDeviceManager.addDevice(device);
- dispatchDeviceAdded(cachedDevice);
+ mDeviceManager.addDevice(device);
deviceAdded = true;
}
}
@@ -276,7 +274,6 @@
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
- BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
@@ -287,8 +284,6 @@
+ cachedDevice);
}
cachedDevice.setRssi(rssi);
- cachedDevice.setBtClass(btClass);
- cachedDevice.setNewName(name);
cachedDevice.setJustDiscovered(true);
}
}
@@ -339,18 +334,9 @@
BluetoothDevice.ERROR);
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
- Log.w(TAG, "CachedBluetoothDevice for device " + device +
- " not found, calling readPairedDevices().");
- if (readPairedDevices()) {
- cachedDevice = mDeviceManager.findDevice(device);
- }
-
- if (cachedDevice == null) {
- Log.w(TAG, "Got bonding state changed for " + device +
- ", but we have no record of that device.");
- cachedDevice = mDeviceManager.addDevice(device);
- dispatchDeviceAdded(cachedDevice);
- }
+ Log.w(TAG, "Got bonding state changed for " + device +
+ ", but we have no record of that device.");
+ cachedDevice = mDeviceManager.addDevice(device);
}
synchronized (mCallbacks) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index c511589..33ee569 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -51,13 +51,9 @@
private final BluetoothAdapter mLocalAdapter;
private final LocalBluetoothProfileManager mProfileManager;
private final BluetoothDevice mDevice;
- //TODO: consider remove, BluetoothDevice.getName() is already cached
- private String mName;
private long mHiSyncId;
// Need this since there is no method for getting RSSI
private short mRssi;
- //TODO: consider remove, BluetoothDevice.getBluetoothClass() is already cached
- private BluetoothClass mBtClass;
private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
private final List<LocalBluetoothProfile> mProfiles =
@@ -299,7 +295,7 @@
}
return;
}
- Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
+ Log.i(TAG, "Failed to connect " + profile.toString() + " to " + getName());
}
private boolean ensurePaired() {
@@ -376,8 +372,6 @@
// TODO: do any of these need to run async on a background thread?
private void fillData() {
- fetchName();
- fetchBtClass();
updateProfiles();
fetchActiveDevices();
migratePhonebookPermissionChoice();
@@ -400,21 +394,15 @@
return mDevice.getAddress();
}
- public String getName() {
- return mName;
- }
-
/**
- * Populate name from BluetoothDevice.ACTION_FOUND intent
+ * Get name from remote device
+ * @return {@link BluetoothDevice#getAliasName()} if
+ * {@link BluetoothDevice#getAliasName()} is not null otherwise return
+ * {@link BluetoothDevice#getAddress()}
*/
- void setNewName(String name) {
- if (mName == null) {
- mName = name;
- if (mName == null || TextUtils.isEmpty(mName)) {
- mName = mDevice.getAddress();
- }
- dispatchAttributesChanged();
- }
+ public String getName() {
+ final String aliasName = mDevice.getAliasName();
+ return TextUtils.isEmpty(aliasName) ? getAddress() : aliasName;
}
/**
@@ -422,9 +410,8 @@
* @param name new alias name to be set, should never be null
*/
public void setName(String name) {
- // Prevent mName to be set to null if setName(null) is called
- if (name != null && !TextUtils.equals(name, mName)) {
- mName = name;
+ // Prevent getName() to be set to null if setName(null) is called
+ if (name != null && !TextUtils.equals(name, getName())) {
mDevice.setAlias(name);
dispatchAttributesChanged();
}
@@ -461,19 +448,10 @@
}
void refreshName() {
- fetchName();
- dispatchAttributesChanged();
- }
-
- private void fetchName() {
- mName = mDevice.getAliasName();
-
- if (TextUtils.isEmpty(mName)) {
- mName = mDevice.getAddress();
- if (BluetoothUtils.D) {
- Log.d(TAG, "Device has no name (yet), use address: " + mName);
- }
+ if (BluetoothUtils.D) {
+ Log.d(TAG, "Device name: " + getName());
}
+ dispatchAttributesChanged();
}
/**
@@ -606,13 +584,6 @@
return getBondState() == BluetoothDevice.BOND_BONDING;
}
- /**
- * Fetches a new value for the cached BT class.
- */
- private void fetchBtClass() {
- mBtClass = mDevice.getBluetoothClass();
- }
-
private boolean updateProfiles() {
ParcelUuid[] uuids = mDevice.getUuids();
if (uuids == null) return false;
@@ -657,15 +628,6 @@
}
/**
- * Refreshes the UI for the BT class, including fetching the latest value
- * for the class.
- */
- void refreshBtClass() {
- fetchBtClass();
- dispatchAttributesChanged();
- }
-
- /**
* Refreshes the UI when framework alerts us of a UUID change.
*/
void onUuidChanged() {
@@ -715,15 +677,8 @@
}
}
- void setBtClass(BluetoothClass btClass) {
- if (btClass != null && mBtClass != btClass) {
- mBtClass = btClass;
- dispatchAttributesChanged();
- }
- }
-
public BluetoothClass getBtClass() {
- return mBtClass;
+ return mDevice.getBluetoothClass();
}
public List<LocalBluetoothProfile> getProfiles() {
@@ -757,7 +712,7 @@
}
}
- private void dispatchAttributesChanged() {
+ void dispatchAttributesChanged() {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
callback.onDeviceAttributesChanged();
@@ -805,7 +760,7 @@
if (comparison != 0) return comparison;
// Fallback on name
- return mName.compareTo(another.mName);
+ return getName().compareTo(another.getName());
}
public interface Callback {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index f8543fc..47bd853 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -260,7 +260,7 @@
public synchronized void onBtClassChanged(BluetoothDevice device) {
CachedBluetoothDevice cachedDevice = findDevice(device);
if (cachedDevice != null) {
- cachedDevice.refreshBtClass();
+ cachedDevice.dispatchAttributesChanged();
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 5e417c3..c18db11 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -606,4 +606,35 @@
assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
}
+
+ @Test
+ public void getName_aliasNameNotNull_returnAliasName() {
+ when(mDevice.getAliasName()).thenReturn(DEVICE_NAME);
+
+ assertThat(mCachedDevice.getName()).isEqualTo(DEVICE_NAME);
+ }
+
+ @Test
+ public void getName_aliasNameIsNull_returnAddress() {
+ when(mDevice.getAliasName()).thenReturn(null);
+
+ assertThat(mCachedDevice.getName()).isEqualTo(DEVICE_ADDRESS);
+ }
+
+ @Test
+ public void setName_setDeviceNameIsNotNull() {
+ final String name = "test name";
+ when(mDevice.getAliasName()).thenReturn(DEVICE_NAME);
+
+ mCachedDevice.setName(name);
+
+ verify(mDevice).setAlias(name);
+ }
+
+ @Test
+ public void setName_setDeviceNameIsNull() {
+ mCachedDevice.setName(null);
+
+ verify(mDevice, never()).setAlias(any());
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index f223176..e05f9fd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -241,6 +241,7 @@
mShadowBluetoothAdapter.setSupportedProfiles(null);
mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
mDeviceManager, mEventManager);
+ mEventManager.registerProfileIntentReceiver();
// Refer to BluetoothControllerImpl, it will call setReceiverHandler after
// LocalBluetoothProfileManager created.
mEventManager.setReceiverHandler(null);
diff --git a/packages/SystemUI/res/drawable-ldrtl/ic_sysbar_back_carmode.xml b/packages/SystemUI/res/drawable-ldrtl/ic_sysbar_back_carmode.xml
deleted file mode 100644
index f91190b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl/ic_sysbar_back_carmode.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="44dp"
- android:height="44dp"
- android:viewportWidth="44.0"
- android:viewportHeight="44.0">
- <path
- android:pathData="M35,21.94C35,22.78 34.49,23.58 33.64,24.05L12.44,36.13C11.43,36.7 10.58,36.51 10.11,36.25C9.08,35.67 9,34.56 9,34.09L9,9.91C9,9.35 9.08,8.31 10.09,7.75C10.54,7.49 11.34,7.31 12.33,7.86L33.74,19.95C34.51,20.39 35,21.13 35,21.94L35,21.94ZM12.5,32L30.5,21.96L12.5,12L12.5,32Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#F8F9FA"
- android:strokeWidth="1"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_ime_carmode.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_ime_carmode.xml
deleted file mode 100644
index 542ba9b..0000000
--- a/packages/SystemUI/res/drawable/ic_sysbar_back_ime_carmode.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="44dp"
- android:height="44dp"
- android:viewportWidth="44.0"
- android:viewportHeight="44.0">
- <path
- android:pathData="M22.06,35C21.22,35 20.42,34.49 19.95,33.64L7.87,12.44C7.3,11.43 7.49,10.58 7.75,10.11C8.33,9.08 9.44,9 9.91,9L34.09,9C34.65,9 35.69,9.08 36.25,10.09C36.51,10.54 36.69,11.34 36.14,12.33L24.05,33.74C23.61,34.51 22.87,35 22.06,35L22.06,35ZM12,12.5L22.04,30.5L32,12.5L12,12.5Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#F8F9FA"
- android:strokeWidth="1"/>
-</vector>
diff --git a/packages/SystemUI/res/layout/qs_customize_divider.xml b/packages/SystemUI/res/layout/qs_customize_divider.xml
index 51febc7..6fcfa8d 100644
--- a/packages/SystemUI/res/layout/qs_customize_divider.xml
+++ b/packages/SystemUI/res/layout/qs_customize_divider.xml
@@ -23,6 +23,6 @@
android:gravity="center"
android:paddingTop="20dp"
android:paddingBottom="13dp"
- android:textAppearance="@android:style/TextAppearance.Material.Body2"
+ android:textAppearance="@style/TextAppearance.QSEdit.Headers"
android:textColor="?android:attr/colorAccent"
android:text="@string/drag_to_add_tiles" />
diff --git a/packages/SystemUI/res/layout/qs_customize_header.xml b/packages/SystemUI/res/layout/qs_customize_header.xml
new file mode 100644
index 0000000..093f971
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_customize_header.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:minHeight="28dp"
+ android:textAppearance="@style/TextAppearance.QSEdit.Headers"
+ android:textColor="?android:attr/colorAccent"
+ android:text="@string/drag_to_rearrange_tiles" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 4ce6ef6..bb67c54 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -43,7 +43,6 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:paddingTop="28dp"
android:paddingLeft="@dimen/qs_tile_layout_margin_side"
android:paddingRight="@dimen/qs_tile_layout_margin_side"
android:paddingBottom="28dp"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c113745d..2deec5e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1869,6 +1869,9 @@
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Hold and drag to add tiles</string>
+ <!-- Label for header of customize QS [CHAR LIMIT=60] -->
+ <string name="drag_to_rearrange_tiles">Hold and drag to rearrange tiles</string>
+
<!-- Label for area where tiles can be dragged in to [CHAR LIMIT=60] -->
<string name="drag_to_remove_tiles">Drag here to remove</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c0b50ea..47ec5cd 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -495,6 +495,11 @@
parent="@*android:style/TextAppearance.Material.Notification.Info">
</style>
+ <style name="TextAppearance.QSEdit.Headers"
+ parent="@*android:style/TextAppearance.Material.Body2">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ </style>
+
<style name="edit_theme" parent="qs_theme">
<item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index ebfadd8..1c46f12 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -17,7 +17,6 @@
package com.android.systemui.shared.recents;
import android.graphics.Rect;
-import com.android.systemui.shared.system.GraphicBufferCompat;
/**
* Temporary callbacks into SystemUI.
@@ -26,9 +25,10 @@
/**
* Proxies SurfaceControl.screenshotToBuffer().
+ * @Removed
+ * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
+ * int maxLayer, boolean useIdentityTransform, int rotation) = 0;
*/
- GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
- int maxLayer, boolean useIdentityTransform, int rotation) = 0;
/**
* Begins screen pinning on the provided {@param taskId}.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java
deleted file mode 100644
index 66b8fed..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- */
-package com.android.systemui.shared.system;
-
-import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Wraps the internal graphic buffer.
- */
-public class GraphicBufferCompat implements Parcelable {
-
- private GraphicBuffer mBuffer;
-
- public GraphicBufferCompat(GraphicBuffer buffer) {
- mBuffer = buffer;
- }
-
- public GraphicBufferCompat(Parcel in) {
- mBuffer = GraphicBuffer.CREATOR.createFromParcel(in);
- }
-
- public Bitmap toBitmap() {
- return mBuffer != null
- ? Bitmap.createHardwareBitmap(mBuffer)
- : null;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- mBuffer.writeToParcel(dest, flags);
- }
-
- public static final Parcelable.Creator<GraphicBufferCompat> CREATOR
- = new Parcelable.Creator<GraphicBufferCompat>() {
- public GraphicBufferCompat createFromParcel(Parcel in) {
- return new GraphicBufferCompat(in);
- }
-
- public GraphicBufferCompat[] newArray(int size) {
- return new GraphicBufferCompat[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index bc1552e..ad853f1 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -32,7 +32,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
-import android.view.SurfaceControl;
import com.android.systemui.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.recents.events.EventBus;
@@ -41,7 +40,6 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.GraphicBufferCompat;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -94,20 +92,6 @@
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
- public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer,
- int maxLayer, boolean useIdentityTransform, int rotation) {
- if (!verifyCaller("screenshot")) {
- return null;
- }
- long token = Binder.clearCallingIdentity();
- try {
- return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width,
- height, minLayer, maxLayer, useIdentityTransform, rotation));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
public void startScreenPinning(int taskId) {
if (!verifyCaller("startScreenPinning")) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 10b92f7..92f5cae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -62,6 +62,7 @@
private static final int TYPE_TILE = 0;
private static final int TYPE_EDIT = 1;
private static final int TYPE_ACCESSIBLE_DROP = 2;
+ private static final int TYPE_HEADER = 3;
private static final int TYPE_DIVIDER = 4;
private static final long EDIT_ID = 10000;
@@ -112,7 +113,7 @@
public void saveSpecs(QSTileHost host) {
List<String> newSpecs = new ArrayList<>();
- for (int i = 0; i < mTiles.size() && mTiles.get(i) != null; i++) {
+ for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) {
newSpecs.add(mTiles.get(i).spec);
}
host.changeTiles(mCurrentSpecs, newSpecs);
@@ -145,6 +146,7 @@
}
mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
mTiles.clear();
+ mTiles.add(null);
for (int i = 0; i < mCurrentSpecs.size(); i++) {
final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i));
if (tile != null) {
@@ -177,6 +179,9 @@
@Override
public int getItemViewType(int position) {
+ if (position == 0) {
+ return TYPE_HEADER;
+ }
if (mAccessibilityAction == ACTION_ADD && position == mEditIndex - 1) {
return TYPE_ACCESSIBLE_DROP;
}
@@ -193,6 +198,9 @@
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
final Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
+ if (viewType == TYPE_HEADER) {
+ return new Holder(inflater.inflate(R.layout.qs_customize_header, parent, false));
+ }
if (viewType == TYPE_DIVIDER) {
return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
}
@@ -218,6 +226,9 @@
@Override
public void onBindViewHolder(final Holder holder, int position) {
+ if (holder.getItemViewType() == TYPE_HEADER) {
+ return;
+ }
if (holder.getItemViewType() == TYPE_DIVIDER) {
holder.itemView.setVisibility(mTileDividerIndex < mTiles.size() - 1 ? View.VISIBLE
: View.INVISIBLE);
@@ -243,7 +254,7 @@
holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
holder.mTileView.setContentDescription(mContext.getString(
R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel,
- position + 1));
+ position));
holder.mTileView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -274,13 +285,13 @@
R.string.accessibility_qs_edit_add_tile_label, info.state.label);
} else if (mAccessibilityAction == ACTION_ADD) {
info.state.contentDescription = mContext.getString(
- R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position + 1);
+ R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position);
} else if (mAccessibilityAction == ACTION_MOVE) {
info.state.contentDescription = mContext.getString(
- R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position + 1);
+ R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position);
} else {
info.state.contentDescription = mContext.getString(
- R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
+ R.string.accessibility_qs_edit_tile_label, position, info.state.label);
}
holder.mTileView.handleStateChanged(info.state);
holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
@@ -403,11 +414,12 @@
}
private void updateDividerLocations() {
- // The first null is the edit tiles label, the second null is the tile divider.
- // If there is no second null, then there are no non-system tiles.
+ // The first null is the header label (index 0) so we can skip it,
+ // the second null is the edit tiles label, the third null is the tile divider.
+ // If there is no third null, then there are no non-system tiles.
mEditIndex = -1;
mTileDividerIndex = mTiles.size();
- for (int i = 0; i < mTiles.size(); i++) {
+ for (int i = 1; i < mTiles.size(); i++) {
if (mTiles.get(i) == null) {
if (mEditIndex == -1) {
mEditIndex = i;
@@ -486,7 +498,7 @@
@Override
public int getSpanSize(int position) {
final int type = getItemViewType(position);
- return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
+ return type == TYPE_EDIT || type == TYPE_DIVIDER || type == TYPE_HEADER ? 3 : 1;
}
};
@@ -511,7 +523,8 @@
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
- if (holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) {
+ if (holder.getAdapterPosition() == 0 ||
+ holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) {
continue;
}
@@ -569,6 +582,9 @@
@Override
public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
ViewHolder target) {
+ if (target.getAdapterPosition() == 0){
+ return false;
+ }
if (!canRemoveTiles() && current.getAdapterPosition() < mEditIndex) {
return target.getAdapterPosition() < mEditIndex;
}
@@ -577,12 +593,17 @@
@Override
public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
- if (viewHolder.getItemViewType() == TYPE_EDIT || viewHolder.getItemViewType() == TYPE_DIVIDER) {
- return makeMovementFlags(0, 0);
+ switch (viewHolder.getItemViewType()) {
+ case TYPE_EDIT:
+ case TYPE_DIVIDER:
+ case TYPE_HEADER:
+ // Fall through
+ return makeMovementFlags(0, 0);
+ default:
+ int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN
+ | ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT;
+ return makeMovementFlags(dragFlags, 0);
}
- int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
- | ItemTouchHelper.LEFT;
- return makeMovementFlags(dragFlags, 0);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 3e41cd2..0d9c623 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -123,9 +123,9 @@
private Rect mTmpRect = new Rect();
private KeyButtonDrawable mBackIcon;
- private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon;
- private KeyButtonDrawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
- private KeyButtonDrawable mHomeDefaultIcon, mHomeCarModeIcon;
+ private KeyButtonDrawable mHomeDefaultIcon;
+ private KeyButtonDrawable mBackCarModeIcon;
+ private KeyButtonDrawable mHomeCarModeIcon;
private KeyButtonDrawable mRecentIcon;
private KeyButtonDrawable mDockedIcon;
private KeyButtonDrawable mImeIcon;
@@ -461,16 +461,9 @@
&& ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0);
}
- // TODO(b/80003212): change car mode icons to vector icons.
private void updateCarModeIcons(Context ctx) {
- mBackCarModeIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
- mBackLandCarModeIcon = mBackCarModeIcon;
- mBackAltCarModeIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_back_ime_carmode, R.drawable.ic_sysbar_back_ime_carmode);
- mBackAltLandCarModeIcon = mBackAltCarModeIcon;
- mHomeCarModeIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_home_carmode, R.drawable.ic_sysbar_home_carmode);
+ mBackCarModeIcon = getDrawable(ctx, R.drawable.ic_sysbar_back_carmode);
+ mHomeCarModeIcon = getDrawable(ctx, R.drawable.ic_sysbar_home_carmode);
}
private void reloadNavIcons() {
@@ -575,11 +568,9 @@
darkContext.getDrawable(icon), hasShadow);
}
- private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int lightIcon,
- @DrawableRes int darkIcon) {
- // Legacy image icons using separate light and dark images will not support shadows
- return KeyButtonDrawable.create(ctx, ctx.getDrawable(lightIcon),
- ctx.getDrawable(darkIcon), false /* hasShadow */);
+ private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon) {
+ // Legacy image icons using a single image will not support shadows
+ return KeyButtonDrawable.create(ctx, ctx.getDrawable(icon), null, false /* hasShadow */);
}
private TintedKeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon,
@@ -594,16 +585,8 @@
super.setLayoutDirection(layoutDirection);
}
- private KeyButtonDrawable getBackIconWithAlt(boolean carMode, boolean landscape) {
- return landscape
- ? carMode ? mBackAltLandCarModeIcon : mBackIcon
- : carMode ? mBackAltCarModeIcon : mBackIcon;
- }
-
- private KeyButtonDrawable getBackIcon(boolean carMode, boolean landscape) {
- return landscape
- ? carMode ? mBackLandCarModeIcon : mBackIcon
- : carMode ? mBackCarModeIcon : mBackIcon;
+ private KeyButtonDrawable getBackIcon(boolean carMode) {
+ return carMode ? mBackCarModeIcon : mBackIcon;
}
public void setNavigationIconHints(int hints) {
@@ -643,12 +626,10 @@
// to recent icon is not required.
final boolean useAltBack =
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
- KeyButtonDrawable backIcon = useAltBack
- ? getBackIconWithAlt(mUseCarModeUi, mVertical)
- : getBackIcon(mUseCarModeUi, mVertical);
+ KeyButtonDrawable backIcon = getBackIcon(mUseCarModeUi);
+ orientBackButton(backIcon);
KeyButtonDrawable homeIcon = mUseCarModeUi ? mHomeCarModeIcon : mHomeDefaultIcon;
if (!mUseCarModeUi) {
- orientBackButton(backIcon);
orientHomeButton(homeIcon);
}
getHomeButton().setImageDrawable(homeIcon);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java
index 214dda2..9c9b929 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java
@@ -60,7 +60,7 @@
if (mEventBuf.size() == MAX_EVENTS) {
mEventBuf.remove();
}
- mEventBuf.add(new MotionEventCopy(event.getX(), event.getY(), event.getEventTime()));
+ mEventBuf.add(new MotionEventCopy(event.getRawX(), event.getRawY(), event.getEventTime()));
}
public void computeCurrentVelocity(int units) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 9a26709..bef34f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -227,13 +227,7 @@
}
private void trackMovement(MotionEvent event) {
- // Add movement to velocity tracker using raw screen X and Y coordinates instead
- // of window coordinates because the window frame may be moving at the same time.
- float deltaX = event.getRawX() - event.getX();
- float deltaY = event.getRawY() - event.getY();
- event.offsetLocation(deltaX, deltaY);
if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
- event.offsetLocation(-deltaX, -deltaY);
}
public void setTouchAndAnimationDisabled(boolean disabled) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 75b3556..0eff7f5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -151,6 +151,8 @@
// Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
+ private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
+
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
@@ -243,6 +245,15 @@
// device).
private Point mStableDisplaySize = new Point();
+ // Whether the system has finished booting or not.
+ private boolean mSystemReady;
+
+ // The top inset of the default display.
+ // This gets persisted so that the boot animation knows how to transition from the display's
+ // full size to the size configured by the user. Right now we only persist and animate the top
+ // inset, but theoretically we could do it for all of them.
+ private int mDefaultDisplayTopInset;
+
// Viewports of the default display and the display that should receive touch
// input from an external source. Used by the input system.
private final DisplayViewport mDefaultViewport = new DisplayViewport();
@@ -301,6 +312,7 @@
Resources resources = mContext.getResources();
mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
+ mDefaultDisplayTopInset = SystemProperties.getInt(PROP_DEFAULT_DISPLAY_TOP_INSET, -1);
float[] lux = getFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_minimumBrightnessCurveLux));
float[] nits = getFloatArray(resources.obtainTypedArray(
@@ -311,6 +323,8 @@
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
mCurrentUserId = UserHandle.USER_SYSTEM;
+
+ mSystemReady = false;
}
public void setupSchedulerPolicies() {
@@ -400,6 +414,10 @@
synchronized (mSyncRoot) {
mSafeMode = safeMode;
mOnlyCore = onlyCore;
+ mSystemReady = true;
+ // Just in case the top inset changed before the system was ready. At this point, any
+ // relevant configuration should be in place.
+ recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
}
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -457,7 +475,7 @@
LogicalDisplay display = mLogicalDisplays.get(displayId);
if (display != null) {
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
- sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ handleLogicalDisplayChanged(displayId, display);
scheduleTraversalLocked(false);
}
}
@@ -938,6 +956,13 @@
scheduleTraversalLocked(false);
}
+ private void handleLogicalDisplayChanged(int displayId, @NonNull LogicalDisplay display) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ recordTopInsetLocked(display);
+ }
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ }
+
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
@@ -991,6 +1016,7 @@
configureColorModeLocked(display, device);
if (isDefault) {
recordStableDisplayStatsIfNeededLocked(display);
+ recordTopInsetLocked(display);
}
mLogicalDisplays.put(displayId, display);
@@ -1039,6 +1065,21 @@
}
}
+ private void recordTopInsetLocked(@Nullable LogicalDisplay d) {
+ // We must only persist the inset after boot has completed, otherwise we will end up
+ // overwriting the persisted value before the masking flag has been loaded from the
+ // resource overlay.
+ if (!mSystemReady || d == null) {
+ return;
+ }
+ int topInset = d.getInsets().top;
+ if (topInset == mDefaultDisplayTopInset) {
+ return;
+ }
+ mDefaultDisplayTopInset = topInset;
+ SystemProperties.set(PROP_DEFAULT_DISPLAY_TOP_INSET, Integer.toString(topInset));
+ }
+
private void setStableDisplaySizeLocked(int width, int height) {
mStableDisplaySize = new Point(width, height);
try {
@@ -1118,7 +1159,7 @@
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
changed = true;
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
- sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ handleLogicalDisplayChanged(displayId, display);
changed = true;
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 373de63..5b7c520 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemProperties;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -57,6 +58,8 @@
* </p>
*/
final class LogicalDisplay {
+ private static final String PROP_MASKING_INSET_TOP = "persist.sys.displayinset.top";
+
private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
// The layer stack we use when the display has been blanked to prevent any
@@ -297,6 +300,17 @@
}
/**
+ * Return the insets currently applied to the display.
+ *
+ * Note that the base DisplayInfo already takes these insets into account, so if you want to
+ * find out the <b>true</b> size of the display, you need to add them back to the logical
+ * dimensions.
+ */
+ public Rect getInsets() {
+ return getMaskingInsets(mPrimaryDisplayDeviceInfo);
+ }
+
+ /**
* Returns insets in ROTATION_0 for areas that are masked.
*/
private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index f082271..c738701 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -22,11 +22,14 @@
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -34,6 +37,7 @@
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
@@ -269,13 +273,30 @@
@Override
public void onBootPhase(int phase) {
- if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY && mInitCompleteSignal != null) {
ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
"Wait for OverlayManagerService init");
mInitCompleteSignal = null;
}
}
+ public void updateSystemUiContext() {
+ if (mInitCompleteSignal != null) {
+ ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
+ "Wait for OverlayManagerService init");
+ mInitCompleteSignal = null;
+ }
+
+ final ApplicationInfo ai;
+ try {
+ ai = mPackageManager.mPackageManager.getApplicationInfo("android",
+ GET_SHARED_LIBRARY_FILES, UserHandle.USER_SYSTEM);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai);
+ }
+
private void initIfNeeded() {
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fc2813b..18bed54 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8866,15 +8866,16 @@
+ " better than this " + pkg.getLongVersionCode());
}
- // Verify certificates against what was last scanned. If there was an upgrade or this is an
- // updated priv app, we will force re-collecting certificate.
- final boolean forceCollect = mIsUpgrade ||
- PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting);
+ // Verify certificates against what was last scanned. If there was an upgrade and this is an
+ // app in a system partition, or if this is an updated priv app, we will force re-collecting
+ // certificate.
+ final boolean forceCollect = (mIsUpgrade && scanSystemPartition)
+ || PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting);
// Full APK verification can be skipped during certificate collection, only if the file is
// in verified partition, or can be verified on access (when apk verity is enabled). In both
// cases, only data in Signing Block is verified instead of the whole file.
- final boolean skipVerify = ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) ||
- (forceCollect && canSkipFullPackageVerification(pkg));
+ final boolean skipVerify = scanSystemPartition
+ || (forceCollect && canSkipFullPackageVerification(pkg));
collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
// Reset profile if the application version is changed
@@ -17351,11 +17352,11 @@
final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
final File privilegedProductServicesAppDir =
new File(Environment.getProductServicesDirectory(), "priv-app");
- return path.startsWith(privilegedAppDir.getCanonicalPath())
- || path.startsWith(privilegedVendorAppDir.getCanonicalPath())
- || path.startsWith(privilegedOdmAppDir.getCanonicalPath())
- || path.startsWith(privilegedProductAppDir.getCanonicalPath())
- || path.startsWith(privilegedProductServicesAppDir.getCanonicalPath());
+ return path.startsWith(privilegedAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedVendorAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedOdmAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedProductAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedProductServicesAppDir.getCanonicalPath() + "/");
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
@@ -17364,7 +17365,7 @@
static boolean locationIsOem(String path) {
try {
- return path.startsWith(Environment.getOemDirectory().getCanonicalPath());
+ return path.startsWith(Environment.getOemDirectory().getCanonicalPath() + "/");
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
@@ -17373,8 +17374,8 @@
static boolean locationIsVendor(String path) {
try {
- return path.startsWith(Environment.getVendorDirectory().getCanonicalPath())
- || path.startsWith(Environment.getOdmDirectory().getCanonicalPath());
+ return path.startsWith(Environment.getVendorDirectory().getCanonicalPath() + "/")
+ || path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/");
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
@@ -17383,7 +17384,7 @@
static boolean locationIsProduct(String path) {
try {
- return path.startsWith(Environment.getProductDirectory().getCanonicalPath());
+ return path.startsWith(Environment.getProductDirectory().getCanonicalPath() + "/");
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
@@ -17392,7 +17393,8 @@
static boolean locationIsProductServices(String path) {
try {
- return path.startsWith(Environment.getProductServicesDirectory().getCanonicalPath());
+ return path.startsWith(
+ Environment.getProductServicesDirectory().getCanonicalPath() + "/");
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c82c242..2f6fca4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,6 +29,7 @@
import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
+import android.hardware.display.DisplayManagerInternal;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -694,9 +695,17 @@
// Manages Overlay packages
traceBeginAndSlog("StartOverlayManagerService");
- mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
+ OverlayManagerService overlayManagerService = new OverlayManagerService(
+ mSystemContext, installer);
+ mSystemServiceManager.startService(overlayManagerService);
traceEnd();
+ if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
+ // DisplayManager needs the overlay immediately.
+ overlayManagerService.updateSystemUiContext();
+ LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
+ }
+
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
// Start sensor service in a separate thread. Completion should be checked
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index e379cd0..111fb74 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -107,4 +107,24 @@
// TODO: test that sendApplicationHiddenForUser() actually fills in
// broadcastUsers
}
+
+ @Test
+ public void testPartitions() throws Exception {
+ String[] partitions = { "system", "vendor", "odm", "oem", "product", "product_services" };
+ String[] appdir = { "app", "priv-app" };
+ for (int i = 0; i < partitions.length; i++) {
+ for (int j = 0; j < appdir.length; j++) {
+ String canonical = new File("/" + partitions[i]).getCanonicalPath();
+ String path = String.format("%s/%s/A.apk", canonical, appdir[j]);
+
+ Assert.assertEquals(j == 1 && i != 3,
+ PackageManagerService.locationIsPrivileged(path));
+
+ Assert.assertEquals(i == 1 || i == 2, PackageManagerService.locationIsVendor(path));
+ Assert.assertEquals(i == 3, PackageManagerService.locationIsOem(path));
+ Assert.assertEquals(i == 4, PackageManagerService.locationIsProduct(path));
+ Assert.assertEquals(i == 5, PackageManagerService.locationIsProductServices(path));
+ }
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a45d70b..97068a6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -163,10 +163,20 @@
/**
* Flag indicating whether radio is to be restarted on error PDP_FAIL_REGULAR_DEACTIVATION
* This is false by default.
+ *
+ * @deprecated Use {@link #KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY} instead
*/
- public static final String
- KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL =
- "restart_radio_on_pdp_fail_regular_deactivation_bool";
+ @Deprecated
+ public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL =
+ "restart_radio_on_pdp_fail_regular_deactivation_bool";
+
+ /**
+ * A list of failure cause codes that will trigger a modem restart when telephony receiving
+ * one of those during data setup. The cause codes are defined in 3GPP TS 24.008 Annex I and
+ * TS 24.301 Annex B.
+ */
+ public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY =
+ "radio_restart_failure_causes_int_array";
/**
* If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
@@ -2124,6 +2134,7 @@
sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
sDefaults.putBoolean(KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, false);
+ sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[]{});
sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
new file mode 100644
index 0000000..9c80cb7
--- /dev/null
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 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.telephony.data;
+
+import android.telephony.data.IQualifiedNetworksServiceCallback;
+
+/**
+ * {@hide}
+ */
+interface IQualifiedNetworksService
+{
+ oneway void createNetworkAvailabilityUpdater(int slotId, IQualifiedNetworksServiceCallback callback);
+ oneway void removeNetworkAvailabilityUpdater(int slotId);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl
similarity index 64%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
rename to telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl
index f9450ad..e8e1f01 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 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.
@@ -14,6 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.shared.system;
+package android.telephony.data;
-parcelable GraphicBufferCompat;
\ No newline at end of file
+/**
+ * The qualified networks service call back interface
+ * @hide
+ */
+oneway interface IQualifiedNetworksServiceCallback
+{
+ void onQualifiedNetworkTypesChanged(int apnType, in int[] qualifiedNetworkTypesList);
+}
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
new file mode 100644
index 0000000..bb89f19
--- /dev/null
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright 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.telephony.data;
+
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.Rlog;
+import android.telephony.data.ApnSetting.ApnType;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Base class of the qualified networks service. Services that extend QualifiedNetworksService must
+ * register the service in their AndroidManifest to be detected by the framework. They must be
+ * protected by the permission "android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE".
+ * The qualified networks service definition in the manifest must follow the following format:
+ * ...
+ * <service android:name=".xxxQualifiedNetworksService"
+ * android:permission="android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE" >
+ * <intent-filter>
+ * <action android:name="android.telephony.data.QualifiedNetworksService" />
+ * </intent-filter>
+ * </service>
+ * @hide
+ */
+@SystemApi
+public abstract class QualifiedNetworksService extends Service {
+ private static final String TAG = QualifiedNetworksService.class.getSimpleName();
+
+ public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE =
+ "android.telephony.data.QualifiedNetworksService";
+
+ private static final int QNS_CREATE_NETWORK_AVAILABILITY_UPDATER = 1;
+ private static final int QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER = 2;
+ private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS = 3;
+ private static final int QNS_UPDATE_QUALIFIED_NETWORKS = 4;
+
+ private final HandlerThread mHandlerThread;
+
+ private final QualifiedNetworksServiceHandler mHandler;
+
+ private final SparseArray<NetworkAvailabilityUpdater> mUpdaters = new SparseArray<>();
+
+ /** @hide */
+ @VisibleForTesting
+ public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper();
+
+ /**
+ * The abstract class of the network availability updater implementation. The vendor qualified
+ * network service must extend this class to report the available networks for data
+ * connection setup. Note that each instance of network availability updater is associated with
+ * one physical SIM slot.
+ */
+ public abstract class NetworkAvailabilityUpdater implements AutoCloseable {
+ private final int mSlotIndex;
+
+ private IQualifiedNetworksServiceCallback mCallback;
+
+ /**
+ * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array
+ * of available networks.
+ */
+ private SparseArray<int[]> mQualifiedNetworkTypesList = new SparseArray<>();
+
+ /**
+ * Constructor
+ * @param slotIndex SIM slot index the network availability updater associated with.
+ */
+ public NetworkAvailabilityUpdater(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ /**
+ * @return SIM slot index the network availability updater associated with.
+ */
+ public final int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ private void registerForQualifiedNetworkTypesChanged(
+ IQualifiedNetworksServiceCallback callback) {
+ mCallback = callback;
+
+ // Force sending the qualified networks upon registered.
+ if (mCallback != null) {
+ for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) {
+ try {
+ mCallback.onQualifiedNetworkTypesChanged(
+ mQualifiedNetworkTypesList.keyAt(i),
+ mQualifiedNetworkTypesList.valueAt(i));
+ } catch (RemoteException e) {
+ loge("Failed to call onQualifiedNetworksChanged. " + e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update the qualified networks list. Network availability updater must invoke this method
+ * whenever the qualified networks changes. If this method is never invoked for certain
+ * APN type, then frameworks will always use the default (i.e. cellular) data and network
+ * service.
+ *
+ * @param apnType APN type of the qualified networks
+ * @param qualifiedNetworkTypes List of network types which are qualified for data
+ * connection setup for {@link @apnType} in the preferred order. Each element in the array
+ * is a {@link AccessNetworkType}. An empty list or null indicates no networks are qualified
+ * for data setup.
+ */
+ public final void updateQualifiedNetworkTypes(@ApnType int apnType,
+ int[] qualifiedNetworkTypes) {
+ mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnType,
+ qualifiedNetworkTypes).sendToTarget();
+ }
+
+ private void onUpdateQualifiedNetworkTypes(@ApnType int apnType,
+ int[] qualifiedNetworkTypes) {
+ mQualifiedNetworkTypesList.put(apnType, qualifiedNetworkTypes);
+ if (mCallback != null) {
+ try {
+ mCallback.onQualifiedNetworkTypesChanged(apnType, qualifiedNetworkTypes);
+ } catch (RemoteException e) {
+ loge("Failed to call onQualifiedNetworksChanged. " + e);
+ }
+ }
+ }
+
+ /**
+ * Called when the qualified networks updater is removed. The extended class should
+ * implement this method to perform clean up works.
+ */
+ @Override
+ public abstract void close();
+ }
+
+ private class QualifiedNetworksServiceHandler extends Handler {
+ QualifiedNetworksServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ IQualifiedNetworksServiceCallback callback;
+ final int slotIndex = message.arg1;
+ NetworkAvailabilityUpdater updater = mUpdaters.get(slotIndex);
+
+ switch (message.what) {
+ case QNS_CREATE_NETWORK_AVAILABILITY_UPDATER:
+ if (mUpdaters.get(slotIndex) != null) {
+ loge("Network availability updater for slot " + slotIndex
+ + " already existed.");
+ return;
+ }
+
+ updater = createNetworkAvailabilityUpdater(slotIndex);
+ if (updater != null) {
+ mUpdaters.put(slotIndex, updater);
+
+ callback = (IQualifiedNetworksServiceCallback) message.obj;
+ updater.registerForQualifiedNetworkTypesChanged(callback);
+ } else {
+ loge("Failed to create network availability updater. slot index = "
+ + slotIndex);
+ }
+ break;
+
+ case QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER:
+ if (updater != null) {
+ updater.close();
+ mUpdaters.remove(slotIndex);
+ }
+ break;
+
+ case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS:
+ for (int i = 0; i < mUpdaters.size(); i++) {
+ updater = mUpdaters.get(i);
+ if (updater != null) {
+ updater.close();
+ }
+ }
+ mUpdaters.clear();
+ break;
+
+ case QNS_UPDATE_QUALIFIED_NETWORKS:
+ if (updater == null) break;
+ updater.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ public QualifiedNetworksService() {
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+
+ mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper());
+ log("Qualified networks service created");
+ }
+
+ /**
+ * Create the instance of {@link NetworkAvailabilityUpdater}. Vendor qualified network service
+ * must override this method to facilitate the creation of {@link NetworkAvailabilityUpdater}
+ * instances. The system will call this method after binding the qualified networks service for
+ * each active SIM slot index.
+ *
+ * @param slotIndex SIM slot index the qualified networks service associated with.
+ * @return Qualified networks service instance
+ */
+ public abstract NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int slotIndex);
+
+ /** @hide */
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) {
+ loge("Unexpected intent " + intent);
+ return null;
+ }
+ return mBinder;
+ }
+
+ /** @hide */
+ @Override
+ public boolean onUnbind(Intent intent) {
+ mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS).sendToTarget();
+ return false;
+ }
+
+ /** @hide */
+ @Override
+ public void onDestroy() {
+ mHandlerThread.quit();
+ }
+
+ /**
+ * A wrapper around IQualifiedNetworksService that forwards calls to implementations of
+ * {@link QualifiedNetworksService}.
+ */
+ private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub {
+ @Override
+ public void createNetworkAvailabilityUpdater(int slotIndex,
+ IQualifiedNetworksServiceCallback callback) {
+ mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0,
+ callback).sendToTarget();
+ }
+
+ @Override
+ public void removeNetworkAvailabilityUpdater(int slotIndex) {
+ mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0)
+ .sendToTarget();
+ }
+ }
+
+ private void log(String s) {
+ Rlog.d(TAG, s);
+ }
+
+ private void loge(String s) {
+ Rlog.e(TAG, s);
+ }
+}
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 861efd5..69392d6 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -474,9 +474,9 @@
if (value.dataType == Res_value::TYPE_NULL) {
printf("=(null)");
} else if (value.dataType == Res_value::TYPE_REFERENCE) {
- printf("=@0x%x", (int)value.data);
+ printf("=@0x%08x", (int)value.data);
} else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
- printf("=?0x%x", (int)value.data);
+ printf("=?0x%08x", (int)value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
printf("=\"%s\"",
ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i,