summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt8
-rw-r--r--api/system-current.txt8
-rw-r--r--api/test-current.txt8
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java8
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl4
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java5
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl5
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java39
-rw-r--r--core/java/android/printservice/PrinterDiscoverySession.java5
-rw-r--r--core/java/android/view/ViewGroup.java12
-rw-r--r--core/java/android/widget/SimpleMonthView.java40
-rw-r--r--core/tests/coretests/src/android/print/BasePrintTest.java4
-rw-r--r--core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java3
-rw-r--r--core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java5
-rw-r--r--media/java/android/media/ExifInterface.java125
-rw-r--r--media/tests/MediaFrameworkTest/res/values/exifinterface.xml2
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java239
-rw-r--r--packages/DocumentsUI/perf-tests/Android.mk2
-rw-r--r--packages/DocumentsUI/perf-tests/res/raw/earth_small.jpgbin0 -> 44514 bytes
-rw-r--r--packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java39
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java4
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java230
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java18
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java6
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java9
-rw-r--r--services/java/com/android/server/SystemServer.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java231
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/testutis/TestUtils.java9
30 files changed, 798 insertions, 286 deletions
diff --git a/api/current.txt b/api/current.txt
index dd70a3298aeb..c81284b1af46 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5855,7 +5855,7 @@ package android.app.admin {
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
- method public java.lang.String getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public java.lang.String getLongSupportMessage(android.content.ComponentName);
@@ -5926,7 +5926,7 @@ package android.app.admin {
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+ method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -10001,6 +10001,7 @@ package android.content.pm {
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
+ method public java.lang.String getText();
method public java.lang.String getTitle();
method public int getWeight();
method public boolean hasIconFile();
@@ -10028,6 +10029,7 @@ package android.content.pm {
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
}
@@ -30370,7 +30372,7 @@ package android.printservice {
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
- method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
diff --git a/api/system-current.txt b/api/system-current.txt
index 0fe632d27d88..071d1f123ebe 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5995,7 +5995,7 @@ package android.app.admin {
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public java.lang.String getDeviceOwner();
- method public java.lang.String getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.lang.String getDeviceOwnerNameOnAnyUser();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -6074,7 +6074,7 @@ package android.app.admin {
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+ method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -10399,6 +10399,7 @@ package android.content.pm {
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
+ method public java.lang.String getText();
method public java.lang.String getTitle();
method public int getWeight();
method public boolean hasIconFile();
@@ -10426,6 +10427,7 @@ package android.content.pm {
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
}
@@ -32685,7 +32687,7 @@ package android.printservice {
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
- method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
diff --git a/api/test-current.txt b/api/test-current.txt
index d59fa272088d..821614631d65 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5859,7 +5859,7 @@ package android.app.admin {
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
- method public java.lang.String getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public java.lang.String getLongSupportMessage(android.content.ComponentName);
@@ -5930,7 +5930,7 @@ package android.app.admin {
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+ method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -10011,6 +10011,7 @@ package android.content.pm {
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
+ method public java.lang.String getText();
method public java.lang.String getTitle();
method public int getWeight();
method public boolean hasIconFile();
@@ -10038,6 +10039,7 @@ package android.content.pm {
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
}
@@ -30439,7 +30441,7 @@ package android.printservice {
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
- method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e7427bfabe01..502d1cfd60a4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3736,24 +3736,22 @@ public class DevicePolicyManager {
*
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user owner info.
- * @return Whether the device owner information has been set.
* @throws SecurityException if {@code admin} is not a device owner.
*/
- public boolean setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, String info) {
+ public void setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, CharSequence info) {
if (mService != null) {
try {
- return mService.setDeviceOwnerLockScreenInfo(admin, info);
+ mService.setDeviceOwnerLockScreenInfo(admin, info);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
- return false;
}
/**
* @return The device owner information. If it is not set returns {@code null}.
*/
- public String getDeviceOwnerLockScreenInfo() {
+ public CharSequence getDeviceOwnerLockScreenInfo() {
if (mService != null) {
try {
return mService.getDeviceOwnerLockScreenInfo();
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index aed220dd5705..97383a3f4963 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -135,8 +135,8 @@ interface IDevicePolicyManager {
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
- boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
- String getDeviceOwnerLockScreenInfo();
+ void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
+ CharSequence getDeviceOwnerLockScreenInfo();
String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
boolean getPackageSuspended(in ComponentName admin, String packageName);
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index f6d2268343a3..b8a40dc6895a 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -422,7 +422,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
mAuthRetry = true;
mService.writeDescriptor(mClientIf, address, handle,
- descriptor.getCharacteristic().getWriteType(),
+ BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT,
AUTHENTICATION_MITM, descriptor.getValue());
return;
} catch (RemoteException e) {
@@ -943,7 +943,8 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
- characteristic.getWriteType(), AUTHENTICATION_NONE, descriptor.getValue());
+ BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, AUTHENTICATION_NONE,
+ descriptor.getValue());
} catch (RemoteException e) {
Log.e(TAG,"",e);
mDeviceBusy = false;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a0238fb07e5e..6fce36be43ab 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -437,10 +437,9 @@ interface IPackageManager {
void performFstrimIfNeeded();
/**
- * Ask the package manager to extract packages if needed, to save
- * the VM unzipping the APK in memory during launch.
+ * Ask the package manager to update packages if needed.
*/
- void extractPackagesIfNeeded();
+ void updatePackagesIfNeeded();
/**
* Notify the package manager that a package is going to be used.
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index ae75e3f9a156..7408c34538ab 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -118,6 +118,9 @@ public class ShortcutInfo implements Parcelable {
@NonNull
private String mTitle;
+ @Nullable
+ private String mText;
+
/**
* Intent *with extras removed*.
*/
@@ -157,6 +160,7 @@ public class ShortcutInfo implements Parcelable {
mActivityComponent = b.mActivityComponent;
mIcon = b.mIcon;
mTitle = b.mTitle;
+ mText = b.mText;
mIntent = b.mIntent;
if (mIntent != null) {
final Bundle intentExtras = mIntent.getExtras();
@@ -176,6 +180,7 @@ public class ShortcutInfo implements Parcelable {
* @hide
*/
public void enforceMandatoryFields() {
+ Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
}
@@ -195,16 +200,17 @@ public class ShortcutInfo implements Parcelable {
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
mBitmapPath = source.mBitmapPath;
+ mIconResourceId = source.mIconResourceId;
}
mTitle = source.mTitle;
+ mText = source.mText;
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
}
mWeight = source.mWeight;
mExtras = source.mExtras;
- mIconResourceId = source.mIconResourceId;
} else {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
@@ -244,6 +250,9 @@ public class ShortcutInfo implements Parcelable {
if (source.mTitle != null) {
mTitle = source.mTitle;
}
+ if (source.mText != null) {
+ mText = source.mText;
+ }
if (source.mIntent != null) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -305,6 +314,8 @@ public class ShortcutInfo implements Parcelable {
private String mTitle;
+ private String mText;
+
private Intent mIntent;
private int mWeight;
@@ -368,6 +379,15 @@ public class ShortcutInfo implements Parcelable {
}
/**
+ * Sets the text of a shortcut. This is an optional field.
+ */
+ @NonNull
+ public Builder setText(@NonNull String text) {
+ mText = Preconditions.checkStringNotEmpty(text, "text");
+ return this;
+ }
+
+ /**
* Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
* persistable information. (See {@link PersistableBundle}).
*/
@@ -457,6 +477,14 @@ public class ShortcutInfo implements Parcelable {
}
/**
+ * Return the shortcut text.
+ */
+ @Nullable
+ public String getText() {
+ return mText;
+ }
+
+ /**
* Return the intent.
*
* <p>All shortcuts must have an intent, but this method will return null when
@@ -630,6 +658,7 @@ public class ShortcutInfo implements Parcelable {
mActivityComponent = source.readParcelable(cl);
mIcon = source.readParcelable(cl);
mTitle = source.readString();
+ mText = source.readString();
mIntent = source.readParcelable(cl);
mIntentPersistableExtras = source.readParcelable(cl);
mWeight = source.readInt();
@@ -647,6 +676,7 @@ public class ShortcutInfo implements Parcelable {
dest.writeParcelable(mActivityComponent, flags);
dest.writeParcelable(mIcon, flags);
dest.writeString(mTitle);
+ dest.writeString(mText);
dest.writeParcelable(mIntent, flags);
dest.writeParcelable(mIntentPersistableExtras, flags);
dest.writeInt(mWeight);
@@ -708,6 +738,9 @@ public class ShortcutInfo implements Parcelable {
sb.append(", title=");
sb.append(secure ? "***" : mTitle);
+ sb.append(", text=");
+ sb.append(secure ? "***" : mText);
+
sb.append(", icon=");
sb.append(mIcon);
@@ -744,7 +777,8 @@ public class ShortcutInfo implements Parcelable {
/** @hide */
public ShortcutInfo(String id, String packageName, ComponentName activityComponent,
- Icon icon, String title, Intent intent, PersistableBundle intentPersistableExtras,
+ Icon icon, String title, String text, Intent intent,
+ PersistableBundle intentPersistableExtras,
int weight, PersistableBundle extras, long lastChangedTimestamp,
int flags, int iconResId, String bitmapPath) {
mId = id;
@@ -752,6 +786,7 @@ public class ShortcutInfo implements Parcelable {
mActivityComponent = activityComponent;
mIcon = icon;
mTitle = title;
+ mText = text;
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mWeight = weight;
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index cd5a903c4e69..7b9533d73216 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -18,6 +18,7 @@ package android.printservice;
import android.annotation.NonNull;
import android.content.pm.ParceledListSlice;
+import android.os.CancellationSignal;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
@@ -412,11 +413,13 @@ public abstract class PrinterDiscoverySession {
* service.
*
* @param printerId The printer to icon belongs to.
+ * @param cancellationSignal Signal used to cancel the request
* @param callback Callback for returning the icon to the print spooler.
*
* @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
*/
public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+ @NonNull CancellationSignal cancellationSignal,
@NonNull CustomPrinterIconCallback callback) {
}
@@ -533,7 +536,7 @@ public abstract class PrinterDiscoverySession {
if (!mIsDestroyed && mObserver != null) {
CustomPrinterIconCallback callback = new CustomPrinterIconCallback(printerId,
mObserver);
- onRequestCustomPrinterIcon(printerId, callback);
+ onRequestCustomPrinterIcon(printerId, new CancellationSignal(), callback);
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 816d9c48539e..f6958738353b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -6749,7 +6749,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
- // Do nothing
+ // Re-dispatch up the tree by default
+ dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
}
/**
@@ -6757,7 +6758,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
- // Do nothing
+ // Re-dispatch up the tree by default
+ dispatchNestedPreScroll(dx, dy, consumed, null);
}
/**
@@ -6765,7 +6767,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
- return false;
+ // Re-dispatch up the tree by default
+ return dispatchNestedFling(velocityX, velocityY, consumed);
}
/**
@@ -6773,7 +6776,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
- return false;
+ // Re-dispatch up the tree by default
+ return dispatchNestedPreFling(velocityX, velocityY);
}
/**
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 43cf5a1cdc0b..ee716df58548 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -16,6 +16,9 @@
package android.widget;
+import com.android.internal.R;
+import com.android.internal.widget.ExploreByTouchHelper;
+
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -44,14 +47,13 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import com.android.internal.R;
-import com.android.internal.widget.ExploreByTouchHelper;
-
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
+import libcore.icu.LocaleData;
+
/**
* A calendar-like view displaying a specified month and the appropriate selectable day numbers
* within the specified month.
@@ -66,7 +68,6 @@ class SimpleMonthView extends View {
private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
private static final String MONTH_YEAR_FORMAT = "MMMMy";
- private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
private static final int SELECTED_HIGHLIGHT_ALPHA = 0xB0;
@@ -80,6 +81,7 @@ class SimpleMonthView extends View {
private final Paint mDayHighlightPaint = new Paint();
private final Paint mDayHighlightSelectorPaint = new Paint();
+ /** Array of single-character weekday labels ordered by column index. */
private final String[] mDayOfWeekLabels = new String[7];
private final Calendar mCalendar;
@@ -120,7 +122,7 @@ class SimpleMonthView extends View {
*/
private int mToday = DEFAULT_SELECTED_DAY;
- /** The first day of the week (ex. Calendar.SUNDAY). */
+ /** The first day of the week (ex. Calendar.SUNDAY) indexed from one. */
private int mWeekStart = DEFAULT_WEEK_START;
/** The number of days (ex. 28) in the current month. */
@@ -199,13 +201,11 @@ class SimpleMonthView extends View {
Log.d(LOG_TAG, "mWeekStart => " + mWeekStart);
}
- final Calendar calendar = Calendar.getInstance(mLocale);
- calendar.setFirstDayOfWeek(mWeekStart);
-
- final SimpleDateFormat formatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, mLocale);
- for (int i = 0; i < 7; i++) {
- calendar.set(Calendar.DAY_OF_WEEK, i);
- mDayOfWeekLabels[i] = formatter.format(calendar.getTime());
+ // Use tiny (e.g. single-character) weekday names from ICU. The indices
+ // for this list correspond to Calendar days, e.g. SUNDAY is index 1.
+ final String[] tinyWeekdayNames = LocaleData.get(mLocale).tinyWeekdayNames;
+ for (int i = 0; i < DAYS_IN_WEEK; i++) {
+ mDayOfWeekLabels[i] = tinyWeekdayNames[(mWeekStart + i - 1) % DAYS_IN_WEEK + 1];
}
if (DEBUG_WRONG_DATE) {
@@ -662,8 +662,7 @@ class SimpleMonthView extends View {
colCenterRtl = colCenter;
}
- final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK;
- final String label = mDayOfWeekLabels[dayOfWeek];
+ final String label = mDayOfWeekLabels[col];
canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p);
}
}
@@ -813,6 +812,11 @@ class SimpleMonthView extends View {
*/
void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart,
int enabledDayEnd) {
+ if (DEBUG_WRONG_DATE) {
+ Log.d(LOG_TAG, "setMonthParams(" + selectedDay + ", " + month + ", " + year + ", "
+ + weekStart + ", " + enabledDayStart + ", " + enabledDayEnd + ")");
+ }
+
mActivatedDay = selectedDay;
if (isValidMonth(month)) {
@@ -849,6 +853,14 @@ class SimpleMonthView extends View {
mTouchHelper.invalidateRoot();
updateMonthYearLabel();
+
+ if (DEBUG_WRONG_DATE) {
+ Log.d(LOG_TAG, "mMonth = " + mMonth);
+ Log.d(LOG_TAG, "mDayOfWeekStart = " + mDayOfWeekStart);
+ Log.d(LOG_TAG, "mWeekStart = " + mWeekStart);
+ Log.d(LOG_TAG, "mDaysInMonth = " + mDaysInMonth);
+ Log.d(LOG_TAG, "mToday = " + mToday);
+ }
}
private static int getDaysInMonth(int month, int year) {
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index c9bc8aaae0cb..d56a405ba0bb 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.print.PrintAttributes;
@@ -281,7 +282,8 @@ public abstract class BasePrintTest extends InstrumentationTestCase {
}
if (onRequestCustomPrinterIcon != null) {
doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
- any(PrinterId.class), any(CustomPrinterIconCallback.class));
+ any(PrinterId.class), any(CancellationSignal.class),
+ any(CustomPrinterIconCallback.class));
}
if (onStopPrinterStateTracking != null) {
doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
index 26b7caeba15f..be002e29ff68 100644
--- a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
+++ b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
@@ -16,6 +16,7 @@
package android.print.mockservice;
+import android.os.CancellationSignal;
import android.print.PrinterId;
import android.printservice.CustomPrinterIconCallback;
@@ -42,7 +43,7 @@ public abstract class PrinterDiscoverySessionCallbacks {
public abstract void onStartPrinterStateTracking(PrinterId printerId);
public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
- CustomPrinterIconCallback callback);
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
public abstract void onStopPrinterStateTracking(PrinterId printerId);
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
index 04683f267aab..e132d79cfd8b 100644
--- a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.print.mockservice;
+import android.os.CancellationSignal;
import android.print.PrinterId;
import android.printservice.CustomPrinterIconCallback;
import android.printservice.PrintService;
@@ -70,9 +71,9 @@ public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
@Override
public void onRequestCustomPrinterIcon(PrinterId printerId,
- CustomPrinterIconCallback callback) {
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) {
if (mCallbacks != null) {
- mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+ mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
}
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4bf08527b594..cd2d51d4dd79 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -693,7 +693,7 @@ public class ExifInterface {
*/
public ExifInterface(FileDescriptor fileDescriptor) throws IOException {
if (fileDescriptor == null) {
- throw new IllegalArgumentException("parcelFileDescriptor cannot be null");
+ throw new IllegalArgumentException("fileDescriptor cannot be null");
}
mAssetInputStream = null;
mFilename = null;
@@ -705,7 +705,7 @@ public class ExifInterface {
try {
fileDescriptor = Os.dup(fileDescriptor);
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
}
} else {
mSeekableFileDescriptor = null;
@@ -811,6 +811,9 @@ public class ExifInterface {
*/
public void setAttribute(String tag, String value) {
for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ if (i == IFD_THUMBNAIL_HINT && !mHasThumbnail) {
+ continue;
+ }
if (sExifTagMapsForWriting[i].containsKey(tag)) {
mAttributes[i].put(tag, value);
}
@@ -818,6 +821,35 @@ public class ExifInterface {
}
/**
+ * Update the values of the tags in the tag groups if any value for the tag already was stored.
+ *
+ * @param tag the name of the tag.
+ * @param value the value of the tag.
+ * @return Returns {@code true} if updating is placed.
+ */
+ private boolean updateAttribute(String tag, String value) {
+ boolean updated = false;
+ for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ if (mAttributes[i].containsKey(tag)) {
+ mAttributes[i].put(tag, value);
+ updated = true;
+ }
+ }
+ return updated;
+ }
+
+ /**
+ * Remove any values of the specified tag.
+ *
+ * @param tag the name of the tag.
+ */
+ private void removeAttribute(String tag) {
+ for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ mAttributes[i].remove(tag);
+ }
+ }
+
+ /**
* This function decides which parser to read the image data according to the given input stream
* type and the content of the input stream. In each case, it reads the first three bytes to
* determine whether the image data format is JPEG or not.
@@ -853,7 +885,7 @@ public class ExifInterface {
} catch (IOException e) {
// Ignore exceptions in order to keep the compatibility with the old versions of
// ExifInterface.
- Log.w(TAG, "Invalid JPEG: ExifInterface got an unsupported image format file"
+ Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file"
+ "(ExifInterface supports JPEG and some RAW image formats only) "
+ "or a corrupted JPEG file to ExifInterface.", e);
} finally {
@@ -882,27 +914,22 @@ public class ExifInterface {
// Mark for disabling the save feature.
mIsRaw = true;
- for (Map.Entry entry : (Set<Map.Entry>) map.entrySet()) {
- String attrName = (String) entry.getKey();
+ String value = (String) map.remove(TAG_HAS_THUMBNAIL);
+ mHasThumbnail = value != null && value.equalsIgnoreCase("true");
+ value = (String) map.remove(TAG_THUMBNAIL_OFFSET);
+ if (value != null) {
+ mThumbnailOffset = Integer.parseInt(value);
+ }
+ value = (String) map.remove(TAG_THUMBNAIL_LENGTH);
+ if (value != null) {
+ mThumbnailLength = Integer.parseInt(value);
+ }
+ mThumbnailBytes = (byte[]) map.remove(TAG_THUMBNAIL_DATA);
- switch (attrName) {
- case TAG_HAS_THUMBNAIL:
- mHasThumbnail = ((String) entry.getValue()).equalsIgnoreCase("true");
- break;
- case TAG_THUMBNAIL_OFFSET:
- mThumbnailOffset = Integer.parseInt((String) entry.getValue());
- break;
- case TAG_THUMBNAIL_LENGTH:
- mThumbnailLength = Integer.parseInt((String) entry.getValue());
- break;
- case TAG_THUMBNAIL_DATA:
- mThumbnailBytes = (byte[]) entry.getValue();
- break;
- default:
- setAttribute(attrName, (String) entry.getValue());
- break;
- }
+ for (Map.Entry entry : (Set<Map.Entry>) map.entrySet()) {
+ setAttribute((String) entry.getKey(), (String) entry.getValue());
}
+
return true;
}
@@ -928,7 +955,7 @@ public class ExifInterface {
/**
* Save the tag data into the original image file. This is expensive because it involves
* copying all the data from one file to another and deleting the old file and renaming the
- * other. It's best to use{@link #setAttribute(String,String)} to set all attributes to write
+ * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
* and make a single call rather than multiple calls for each attribute.
*/
public void saveAttributes() throws IOException {
@@ -963,7 +990,7 @@ public class ExifInterface {
Streams.copy(in, out);
}
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
@@ -982,7 +1009,7 @@ public class ExifInterface {
}
saveJpegAttributes(in, out);
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
@@ -1276,7 +1303,8 @@ public class ExifInterface {
throw new IOException("Invalid exif");
}
length = 0;
- setAttribute("UserComment", new String(bytes, Charset.forName("US-ASCII")));
+ mAttributes[IFD_EXIF_HINT].put(TAG_USER_COMMENT,
+ new String(bytes, Charset.forName("US-ASCII")));
break;
}
@@ -1296,9 +1324,10 @@ public class ExifInterface {
if (dataInputStream.skipBytes(1) != 1) {
throw new IOException("Invalid SOFx");
}
- setAttribute("ImageLength",
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH,
+ String.valueOf(dataInputStream.readUnsignedShort()));
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH,
String.valueOf(dataInputStream.readUnsignedShort()));
- setAttribute("ImageWidth", String.valueOf(dataInputStream.readUnsignedShort()));
length -= 5;
break;
}
@@ -1521,31 +1550,31 @@ public class ExifInterface {
convertToInt(TAG_GPS_ALTITUDE_REF);
convertToRational(TAG_GPS_LONGITUDE);
convertToRational(TAG_GPS_LATITUDE);
- convertToTimetamp(TAG_GPS_TIMESTAMP);
+ convertToTimestamp(TAG_GPS_TIMESTAMP);
// The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag.
- String valueOfDateTimeOriginal = getAttribute("DateTimeOriginal");
+ String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL);
if (valueOfDateTimeOriginal != null) {
- setAttribute(TAG_DATETIME, valueOfDateTimeOriginal);
+ mAttributes[IFD_TIFF_HINT].put(TAG_DATETIME, valueOfDateTimeOriginal);
}
// Add the default value.
if (getAttribute(TAG_IMAGE_WIDTH) == null) {
- setAttribute(TAG_IMAGE_WIDTH, "0");
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, "0");
}
if (getAttribute(TAG_IMAGE_LENGTH) == null) {
- setAttribute(TAG_IMAGE_LENGTH, "0");
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, "0");
}
if (getAttribute(TAG_ORIENTATION) == null) {
- setAttribute(TAG_ORIENTATION, "0");
+ mAttributes[IFD_TIFF_HINT].put(TAG_ORIENTATION, "0");
}
if (getAttribute(TAG_LIGHT_SOURCE) == null) {
- setAttribute(TAG_LIGHT_SOURCE, "0");
+ mAttributes[IFD_EXIF_HINT].put(TAG_LIGHT_SOURCE, "0");
}
}
// Converts the tag value to timestamp; Otherwise deletes the given tag.
- private void convertToTimetamp(String tagName) {
+ private void convertToTimestamp(String tagName) {
String entryValue = getAttribute(tagName);
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
@@ -1566,9 +1595,9 @@ public class ExifInterface {
int value = numerator / denominator;
stringBuilder.append(String.format("%02d", value));
}
- setAttribute(tagName, stringBuilder.toString());
+ updateAttribute(tagName, stringBuilder.toString());
} else if (dataFormat != IFD_FORMAT_STRING) {
- setAttribute(tagName, null);
+ removeAttribute(tagName);
}
}
@@ -1595,14 +1624,14 @@ public class ExifInterface {
}
stringBuilder.append((double) numerator / denominator);
}
- setAttribute(tagName, stringBuilder.toString());
+ updateAttribute(tagName, stringBuilder.toString());
break;
}
case IFD_FORMAT_DOUBLE:
// Keep it as is.
break;
default:
- setAttribute(tagName, null);
+ removeAttribute(tagName);
break;
}
}
@@ -1624,14 +1653,14 @@ public class ExifInterface {
double doubleValue = Double.parseDouble(component);
stringBuilder.append((int) (doubleValue * 10000.0)).append("/").append(10000);
}
- setAttribute(tagName, stringBuilder.toString());
+ updateAttribute(tagName, stringBuilder.toString());
break;
}
case IFD_FORMAT_SRATIONAL:
// Keep it as is.
break;
default:
- setAttribute(tagName, null);
+ removeAttribute(tagName);
break;
}
}
@@ -1642,7 +1671,7 @@ public class ExifInterface {
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
if (dataFormat != IFD_FORMAT_SLONG) {
- setAttribute(tagName, null);
+ removeAttribute(tagName);
}
}
@@ -1758,7 +1787,7 @@ public class ExifInterface {
String entryValue = readExifEntryValue(
dataInputStream, dataFormat, numberOfComponents);
if (entryValue != null) {
- setAttribute(tagName, entryValue);
+ mAttributes[hint].put(tagName, entryValue);
}
} else {
StringBuilder entryValueBuilder = new StringBuilder();
@@ -1769,7 +1798,7 @@ public class ExifInterface {
entryValueBuilder.append(readExifEntryValue(
dataInputStream, dataFormat, numberOfComponents));
}
- setAttribute(tagName, entryValueBuilder.toString());
+ mAttributes[hint].put(tagName, entryValueBuilder.toString());
}
if (dataInputStream.peek() != nextEntryOffset) {
@@ -1886,11 +1915,11 @@ public class ExifInterface {
// Remove IFD pointer tags (we'll re-add it later.)
for (ExifTag tag : IFD_POINTER_TAGS) {
- setAttribute(tag.name, null);
+ removeAttribute(tag.name);
}
// Remove old thumbnail data
- setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null);
- setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null);
+ removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
+ removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
// Remove null value tags.
for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
diff --git a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
index d556ad33c04a..3c5dd3786e7c 100644
--- a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
+++ b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
@@ -103,7 +103,7 @@
<item>600</item>
<item>800</item>
<item>1</item>
- <item />
+ <item>0</item>
</array>
<array name="volantis_jpg">
<item>false</item>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index 6207f7d59809..dde9bdadebcd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -45,7 +45,7 @@ public class ExifInterfaceTest extends AndroidTestCase {
private static final String TAG = ExifInterface.class.getSimpleName();
private static final boolean VERBOSE = false; // lots of logging
- private static final double DIFFERENCE_TOLERANCE = .005;
+ private static final double DIFFERENCE_TOLERANCE = .001;
// List of files.
private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
@@ -111,11 +111,11 @@ public class ExifInterfaceTest extends AndroidTestCase {
public final String gpsLongitudeRef;
public final String gpsProcessingMethod;
public final String gpsTimestamp;
- public final String imageLength;
- public final String imageWidth;
+ public final int imageLength;
+ public final int imageWidth;
public final String iso;
- public final String whiteBalance;
- public final String orientation;
+ public final int orientation;
+ public final int whiteBalance;
private static String getString(TypedArray typedArray, int index) {
String stringValue = typedArray.getString(index);
@@ -137,7 +137,7 @@ public class ExifInterfaceTest extends AndroidTestCase {
longitude = typedArray.getFloat(5, 0f);
altitude = typedArray.getFloat(6, 0f);
- // Read values.
+ // Reads values.
make = getString(typedArray, 7);
model = getString(typedArray, 8);
aperture = typedArray.getFloat(9, 0f);
@@ -154,11 +154,11 @@ public class ExifInterfaceTest extends AndroidTestCase {
gpsLongitudeRef = getString(typedArray, 20);
gpsProcessingMethod = getString(typedArray, 21);
gpsTimestamp = getString(typedArray, 22);
- imageLength = getString(typedArray, 23);
- imageWidth = getString(typedArray, 24);
+ imageLength = typedArray.getInt(23, 0);
+ imageWidth = typedArray.getInt(24, 0);
iso = getString(typedArray, 25);
- orientation = getString(typedArray, 26);
- whiteBalance = getString(typedArray, 27);
+ orientation = typedArray.getInt(26, 0);
+ whiteBalance = typedArray.getInt(27, 0);
typedArray.recycle();
}
@@ -208,11 +208,13 @@ public class ExifInterfaceTest extends AndroidTestCase {
+ bitmap.getHeight());
}
} else {
- Log.e(TAG, fileName + " Corrupted image (no thumbnail)");
+ Log.e(TAG, fileName + " Unexpected result: No thumbnails were found. "
+ + "A thumbnail is expected.");
}
} else {
if (exifInterface.getThumbnail() != null) {
- Log.e(TAG, fileName + " Corrupted image (a thumbnail exists)");
+ Log.e(TAG, fileName + " Unexpected result: A thumbnail was found. "
+ + "No thumbnail is expected.");
} else {
Log.v(TAG, fileName + " No thumbnail");
}
@@ -226,28 +228,27 @@ public class ExifInterfaceTest extends AndroidTestCase {
Log.v(TAG, fileName + " Latitude = " + latLong[0]);
Log.v(TAG, fileName + " Longitude = " + latLong[1]);
} else {
- Log.v(TAG, fileName + "No latlong data");
+ Log.v(TAG, fileName + " No latlong data");
}
// Prints values.
for (String tagKey : EXIF_TAGS) {
String tagValue = exifInterface.getAttribute(tagKey);
- Log.v(TAG, fileName + "Key{" + tagKey + "} = '" + tagValue + "'");
+ Log.v(TAG, fileName + " Key{" + tagKey + "} = '" + tagValue + "'");
}
}
- private void compareFloatTag(ExifInterface exifInterface, String tag, float expectedValue) {
- String stringValue = exifInterface.getAttribute(tag);
- float floatValue = 0f;
-
- if (stringValue != null) {
- floatValue = Float.parseFloat(stringValue);
- }
+ private void assertIntTag(ExifInterface exifInterface, String tag, int expectedValue) {
+ int intValue = exifInterface.getAttributeInt(tag, 0);
+ assertEquals(expectedValue, intValue);
+ }
- assertEquals(expectedValue, floatValue, DIFFERENCE_TOLERANCE);
+ private void assertFloatTag(ExifInterface exifInterface, String tag, float expectedValue) {
+ double doubleValue = exifInterface.getAttributeDouble(tag, 0.0);
+ assertEquals(expectedValue, doubleValue, DIFFERENCE_TOLERANCE);
}
- private void compareStringTag(ExifInterface exifInterface, String tag, String expectedValue) {
+ private void assertStringTag(ExifInterface exifInterface, String tag, String expectedValue) {
String stringValue = exifInterface.getAttribute(tag);
if (stringValue != null) {
stringValue = stringValue.trim();
@@ -257,7 +258,10 @@ public class ExifInterfaceTest extends AndroidTestCase {
}
private void compareWithExpectedValue(ExifInterface exifInterface,
- ExpectedValue expectedValue) {
+ ExpectedValue expectedValue, String verboseTag) {
+ if (VERBOSE) {
+ printExifTagsAndValues(verboseTag, exifInterface);
+ }
// Checks a thumbnail image.
assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
if (expectedValue.hasThumbnail) {
@@ -282,114 +286,159 @@ public class ExifInterfaceTest extends AndroidTestCase {
assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
// Checks values.
- compareStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
- compareStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
- compareFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
- compareStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
- compareFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
- compareFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
- compareStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE, expectedValue.gpsAltitude);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE_REF,
+ assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
+ assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
+ assertFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
+ assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
+ assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
+ assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
+ assertStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE, expectedValue.gpsAltitude);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE_REF,
expectedValue.gpsAltitudeRef);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_DATESTAMP,
- expectedValue.gpsDatestamp);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE, expectedValue.gpsLatitude);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE_REF,
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_DATESTAMP, expectedValue.gpsDatestamp);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE, expectedValue.gpsLatitude);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE_REF,
expectedValue.gpsLatitudeRef);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE,
- expectedValue.gpsLongitude);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE_REF,
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE, expectedValue.gpsLongitude);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE_REF,
expectedValue.gpsLongitudeRef);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_PROCESSING_METHOD,
expectedValue.gpsProcessingMethod);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP,
- expectedValue.gpsTimestamp);
- compareStringTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
- compareStringTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
- compareStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
- compareStringTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
- compareStringTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE,
- expectedValue.whiteBalance);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
+ assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
+ assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
+ assertStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
+ assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
+ assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
}
private void testExifInterfaceCommon(File imageFile, ExpectedValue expectedValue)
throws IOException {
- // Created via path.
+ String verboseTag = imageFile.getName();
+
+ // Creates via path.
ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
- // Created from an asset file.
- InputStream in = mContext.getAssets().open(imageFile.getName());
- exifInterface = new ExifInterface(in);
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
+ // Creates from an asset file.
+ InputStream in = null;
+ try {
+ in = mContext.getAssets().open(imageFile.getName());
+ exifInterface = new ExifInterface(in);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ } finally {
+ IoUtils.closeQuietly(in);
}
- compareWithExpectedValue(exifInterface, expectedValue);
- // Created via InputStream.
+ // Creates via InputStream.
in = null;
try {
in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
exifInterface = new ExifInterface(in);
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
} finally {
IoUtils.closeQuietly(in);
}
- // Created via FileDescriptor.
+ // Creates via FileDescriptor.
+ FileDescriptor fd = null;
try {
- FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
+ fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
exifInterface = new ExifInterface(fd);
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(fd);
}
}
- private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
+ private void testSaveAttributes_withFileName(File imageFile, ExpectedValue expectedValue)
throws IOException {
- ExpectedValue expectedValue = new ExpectedValue(
- getContext().getResources().obtainTypedArray(typedArrayResourceId));
- File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+ String verboseTag = imageFile.getName();
- // Test for reading from various inputs.
- testExifInterfaceCommon(imageFile, expectedValue);
+ ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
- // Test for saving attributes.
- ExifInterface exifInterface;
+ // Test for modifying one attribute.
+ String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ // Restore the backup value.
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ }
+
+ private void testSaveAttributes_withFileDescriptor(File imageFile, ExpectedValue expectedValue)
+ throws IOException {
+ String verboseTag = imageFile.getName();
+
+ FileDescriptor fd = null;
try {
- FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+ fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+ ExifInterface exifInterface = new ExifInterface(fd);
+ exifInterface.saveAttributes();
+ Os.lseek(fd, 0, OsConstants.SEEK_SET);
exifInterface = new ExifInterface(fd);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
+ // Test for modifying one attribute.
+ String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
exifInterface.saveAttributes();
- fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+ Os.lseek(fd, 0, OsConstants.SEEK_SET);
exifInterface = new ExifInterface(fd);
- if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ // Restore the backup value.
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
+ exifInterface.saveAttributes();
+ Os.lseek(fd, 0, OsConstants.SEEK_SET);
+ exifInterface = new ExifInterface(fd);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(fd);
}
+ }
- // Test for modifying one attribute.
- exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
- exifInterface.saveAttributes();
- exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
+ private void testSaveAttributes_withInputStream(File imageFile, ExpectedValue expectedValue)
+ throws IOException {
+ InputStream in = null;
+ try {
+ in = getContext().getAssets().open(imageFile.getName());
+ ExifInterface exifInterface = new ExifInterface(in);
+ exifInterface.saveAttributes();
+ } catch (UnsupportedOperationException e) {
+ // Expected. saveAttributes is not supported with an ExifInterface object which was
+ // created with InputStream.
+ return;
+ } finally {
+ IoUtils.closeQuietly(in);
}
- assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ fail("Should not reach here!");
+ }
+
+ private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
+ throws IOException {
+ ExpectedValue expectedValue = new ExpectedValue(
+ getContext().getResources().obtainTypedArray(typedArrayResourceId));
+ File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+ // Test for reading from various inputs.
+ testExifInterfaceCommon(imageFile, expectedValue);
+
+ // Test for saving attributes.
+ testSaveAttributes_withFileName(imageFile, expectedValue);
+ testSaveAttributes_withFileDescriptor(imageFile, expectedValue);
+ testSaveAttributes_withInputStream(imageFile, expectedValue);
}
private void testExifInterfaceForRaw(String fileName, int typedArrayResourceId)
diff --git a/packages/DocumentsUI/perf-tests/Android.mk b/packages/DocumentsUI/perf-tests/Android.mk
index 919fc560951b..5ebf85f74d2a 100644
--- a/packages/DocumentsUI/perf-tests/Android.mk
+++ b/packages/DocumentsUI/perf-tests/Android.mk
@@ -2,8 +2,8 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-#LOCAL_SDK_VERSION := current
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, ../tests/src/com/android/documentsui/bots) \
../tests/src/com/android/documentsui/ActivityTest.java \
diff --git a/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg b/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg
new file mode 100644
index 000000000000..dd2da3e9081b
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg
Binary files differ
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
index 6147a7187de7..f9b06f804bac 100644
--- a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
@@ -18,9 +18,11 @@ package com.android.documentsui;
import android.content.Context;
import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor.RowBuilder;
import android.database.MatrixCursor;
+import android.graphics.Point;
import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -31,6 +33,7 @@ import android.provider.DocumentsProvider;
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -102,7 +105,14 @@ public class StressProvider extends DocumentsProvider {
children = new ArrayList<StubDocument>();
mChildDocuments.put(STRESS_ROOT_2_DOC_ID, children);
for (int i = 0; i < STRESS_ROOT_2_ITEMS; i++) {
- document = StubDocument.createFile(STRESS_ROOT_1_ITEMS + i);
+ try {
+ document = StubDocument.createFile(
+ getContext(), MIME_TYPE_IMAGE,
+ com.android.documentsui.perftests.R.raw.earth_small,
+ STRESS_ROOT_1_ITEMS + i);
+ } catch (IOException e) {
+ return false;
+ }
mDocuments.put(document.id, document);
children.add(document);
}
@@ -151,6 +161,14 @@ public class StressProvider extends DocumentsProvider {
}
@Override
+ public AssetFileDescriptor openDocumentThumbnail(String docId, Point sizeHint,
+ CancellationSignal signal)
+ throws FileNotFoundException {
+ final StubDocument document = mDocuments.get(docId);
+ return getContext().getResources().openRawResourceFd(document.thumbnail);
+ }
+
+ @Override
public ParcelFileDescriptor openDocument(String docId, String mode,
CancellationSignal signal)
throws FileNotFoundException {
@@ -171,7 +189,8 @@ public class StressProvider extends DocumentsProvider {
row.add(Document.COLUMN_DISPLAY_NAME, document.id);
row.add(Document.COLUMN_SIZE, document.size);
row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
- row.add(Document.COLUMN_FLAGS, 0);
+ row.add(Document.COLUMN_FLAGS,
+ document.thumbnail != -1 ? Document.FLAG_SUPPORTS_THUMBNAIL : 0);
row.add(Document.COLUMN_LAST_MODIFIED, document.lastModified);
}
@@ -184,28 +203,32 @@ public class StressProvider extends DocumentsProvider {
final String id;
final int size;
final long lastModified;
+ final int thumbnail;
- private StubDocument(String mimeType, String id, int size, long lastModified) {
+ private StubDocument(String mimeType, String id, int size, long lastModified,
+ int thumbnail) {
this.mimeType = mimeType;
this.id = id;
this.size = size;
this.lastModified = lastModified;
+ this.thumbnail = thumbnail;
}
public static StubDocument createDirectory(int index) {
return new StubDocument(
DocumentsContract.Document.MIME_TYPE_DIR, createRandomId(index), 0,
- createRandomTime(index));
+ createRandomTime(index), -1);
}
public static StubDocument createDirectory(String id) {
- return new StubDocument(DocumentsContract.Document.MIME_TYPE_DIR, id, 0, 0);
+ return new StubDocument(DocumentsContract.Document.MIME_TYPE_DIR, id, 0, 0, -1);
}
- public static StubDocument createFile(int index) {
+ public static StubDocument createFile(Context context, String mimeType, int thumbnail,
+ int index) throws IOException {
return new StubDocument(
- MIME_TYPE_IMAGE, createRandomId(index), createRandomSize(index),
- createRandomTime(index));
+ mimeType, createRandomId(index), createRandomSize(index),
+ createRandomTime(index), thumbnail);
}
private static String createRandomId(int index) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 2d3935b6c9e7..99145b7bda0a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -178,6 +178,8 @@ public final class RemotePrintDocument {
}
if (mState == STATE_FAILED) {
Log.w(LOG_TAG, "Failed before start.");
+ } else if (mState == STATE_DESTROYED) {
+ Log.w(LOG_TAG, "Destroyed before start.");
} else {
if (mState != STATE_INITIAL) {
throw new IllegalStateException("Cannot start in state:" + stateToString(mState));
@@ -267,7 +269,7 @@ public final class RemotePrintDocument {
}
if (mState != STATE_STARTED && mState != STATE_UPDATED
&& mState != STATE_FAILED && mState != STATE_CANCELING
- && mState != STATE_CANCELED) {
+ && mState != STATE_CANCELED && mState != STATE_DESTROYED) {
throw new IllegalStateException("Cannot finish in state:"
+ stateToString(mState));
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index da9c48a2a5ee..d10df02a3f2f 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -32,6 +32,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
@@ -40,6 +41,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
+import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.wifi.WifiManager;
@@ -88,7 +90,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class Tethering extends BaseNetworkObserver {
- private Context mContext;
+ private final Context mContext;
private final static String TAG = "Tethering";
private final static boolean DBG = false;
private final static boolean VDBG = false;
@@ -100,7 +102,7 @@ public class Tethering extends BaseNetworkObserver {
private Collection<Integer> mUpstreamIfaceTypes;
// used to synchronize public access to members
- private Object mPublicSync;
+ private final Object mPublicSync;
private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
@@ -112,7 +114,7 @@ public class Tethering extends BaseNetworkObserver {
private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
- private Looper mLooper;
+ private final Looper mLooper;
private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
@@ -143,7 +145,9 @@ public class Tethering extends BaseNetworkObserver {
private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
- private StateMachine mTetherMasterSM;
+ private final StateMachine mTetherMasterSM;
+ private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+ private String mCurrentUpstreamIface;
private Notification.Builder mTetheredNotificationBuilder;
private int mLastNotificationId;
@@ -167,6 +171,8 @@ public class Tethering extends BaseNetworkObserver {
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
+ mUpstreamNetworkMonitor = new UpstreamNetworkMonitor();
+
mStateReceiver = new StateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
@@ -505,7 +511,7 @@ public class Tethering extends BaseNetworkObserver {
};
// The following is necessary to avoid unmarshalling issues when sending the receiver
- // across proccesses.
+ // across processes.
Parcel parcel = Parcel.obtain();
rr.writeToParcel(parcel,0);
parcel.setDataPosition(0);
@@ -559,6 +565,7 @@ public class Tethering extends BaseNetworkObserver {
}
}
}
+
public int tether(String iface) {
if (DBG) Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
@@ -1371,15 +1378,115 @@ public class Tethering extends BaseNetworkObserver {
}
+ /**
+ * A NetworkCallback class that relays information of interest to the
+ * tethering master state machine thread for subsequent processing.
+ */
+ class UpstreamNetworkCallback extends NetworkCallback {
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
+ mTetherMasterSM.sendMessage(
+ TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED,
+ new NetworkState(null, newLp, null, network, null, null));
+ }
+
+ @Override
+ public void onLost(Network network) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network);
+ }
+ }
+
+ /**
+ * A class to centralize all the network and link properties information
+ * pertaining to the current and any potential upstream network.
+ *
+ * Calling #start() registers two callbacks: one to track the system default
+ * network and a second to specifically observe TYPE_MOBILE_DUN networks.
+ *
+ * The methods and data members of this class are only to be accessed and
+ * modified from the tethering master state machine thread. Any other
+ * access semantics would necessitate the addition of locking.
+ *
+ * TODO: Investigate whether more "upstream-specific" logic/functionality
+ * could/should be moved here.
+ */
+ class UpstreamNetworkMonitor {
+ final HashMap<Network, NetworkState> mNetworkMap = new HashMap();
+ NetworkCallback mDefaultNetworkCallback;
+ NetworkCallback mDunTetheringCallback;
+
+ void start() {
+ stop();
+
+ mDefaultNetworkCallback = new UpstreamNetworkCallback();
+ getConnectivityManager().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+
+ final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+ .build();
+ mDunTetheringCallback = new UpstreamNetworkCallback();
+ getConnectivityManager().registerNetworkCallback(
+ dunTetheringRequest, mDunTetheringCallback);
+ }
+
+ void stop() {
+ if (mDefaultNetworkCallback != null) {
+ getConnectivityManager().unregisterNetworkCallback(mDefaultNetworkCallback);
+ mDefaultNetworkCallback = null;
+ }
+
+ if (mDunTetheringCallback != null) {
+ getConnectivityManager().unregisterNetworkCallback(mDunTetheringCallback);
+ mDunTetheringCallback = null;
+ }
+
+ mNetworkMap.clear();
+ }
+
+ // Returns true if these updated LinkProperties pertain to the current
+ // upstream network interface, false otherwise (or if there is not
+ // currently any upstream tethering interface).
+ boolean processLinkPropertiesChanged(NetworkState networkState) {
+ if (networkState == null ||
+ networkState.network == null ||
+ networkState.linkProperties == null) {
+ return false;
+ }
+
+ mNetworkMap.put(networkState.network, networkState);
+
+ if (mCurrentUpstreamIface != null) {
+ for (String ifname : networkState.linkProperties.getAllInterfaceNames()) {
+ if (mCurrentUpstreamIface.equals(ifname)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void processNetworkLost(Network network) {
+ if (network != null) {
+ mNetworkMap.remove(network);
+ }
+ }
+ }
+
class TetherMasterSM extends StateMachine {
// an interface SM has requested Tethering
- static final int CMD_TETHER_MODE_REQUESTED = 1;
+ static final int CMD_TETHER_MODE_REQUESTED = 1;
// an interface SM has unrequested Tethering
- static final int CMD_TETHER_MODE_UNREQUESTED = 2;
+ static final int CMD_TETHER_MODE_UNREQUESTED = 2;
// upstream connection change - do the right thing
- static final int CMD_UPSTREAM_CHANGED = 3;
+ static final int CMD_UPSTREAM_CHANGED = 3;
// we don't have a valid upstream conn, check again after a delay
- static final int CMD_RETRY_UPSTREAM = 4;
+ static final int CMD_RETRY_UPSTREAM = 4;
+ // Events from NetworkCallbacks that we process on the master state
+ // machine thread on behalf of the UpstreamNetworkMonitor.
+ static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED = 5;
+ static final int EVENT_UPSTREAM_LOST = 6;
// This indicates what a timeout event relates to. A state that
// sends itself a delayed timeout event and handles incoming timeout events
@@ -1399,9 +1506,7 @@ public class Tethering extends BaseNetworkObserver {
private ArrayList<TetherInterfaceSM> mNotifyList;
private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
- private ConnectivityManager.NetworkCallback mMobileUpstreamCallback;
-
- private String mUpstreamIfaceName = null;
+ private NetworkCallback mMobileUpstreamCallback;
private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
@@ -1430,8 +1535,6 @@ public class Tethering extends BaseNetworkObserver {
}
class TetherMasterUtilState extends State {
- protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false;
-
@Override
public boolean processMessage(Message m) {
return false;
@@ -1461,27 +1564,27 @@ public class Tethering extends BaseNetworkObserver {
return false;
}
- NetworkRequest.Builder builder = new NetworkRequest.Builder()
+ final NetworkRequest.Builder builder = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
if (apnType == ConnectivityManager.TYPE_MOBILE_DUN) {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
} else {
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
- NetworkRequest mobileUpstreamRequest = builder.build();
- // Other mechanisms notice network and interface changes and act upon them.
- // TODO, imminently: replace with a proper NetworkCallback-based scheme.
- //
+ final NetworkRequest mobileUpstreamRequest = builder.build();
+
+ // The UpstreamNetworkMonitor's callback will be notified.
+ // Therefore, to avoid duplicate notifications, we only register a no-op.
+ mMobileUpstreamCallback = new NetworkCallback();
+
// TODO: Change the timeout from 0 (no onUnavailable callback) to use some
// moderate callback time (once timeout callbacks are implemented). This might
// be useful for updating some UI. Additionally, we should definitely log a
- // message to aid in any subsequent debugging.
- mMobileUpstreamCallback = new ConnectivityManager.NetworkCallback();
+ // message to aid in any subsequent debugging
if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
getConnectivityManager().requestNetwork(
mobileUpstreamRequest, mMobileUpstreamCallback, 0, apnType);
-
return true;
}
@@ -1513,6 +1616,7 @@ public class Tethering extends BaseNetworkObserver {
}
return true;
}
+
protected boolean turnOffMasterTetherSettings() {
try {
mNMService.stopTethering();
@@ -1606,34 +1710,41 @@ public class Tethering extends BaseNetworkObserver {
}
if (iface != null) {
- String[] dnsServers = mDefaultDnsServers;
- Collection<InetAddress> dnses = linkProperties.getDnsServers();
- if (dnses != null && !dnses.isEmpty()) {
- // TODO: remove this invocation of NetworkUtils.makeStrings().
- dnsServers = NetworkUtils.makeStrings(dnses);
- }
- try {
- Network network = getConnectivityManager().getNetworkForType(upType);
- if (network == null) {
- Log.e(TAG, "No Network for upstream type " + upType + "!");
- }
- if (VDBG) {
- Log.d(TAG, "Setting DNS forwarders: Network=" + network +
- ", dnsServers=" + Arrays.toString(dnsServers));
- }
- mNMService.setDnsForwarders(network, dnsServers);
- } catch (Exception e) {
- Log.e(TAG, "Setting DNS forwarders failed!");
- transitionTo(mSetDnsForwardersErrorState);
+ Network network = getConnectivityManager().getNetworkForType(upType);
+ if (network == null) {
+ Log.e(TAG, "No Network for upstream type " + upType + "!");
}
+ setDnsForwarders(network, linkProperties);
}
}
notifyTetheredOfNewUpstreamIface(iface);
}
+ protected void setDnsForwarders(final Network network, final LinkProperties lp) {
+ String[] dnsServers = mDefaultDnsServers;
+ final Collection<InetAddress> dnses = lp.getDnsServers();
+ // TODO: Properly support the absence of DNS servers.
+ if (dnses != null && !dnses.isEmpty()) {
+ // TODO: remove this invocation of NetworkUtils.makeStrings().
+ dnsServers = NetworkUtils.makeStrings(dnses);
+ }
+ if (VDBG) {
+ Log.d(TAG, "Setting DNS forwarders: Network=" + network +
+ ", dnsServers=" + Arrays.toString(dnsServers));
+ }
+ try {
+ mNMService.setDnsForwarders(network, dnsServers);
+ } catch (Exception e) {
+ // TODO: Investigate how this can fail and what exactly
+ // happens if/when such failures occur.
+ Log.e(TAG, "Setting DNS forwarders failed!");
+ transitionTo(mSetDnsForwardersErrorState);
+ }
+ }
+
protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
- mUpstreamIfaceName = ifaceName;
+ mCurrentUpstreamIface = ifaceName;
for (TetherInterfaceSM sm : mNotifyList) {
sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
ifaceName);
@@ -1772,20 +1883,23 @@ public class Tethering extends BaseNetworkObserver {
}
class TetherModeAliveState extends TetherMasterUtilState {
- boolean mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
+ boolean mTryCell = true;
@Override
public void enter() {
+ // TODO: examine if we should check the return value.
turnOnMasterTetherSettings(); // may transition us out
startListeningForSimChanges();
+ mUpstreamNetworkMonitor.start();
- mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass
- // or crazy tests cases will fail
+ mTryCell = true; // better try something first pass or crazy tests cases will fail
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
}
@Override
public void exit() {
+ // TODO: examine if we should check the return value.
turnOffUpstreamMobileConnection();
+ mUpstreamNetworkMonitor.stop();
stopListeningForSimChanges();
notifyTetheredOfNewUpstreamIface(null);
}
@@ -1799,7 +1913,7 @@ public class Tethering extends BaseNetworkObserver {
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
mNotifyList.add(who);
who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
- mUpstreamIfaceName);
+ mCurrentUpstreamIface);
break;
case CMD_TETHER_MODE_UNREQUESTED:
who = (TetherInterfaceSM)message.obj;
@@ -1823,7 +1937,7 @@ public class Tethering extends BaseNetworkObserver {
break;
case CMD_UPSTREAM_CHANGED:
// need to try DUN immediately if Wifi goes down
- mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
+ mTryCell = true;
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
break;
@@ -1831,6 +1945,24 @@ public class Tethering extends BaseNetworkObserver {
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
break;
+ case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED:
+ NetworkState state = (NetworkState) message.obj;
+ if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) {
+ setDnsForwarders(state.network, state.linkProperties);
+ } else if (mCurrentUpstreamIface == null) {
+ // If we have no upstream interface, try to run through upstream
+ // selection again. If, for example, IPv4 connectivity has shown up
+ // after IPv6 (e.g., 464xlat became available) we want the chance to
+ // notice and act accordingly.
+ chooseUpstreamType(false);
+ }
+ break;
+ case EVENT_UPSTREAM_LOST:
+ // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation
+ // is triggered via received CONNECTIVITY_ACTION broadcasts that result
+ // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED.
+ mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj);
+ break;
default:
retValue = false;
break;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 442643a976e2..fdbbd853a6ec 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6926,8 +6926,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public void extractPackagesIfNeeded() {
- enforceSystemOrRoot("Only the system can request package extraction");
+ public void updatePackagesIfNeeded() {
+ enforceSystemOrRoot("Only the system can request package update");
// We need to re-extract after an OTA.
boolean causeUpgrade = isUpgrade();
@@ -6958,15 +6958,6 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
}
- if (!isFirstBoot()) {
- try {
- ActivityManagerNative.getDefault().showBootMessage(
- mContext.getResources().getString(R.string.android_upgrading_apk,
- curr, total), true);
- } catch (RemoteException e) {
- }
- }
-
if (PackageDexOptimizer.canOptimizePackage(pkg)) {
// If the cache was pruned, any compiled odex files will likely be out of date
// and would have to be patched (would be SELF_PATCHOAT, which is deprecated).
@@ -7247,9 +7238,9 @@ public class PackageManagerService extends IPackageManager.Stub {
private void deleteProfilesLI(PackageParser.Package pkg, boolean destroy) {
try {
if (destroy) {
- mInstaller.clearAppProfiles(pkg.packageName);
- } else {
mInstaller.destroyAppProfiles(pkg.packageName);
+ } else {
+ mInstaller.clearAppProfiles(pkg.packageName);
}
} catch (InstallerException ex) {
Log.e(TAG, "Could not delete profiles for package " + pkg.packageName);
@@ -14521,7 +14512,6 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
res = deletePackageLI(packageName, removeForUser, true, allUsers,
flags | REMOVE_CHATTY, info, true, null);
- deleteProfilesLI(packageName, /*destroy*/ true);
synchronized (mPackages) {
if (res) {
mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPs.pkg);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index f9414328885c..5916202a0bdb 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -55,6 +55,7 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String ATTR_ID = "id";
private static final String ATTR_ACTIVITY = "activity";
private static final String ATTR_TITLE = "title";
+ private static final String ATTR_TEXT = "text";
private static final String ATTR_INTENT = "intent";
private static final String ATTR_WEIGHT = "weight";
private static final String ATTR_TIMESTAMP = "timestamp";
@@ -439,6 +440,7 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeAttr(out, ATTR_ACTIVITY, si.getActivityComponent());
// writeAttr(out, "icon", si.getIcon()); // We don't save it.
ShortcutService.writeAttr(out, ATTR_TITLE, si.getTitle());
+ ShortcutService.writeAttr(out, ATTR_TEXT, si.getText());
ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
ShortcutService.writeAttr(out, ATTR_WEIGHT, si.getWeight());
ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
@@ -515,6 +517,7 @@ class ShortcutPackage extends ShortcutPackageItem {
ComponentName activityComponent;
// Icon icon;
String title;
+ String text;
Intent intent;
PersistableBundle intentPersistableExtras = null;
int weight;
@@ -528,6 +531,7 @@ class ShortcutPackage extends ShortcutPackageItem {
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
ATTR_ACTIVITY);
title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
+ text = ShortcutService.parseStringAttribute(parser, ATTR_TEXT);
intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
@@ -559,7 +563,7 @@ class ShortcutPackage extends ShortcutPackageItem {
throw ShortcutService.throwForInvalidTag(depth, tag);
}
return new ShortcutInfo(
- id, packageName, activityComponent, /* icon =*/ null, title, intent,
+ id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
iconRes, bitmapPath);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 4a00ebd713bb..dbbaa5ebf75f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -319,7 +319,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
*/
@Override
public void disable2(int what, IBinder token, String pkg) {
- disableForUser(what, token, pkg, mCurrentUserId);
+ disable2ForUser(what, token, pkg, mCurrentUserId);
}
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b2cd69d9f371..15a10e92eff7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5696,26 +5696,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean setDeviceOwnerLockScreenInfo(ComponentName who, String info) {
+ public void setDeviceOwnerLockScreenInfo(ComponentName who, CharSequence info) {
Preconditions.checkNotNull(who, "ComponentName is null");
if (!mHasFeature) {
- return false;
+ return;
}
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
long token = mInjector.binderClearCallingIdentity();
try {
- mLockPatternUtils.setDeviceOwnerInfo(info);
+ mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
} finally {
mInjector.binderRestoreCallingIdentity(token);
}
- return true;
}
}
@Override
- public String getDeviceOwnerLockScreenInfo() {
+ public CharSequence getDeviceOwnerLockScreenInfo() {
return mLockPatternUtils.getDeviceOwnerInfo();
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0a4effb26249..7b44f98e6d1a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -697,19 +697,19 @@ public final class SystemServer {
// as appropriate.
mSystemServiceManager.startService(UiModeManagerService.class);
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformFstrimIfNeeded");
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "UpdatePackagesIfNeeded");
try {
- mPackageManagerService.performFstrimIfNeeded();
+ mPackageManagerService.updatePackagesIfNeeded();
} catch (Throwable e) {
- reportWtf("performing fstrim", e);
+ reportWtf("update packages", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "ExtractPackagesIfNeeded");
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformFstrimIfNeeded");
try {
- mPackageManagerService.extractPackagesIfNeeded();
+ mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
- reportWtf("extract packages", e);
+ reportWtf("performing fstrim", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
index eb16a1db5876..c44ffa481f8b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
@@ -16,9 +16,16 @@
*/
package com.android.server.pm;
+import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.PersistableBundle;
import android.test.AndroidTestCase;
+import com.android.internal.util.Preconditions;
import com.android.server.testutis.TestUtils;
/**
@@ -33,12 +40,232 @@ import com.android.server.testutis.TestUtils;
*/
public class ShortcutInfoTest extends AndroidTestCase {
- public void testNoId() {
+ public void testMissingMandatoryFields() {
TestUtils.assertExpectException(
IllegalArgumentException.class,
"ID must be provided",
() -> new ShortcutInfo.Builder(mContext).build());
+ TestUtils.assertExpectException(
+ IllegalArgumentException.class,
+ "title must be provided",
+ () -> new ShortcutInfo.Builder(mContext).setId("id").build()
+ .enforceMandatoryFields());
+ TestUtils.assertExpectException(
+ NullPointerException.class,
+ "Intent must be provided",
+ () -> new ShortcutInfo.Builder(mContext).setId("id").setTitle("x").build()
+ .enforceMandatoryFields());
}
- // TODO Add more tests.
+ private ShortcutInfo parceled(ShortcutInfo si) {
+ Parcel p = Parcel.obtain();
+ p.writeParcelable(si, 0);
+ p.setDataPosition(0);
+ ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
+ p.recycle();
+ return si2;
+ }
+
+ private Intent makeIntent(String action, Object... bundleKeysAndValues) {
+ final Intent intent = new Intent(action);
+ intent.replaceExtras(ShortcutManagerTest.makeBundle(bundleKeysAndValues));
+ return intent;
+ }
+
+ public void testParcel() {
+ ShortcutInfo si = parceled(new ShortcutInfo.Builder(getContext())
+ .setId("id")
+ .setTitle("title")
+ .setIntent(makeIntent("action"))
+ .build());
+ assertEquals(getContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+
+ si = new ShortcutInfo.Builder(getContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ si.addFlags(ShortcutInfo.FLAG_PINNED);
+ si.setBitmapPath("abc");
+ si.setIconResourceId(456);
+
+ si = parceled(si);
+
+ assertEquals(getContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals("content://a.b.c/", si.getIcon().getUriString());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals("abc", si.getBitmapPath());
+ assertEquals(456, si.getIconResourceId());
+ }
+
+ public void testClone() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+ sorig.setBitmapPath("abc");
+ sorig.setIconResourceId(456);
+
+ ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+ assertEquals(getContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals("content://a.b.c/", si.getIcon().getUriString());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals("abc", si.getBitmapPath());
+ assertEquals(456, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+ assertEquals(getContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+ assertEquals(getContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals(null, si.getIntent());
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+ assertEquals(getContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(null, si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals(null, si.getTitle());
+ assertEquals(null, si.getText());
+ assertEquals(null, si.getIntent());
+ assertEquals(0, si.getWeight());
+ assertEquals(null, si.getExtras());
+
+ assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+ }
+
+
+ public void testCopyNonNullFieldsFrom() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+ sorig.setBitmapPath("abc");
+ sorig.setIconResourceId(456);
+
+ ShortcutInfo si;
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setActivityComponent(new ComponentName("x", "y")).build());
+ assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+ assertEquals("content://x.y.z/", si.getIcon().getUriString());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setTitle("xyz").build());
+ assertEquals("xyz", si.getTitle());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setText("xxx").build());
+ assertEquals("xxx", si.getText());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setIntent(makeIntent("action2")).build());
+ assertEquals("action2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getStringExtra("key"));
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setIntent(makeIntent("action3", "key", "x")).build());
+ assertEquals("action3", si.getIntent().getAction());
+ assertEquals("x", si.getIntent().getStringExtra("key"));
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setWeight(999).build());
+ assertEquals(999, si.getWeight());
+
+
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("x", 99);
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
+ .setExtras(pb2).build());
+ assertEquals(99, si.getExtras().getInt("x"));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index f034d55d9736..5d2924283ef7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -646,7 +646,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
runTestOnUiThread(() -> {});
}
- private static Bundle makeBundle(Object... keysAndValues) {
+ public static Bundle makeBundle(Object... keysAndValues) {
Preconditions.checkState((keysAndValues.length % 2) == 0);
if (keysAndValues.length == 0) {
diff --git a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
index 52e8f37f0b6c..d2a44841ee0d 100644
--- a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
@@ -24,19 +24,14 @@ public class TestUtils {
}
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
- Runnable r) {
- assertExpectException(expectedExceptionType, null, r);
- }
-
- public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
String expectedExceptionMessageRegex, Runnable r) {
try {
r.run();
- Assert.fail("Expected exception type " + expectedExceptionType.getClass().getName()
+ Assert.fail("Expected exception type " + expectedExceptionType.getName()
+ " was not thrown");
} catch (Throwable e) {
Assert.assertTrue(
- "Expected exception type was " + expectedExceptionType.getClass().getName()
+ "Expected exception type was " + expectedExceptionType.getName()
+ " but caught " + e.getClass().getName(),
expectedExceptionType.isAssignableFrom(e.getClass()));
if (expectedExceptionMessageRegex != null) {