diff options
93 files changed, 1999 insertions, 900 deletions
diff --git a/api/current.txt b/api/current.txt index 897a8d9ab609..c38d8379821d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -47620,6 +47620,7 @@ package android.view { method public void forceLayout(); method public static int generateViewId(); method public java.lang.CharSequence getAccessibilityClassName(); + method public android.view.View.AccessibilityDelegate getAccessibilityDelegate(); method public int getAccessibilityLiveRegion(); method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(); method public java.lang.CharSequence getAccessibilityPaneTitle(); diff --git a/api/system-current.txt b/api/system-current.txt index 6a00815e78a8..cb7f7bb365b3 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6042,12 +6042,16 @@ package android.telephony.ims { ctor public ImsSsInfo(int, java.lang.String); method public int describeContents(); method public java.lang.String getIcbNum(); + method public int getProvisionStatus(); method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSsInfo> CREATOR; field public static final int DISABLED = 0; // 0x0 field public static final int ENABLED = 1; // 0x1 field public static final int NOT_REGISTERED = -1; // 0xffffffff + field public static final int SERVICE_NOT_PROVISIONED = 0; // 0x0 + field public static final int SERVICE_PROVISIONED = 1; // 0x1 + field public static final int SERVICE_PROVISIONING_UNKNOWN = -1; // 0xffffffff } public final class ImsStreamMediaProfile implements android.os.Parcelable { diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp index 5cc4fc4c16b2..b3e287bae76a 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.cpp +++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp @@ -42,7 +42,6 @@ namespace android { namespace uhid { static const char* UHID_PATH = "/dev/uhid"; -static const size_t UHID_MAX_NAME_LENGTH = 128; static struct { jmethodID onDeviceOpen; @@ -90,8 +89,13 @@ JNIEnv* DeviceCallback::getJNIEnv() { } Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid, - std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize, - std::unique_ptr<DeviceCallback> callback) { + std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback) { + + size_t size = descriptor.size(); + if (size > HID_MAX_DESCRIPTOR_SIZE) { + LOGE("Received invalid hid report with descriptor size %zu, skipping", size); + return nullptr; + } int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC); if (fd < 0) { @@ -102,10 +106,10 @@ Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid, struct uhid_event ev; memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE2; - strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH); - memcpy(&ev.u.create2.rd_data, descriptor.get(), - descriptorSize * sizeof(ev.u.create2.rd_data[0])); - ev.u.create2.rd_size = descriptorSize; + strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name)); + memcpy(&ev.u.create2.rd_data, descriptor.data(), + size * sizeof(ev.u.create2.rd_data[0])); + ev.u.create2.rd_size = size; ev.u.create2.bus = BUS_BLUETOOTH; ev.u.create2.vendor = vid; ev.u.create2.product = pid; @@ -156,12 +160,17 @@ Device::~Device() { mFd = -1; } -void Device::sendReport(uint8_t* report, size_t reportSize) { +void Device::sendReport(const std::vector<uint8_t>& report) const { + if (report.size() > UHID_DATA_MAX) { + LOGE("Received invalid report of size %zu, skipping", report.size()); + return; + } + struct uhid_event ev; memset(&ev, 0, sizeof(ev)); ev.type = UHID_INPUT2; - ev.u.input2.size = reportSize; - memcpy(&ev.u.input2.data, report, reportSize); + ev.u.input2.size = report.size(); + memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0])); ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { LOGE("Failed to send hid event: %s", strerror(errno)); @@ -191,12 +200,13 @@ int Device::handleEvents(int events) { } // namespace uhid -std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) { +std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) { ScopedByteArrayRO scopedArray(env, javaArray); - outSize = scopedArray.size(); - std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]); - for (size_t i = 0; i < outSize; i++) { - data[i] = static_cast<uint8_t>(scopedArray[i]); + size_t size = scopedArray.size(); + std::vector<uint8_t> data; + data.reserve(size); + for (size_t i = 0; i < size; i++) { + data.push_back(static_cast<uint8_t>(scopedArray[i])); } return data; } @@ -208,23 +218,20 @@ static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint i return 0; } - size_t size; - std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size); + std::vector<uint8_t> desc = getData(env, rawDescriptor); std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback)); uhid::Device* d = uhid::Device::open( - id, reinterpret_cast<const char*>(name.c_str()), vid, pid, - std::move(desc), size, std::move(cb)); + id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, std::move(cb)); return reinterpret_cast<jlong>(d); } static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) { - size_t size; - std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size); + std::vector<uint8_t> report = getData(env, rawReport); uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr); if (d) { - d->sendReport(report.get(), size); + d->sendReport(report); } else { LOGE("Could not send report, Device* is null!"); } diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h index 149456d8c10d..61a1f760697f 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.h +++ b/cmds/hid/jni/com_android_commands_hid_Device.h @@ -15,6 +15,7 @@ */ #include <memory> +#include <vector> #include <jni.h> @@ -38,13 +39,12 @@ private: class Device { public: static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid, - std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize, - std::unique_ptr<DeviceCallback> callback); + std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback); Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback); ~Device(); - void sendReport(uint8_t* report, size_t reportSize); + void sendReport(const std::vector<uint8_t>& report) const; void close(); int handleEvents(int events); diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp index 691356b5edc6..35e03e45c785 100644 --- a/cmds/statsd/src/condition/condition_util.cpp +++ b/cmds/statsd/src/condition/condition_util.cpp @@ -76,9 +76,9 @@ ConditionState evaluateCombinationCondition(const std::vector<int>& children, break; } case LogicalOperation::NOT: - newCondition = (conditionCache[children[0]] == ConditionState::kFalse) - ? ConditionState::kTrue - : ConditionState::kFalse; + newCondition = children.empty() ? ConditionState::kUnknown : + ((conditionCache[children[0]] == ConditionState::kFalse) ? + ConditionState::kTrue : ConditionState::kFalse); break; case LogicalOperation::NAND: newCondition = hasFalse ? ConditionState::kTrue : ConditionState::kFalse; diff --git a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp index 23d69267d1c0..6529d65a5825 100644 --- a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp @@ -40,6 +40,7 @@ TEST(ConditionTrackerTest, TestUnknownCondition) { EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults), ConditionState::kUnknown); } + TEST(ConditionTrackerTest, TestAndCondition) { // Set up the matcher LogicalOperation operation = LogicalOperation::AND; @@ -103,6 +104,11 @@ TEST(ConditionTrackerTest, TestNotCondition) { conditionResults.clear(); conditionResults.push_back(ConditionState::kFalse); EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults)); + + children.clear(); + conditionResults.clear(); + EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults), + ConditionState::kUnknown); } TEST(ConditionTrackerTest, TestNandCondition) { diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 4f60b0c52942..bc4ed1543d40 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -964,22 +964,6 @@ Landroid/app/WallpaperManager;->openDefaultWallpaper(Landroid/content/Context;I) Landroid/app/WallpaperManager;->setBitmap(Landroid/graphics/Bitmap;Landroid/graphics/Rect;ZII)I Landroid/app/WallpaperManager;->setWallpaperComponent(Landroid/content/ComponentName;I)Z Landroid/app/WallpaperManager;->sGlobals:Landroid/app/WallpaperManager$Globals; -Landroid/appwidget/AppWidgetHost;-><init>(Landroid/content/Context;ILandroid/widget/RemoteViews$OnClickHandler;Landroid/os/Looper;)V -Landroid/appwidget/AppWidgetHost;->HANDLE_VIEW_DATA_CHANGED:I -Landroid/appwidget/AppWidgetHost;->mHandler:Landroid/os/Handler; -Landroid/appwidget/AppWidgetHost;->sService:Lcom/android/internal/appwidget/IAppWidgetService; -Landroid/appwidget/AppWidgetHostView;->getDefaultPaddingForWidget(Landroid/content/Context;Landroid/content/pm/ApplicationInfo;Landroid/graphics/Rect;)Landroid/graphics/Rect; -Landroid/appwidget/AppWidgetHostView;->mAppWidgetId:I -Landroid/appwidget/AppWidgetHostView;->mInfo:Landroid/appwidget/AppWidgetProviderInfo; -Landroid/appwidget/AppWidgetHostView;->updateAppWidgetSize(Landroid/os/Bundle;IIIIZ)V -Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;)V -Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;Landroid/os/Bundle;)V -Landroid/appwidget/AppWidgetManager;->bindAppWidgetIdIfAllowed(IILandroid/content/ComponentName;Landroid/os/Bundle;)Z -Landroid/appwidget/AppWidgetManager;->bindRemoteViewsService(Landroid/content/Context;ILandroid/content/Intent;Landroid/app/IServiceConnection;I)Z -Landroid/appwidget/AppWidgetManager;->getInstalledProviders(I)Ljava/util/List; -Landroid/appwidget/AppWidgetManager;->getInstalledProvidersForProfile(ILandroid/os/UserHandle;Ljava/lang/String;)Ljava/util/List; -Landroid/appwidget/AppWidgetManager;->mService:Lcom/android/internal/appwidget/IAppWidgetService; -Landroid/appwidget/AppWidgetProviderInfo;->providerInfo:Landroid/content/pm/ActivityInfo; Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String; Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I Landroid/bluetooth/IBluetooth$Stub;-><init>()V @@ -1849,18 +1833,6 @@ Landroid/icu/util/UResourceBundle;->getString()Ljava/lang/String; Landroid/icu/util/UResourceBundle;->getType()I Landroid/icu/util/UResourceBundleIterator;->hasNext()Z Landroid/icu/util/UResourceBundleIterator;->next()Landroid/icu/util/UResourceBundle; -Landroid/location/Country;-><init>(Ljava/lang/String;I)V -Landroid/location/Country;->getCountryIso()Ljava/lang/String; -Landroid/location/Country;->getSource()I -Landroid/location/CountryDetector;-><init>(Landroid/location/ICountryDetector;)V -Landroid/location/CountryDetector;->addCountryListener(Landroid/location/CountryListener;Landroid/os/Looper;)V -Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country; -Landroid/location/CountryDetector;->removeCountryListener(Landroid/location/CountryListener;)V -Landroid/location/CountryListener;->onCountryDetected(Landroid/location/Country;)V -Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String; -Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale; -Landroid/location/Geofence;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/location/GpsStatus;->setTimeToFirstFix(I)V Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector; Landroid/location/ICountryListener$Stub;-><init>()V Landroid/location/IGeocodeProvider$Stub;-><init>()V @@ -1879,25 +1851,6 @@ Landroid/location/ILocationManager$Stub;-><init>()V Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager; Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List; -Landroid/location/Location;->mElapsedRealtimeNanos:J -Landroid/location/Location;->mProvider:Ljava/lang/String; -Landroid/location/LocationManager;->mService:Landroid/location/ILocationManager; -Landroid/location/LocationManager;->requestLocationUpdates(Landroid/location/LocationRequest;Landroid/location/LocationListener;Landroid/os/Looper;Landroid/app/PendingIntent;)V -Landroid/location/LocationManager;->sendNiResponse(II)Z -Landroid/location/LocationRequest;->checkDisplacement(F)V -Landroid/location/LocationRequest;->checkInterval(J)V -Landroid/location/LocationRequest;->checkProvider(Ljava/lang/String;)V -Landroid/location/LocationRequest;->checkQuality(I)V -Landroid/location/LocationRequest;->mExpireAt:J -Landroid/location/LocationRequest;->mExplicitFastestInterval:Z -Landroid/location/LocationRequest;->mFastestInterval:J -Landroid/location/LocationRequest;->mHideFromAppOps:Z -Landroid/location/LocationRequest;->mInterval:J -Landroid/location/LocationRequest;->mNumUpdates:I -Landroid/location/LocationRequest;->mProvider:Ljava/lang/String; -Landroid/location/LocationRequest;->mQuality:I -Landroid/location/LocationRequest;->mSmallestDisplacement:F -Landroid/location/LocationRequest;->mWorkSource:Landroid/os/WorkSource; Landroid/media/AmrInputStream;-><init>(Ljava/io/InputStream;)V Landroid/media/AsyncPlayer;->setUsesWakeLock(Landroid/content/Context;)V Landroid/media/AudioAttributes$Builder;->addTag(Ljava/lang/String;)Landroid/media/AudioAttributes$Builder; @@ -2366,10 +2319,6 @@ Landroid/media/VolumeShaper$State;-><init>(FF)V Landroid/media/VolumeShaper$State;->mVolume:F Landroid/media/VolumeShaper$State;->mXOffset:F Landroid/media/WebVttRenderer;-><init>(Landroid/content/Context;)V -Landroid/mtp/MtpPropertyList;->append(IIIJ)V -Landroid/mtp/MtpPropertyList;->append(IILjava/lang/String;)V -Landroid/mtp/MtpStorage;->getPath()Ljava/lang/String; -Landroid/mtp/MtpStorage;->getStorageId()I Landroid/net/ConnectivityManager;->ACTION_TETHER_STATE_CHANGED:Ljava/lang/String; Landroid/net/ConnectivityManager;->EXTRA_ACTIVE_TETHER:Ljava/lang/String; Landroid/net/ConnectivityManager;->EXTRA_AVAILABLE_TETHER:Ljava/lang/String; @@ -2847,13 +2796,6 @@ Landroid/nfc/INfcAdapterExtras;->getDriverName(Ljava/lang/String;)Ljava/lang/Str Landroid/nfc/INfcAdapterExtras;->open(Ljava/lang/String;Landroid/os/IBinder;)Landroid/os/Bundle; Landroid/nfc/INfcAdapterExtras;->setCardEmulationRoute(Ljava/lang/String;I)V Landroid/nfc/INfcAdapterExtras;->transceive(Ljava/lang/String;[B)Landroid/os/Bundle; -Landroid/opengl/EGL14;->eglGetDisplay(J)Landroid/opengl/EGLDisplay; -Landroid/opengl/GLES20;->glGetActiveAttrib(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V -Landroid/opengl/GLES20;->glGetActiveUniform(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V -Landroid/opengl/GLSurfaceView$EglHelper;->mEglContext:Ljavax/microedition/khronos/egl/EGLContext; -Landroid/opengl/GLSurfaceView$GLThread;->mEglHelper:Landroid/opengl/GLSurfaceView$EglHelper; -Landroid/opengl/GLSurfaceView;->mGLThread:Landroid/opengl/GLSurfaceView$GLThread; -Landroid/opengl/GLSurfaceView;->mRenderer:Landroid/opengl/GLSurfaceView$Renderer; Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;)Landroid/os/AsyncResult; Landroid/os/AsyncTask;->mFuture:Ljava/util/concurrent/FutureTask; Landroid/os/AsyncTask;->mStatus:Landroid/os/AsyncTask$Status; @@ -5233,7 +5175,6 @@ Landroid/view/View;->ensureTransformationInfo()V Landroid/view/View;->findViewByAccessibilityId(I)Landroid/view/View; Landroid/view/View;->fitsSystemWindows()Z Landroid/view/View;->gatherTransparentRegion(Landroid/graphics/Region;)Z -Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; Landroid/view/View;->getAccessibilityViewId()I Landroid/view/View;->getBoundsOnScreen(Landroid/graphics/Rect;)V Landroid/view/View;->getBoundsOnScreen(Landroid/graphics/Rect;Z)V diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 4b4250d12e9c..2808166f7a5b 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -55,15 +55,6 @@ Landroid/app/TaskStackListener;->onTaskSnapshotChanged(ILandroid/app/ActivityMan Landroid/app/TaskStackListener;->onTaskStackChanged()V Landroid/app/WallpaperColors;-><init>(Landroid/graphics/Color;Landroid/graphics/Color;Landroid/graphics/Color;I)V Landroid/bluetooth/IBluetooth;->sendConnectionStateChange(Landroid/bluetooth/BluetoothDevice;III)V -Landroid/companion/AssociationRequest;->getDeviceFilters()Ljava/util/List; -Landroid/companion/AssociationRequest;->isSingleDevice()Z -Landroid/companion/BluetoothDeviceFilter;->getAddress()Ljava/lang/String; -Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceDisplayNameInternal(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String; -Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceDisplayNameInternal(Landroid/net/wifi/ScanResult;)Ljava/lang/String; -Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceMacAddress(Landroid/os/Parcelable;)Ljava/lang/String; -Landroid/companion/BluetoothLeDeviceFilter;->getScanFilter()Landroid/bluetooth/le/ScanFilter; -Landroid/companion/DeviceFilter;->getDeviceDisplayName(Landroid/os/Parcelable;)Ljava/lang/String; -Landroid/companion/DeviceFilter;->matches(Landroid/os/Parcelable;)Z Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V @@ -99,7 +90,6 @@ Landroid/location/ILocationManager;->getNetworkProviderPackage()Ljava/lang/Strin Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V Landroid/location/INetInitiatedListener$Stub;-><init>()V Landroid/location/INetInitiatedListener;->sendNiResponse(II)Z -Landroid/location/Location;->setExtraLocation(Ljava/lang/String;Landroid/location/Location;)V Landroid/media/AudioManager;->registerAudioPortUpdateListener(Landroid/media/AudioManager$OnAudioPortUpdateListener;)V Landroid/media/AudioManager;->unregisterAudioPortUpdateListener(Landroid/media/AudioManager$OnAudioPortUpdateListener;)V Landroid/media/AudioSystem;->checkAudioFlinger()I diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index 49cc498cffa2..f003d4bea028 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -18,6 +18,7 @@ package android.appwidget; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; @@ -53,14 +54,17 @@ public class AppWidgetHost { static final int HANDLE_UPDATE = 1; static final int HANDLE_PROVIDER_CHANGED = 2; static final int HANDLE_PROVIDERS_CHANGED = 3; + @UnsupportedAppUsage static final int HANDLE_VIEW_DATA_CHANGED = 4; final static Object sServiceLock = new Object(); + @UnsupportedAppUsage static IAppWidgetService sService; static boolean sServiceInitialized = false; private DisplayMetrics mDisplayMetrics; private String mContextOpPackageName; + @UnsupportedAppUsage private final Handler mHandler; private final int mHostId; private final Callbacks mCallbacks; @@ -156,6 +160,7 @@ public class AppWidgetHost { /** * @hide */ + @UnsupportedAppUsage public AppWidgetHost(Context context, int hostId, OnClickHandler handler, Looper looper) { mContextOpPackageName = context.getOpPackageName(); mHostId = hostId; diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index ab0eb92e1726..a9187b65a359 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -16,6 +16,7 @@ package android.appwidget; +import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -70,7 +71,9 @@ public class AppWidgetHostView extends FrameLayout { Context mContext; Context mRemoteContext; + @UnsupportedAppUsage int mAppWidgetId; + @UnsupportedAppUsage AppWidgetProviderInfo mInfo; View mView; int mViewMode = VIEW_MODE_NOINIT; @@ -174,6 +177,7 @@ public class AppWidgetHostView extends FrameLayout { return getDefaultPaddingForWidget(context, appInfo, padding); } + @UnsupportedAppUsage private static Rect getDefaultPaddingForWidget(Context context, ApplicationInfo appInfo, Rect padding) { if (padding == null) { @@ -284,6 +288,7 @@ public class AppWidgetHostView extends FrameLayout { /** * @hide */ + @UnsupportedAppUsage public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth, int maxHeight, boolean ignorePadding) { if (newOptions == null) { diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 20248b90d1e9..dbc1c199cb4d 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -23,6 +23,7 @@ import android.annotation.RequiresFeature; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; +import android.annotation.UnsupportedAppUsage; import android.app.IServiceConnection; import android.app.PendingIntent; import android.content.ComponentName; @@ -463,6 +464,7 @@ public class AppWidgetManager { private final Context mContext; private final String mPackageName; + @UnsupportedAppUsage private final IAppWidgetService mService; private final DisplayMetrics mDisplayMetrics; @@ -816,6 +818,7 @@ public class AppWidgetManager { * * @hide */ + @UnsupportedAppUsage public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) { if (mService == null) { return Collections.emptyList(); @@ -842,6 +845,7 @@ public class AppWidgetManager { * * @hide */ + @UnsupportedAppUsage public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, @Nullable UserHandle profile, @Nullable String packageName) { if (mService == null) { @@ -902,6 +906,7 @@ public class AppWidgetManager { * provider for this AppWidget. * @hide */ + @UnsupportedAppUsage public void bindAppWidgetId(int appWidgetId, ComponentName provider) { if (mService == null) { return; @@ -924,6 +929,7 @@ public class AppWidgetManager { * * @hide */ + @UnsupportedAppUsage public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) { if (mService == null) { return; @@ -1094,6 +1100,7 @@ public class AppWidgetManager { * @see Context#getServiceDispatcher(ServiceConnection, Handler, int) * @hide */ + @UnsupportedAppUsage public boolean bindRemoteViewsService(Context context, int appWidgetId, Intent intent, IServiceConnection connection, @Context.BindServiceFlags int flags) { if (mService == null) { @@ -1139,6 +1146,7 @@ public class AppWidgetManager { } } + @UnsupportedAppUsage private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId, ComponentName provider, Bundle options) { if (mService == null) { diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 6dd85caad628..53315cce82dd 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -18,6 +18,7 @@ package android.appwidget; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -270,6 +271,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int widgetFeatures; /** @hide */ + @UnsupportedAppUsage public ActivityInfo providerInfo; public AppWidgetProviderInfo() { diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java index 922224a5d718..db54f08d815c 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -18,6 +18,7 @@ package android.companion; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.provider.OneTimeUseBuilder; @@ -59,12 +60,14 @@ public final class AssociationRequest implements Parcelable { } /** @hide */ + @UnsupportedAppUsage public boolean isSingleDevice() { return mSingleDevice; } /** @hide */ @NonNull + @UnsupportedAppUsage public List<DeviceFilter<?>> getDeviceFilters() { return mDeviceFilters; } diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java index 84e15364c191..7507e174a749 100644 --- a/core/java/android/companion/BluetoothDeviceFilter.java +++ b/core/java/android/companion/BluetoothDeviceFilter.java @@ -25,6 +25,7 @@ import static android.companion.BluetoothDeviceFilterUtils.patternToString; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; import android.os.Parcel; import android.os.ParcelUuid; @@ -99,6 +100,7 @@ public final class BluetoothDeviceFilter implements DeviceFilter<BluetoothDevice /** @hide */ @Nullable + @UnsupportedAppUsage public String getAddress() { return mAddress; } diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java index 4ee38fe4990e..bd507a6b8bcc 100644 --- a/core/java/android/companion/BluetoothDeviceFilterUtils.java +++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java @@ -21,6 +21,7 @@ import static android.text.TextUtils.firstNotEmpty; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.ScanFilter; import android.net.wifi.ScanResult; @@ -124,14 +125,17 @@ public class BluetoothDeviceFilterUtils { Log.i(LOG_TAG, getDeviceDisplayNameInternal(device) + (result ? " ~ " : " !~ ") + criteria); } + @UnsupportedAppUsage public static String getDeviceDisplayNameInternal(@NonNull BluetoothDevice device) { return firstNotEmpty(device.getAliasName(), device.getAddress()); } + @UnsupportedAppUsage public static String getDeviceDisplayNameInternal(@NonNull ScanResult device) { return firstNotEmpty(device.SSID, device.BSSID); } + @UnsupportedAppUsage public static String getDeviceMacAddress(@NonNull Parcelable device) { if (device instanceof BluetoothDevice) { return ((BluetoothDevice) device).getAddress(); diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java index 7fb768c67386..1de931eeb675 100644 --- a/core/java/android/companion/BluetoothLeDeviceFilter.java +++ b/core/java/android/companion/BluetoothLeDeviceFilter.java @@ -25,6 +25,7 @@ import static com.android.internal.util.Preconditions.checkState; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; @@ -92,6 +93,7 @@ public final class BluetoothLeDeviceFilter implements DeviceFilter<ScanResult> { /** @hide */ @NonNull + @UnsupportedAppUsage public ScanFilter getScanFilter() { return mScanFilter; } diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java index 10135a451dda..dc7cf82613e6 100644 --- a/core/java/android/companion/DeviceFilter.java +++ b/core/java/android/companion/DeviceFilter.java @@ -19,6 +19,7 @@ package android.companion; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.os.Parcelable; import java.lang.annotation.Retention; @@ -44,9 +45,11 @@ public interface DeviceFilter<D extends Parcelable> extends Parcelable { * * @hide */ + @UnsupportedAppUsage boolean matches(D device); /** @hide */ + @UnsupportedAppUsage String getDeviceDisplayName(D device); /** @hide */ diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java index 93fa403b760b..b06dd7ae7b32 100644 --- a/core/java/android/content/ContentValues.java +++ b/core/java/android/content/ContentValues.java @@ -21,9 +21,12 @@ import android.os.Parcelable; import android.util.ArrayMap; import android.util.Log; +import com.android.internal.util.Preconditions; + import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -55,6 +58,7 @@ public final class ContentValues implements Parcelable { * @param size the initial size of the set of values */ public ContentValues(int size) { + Preconditions.checkArgumentNonnegative(size); mMap = new ArrayMap<>(size); } @@ -64,6 +68,7 @@ public final class ContentValues implements Parcelable { * @param from the values to copy */ public ContentValues(ContentValues from) { + Objects.requireNonNull(from); mMap = new ArrayMap<>(from.mMap); } diff --git a/core/java/android/database/RedactingCursor.java b/core/java/android/database/RedactingCursor.java new file mode 100644 index 000000000000..6322d56ee31f --- /dev/null +++ b/core/java/android/database/RedactingCursor.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.database; + +import android.annotation.NonNull; +import android.util.SparseArray; + +import java.util.Map; + +/** + * Cursor that offers to redact values of requested columns. + * + * @hide + */ +public class RedactingCursor extends CrossProcessCursorWrapper { + private final SparseArray<Object> mRedactions; + + private RedactingCursor(@NonNull Cursor cursor, SparseArray<Object> redactions) { + super(cursor); + mRedactions = redactions; + } + + /** + * Create a wrapped instance of the given {@link Cursor} which redacts the + * requested columns so they always return specific values when accessed. + * <p> + * If a redacted column appears multiple times in the underlying cursor, all + * instances will be redacted. If none of the redacted columns appear in the + * given cursor, the given cursor will be returned untouched to improve + * performance. + */ + public static Cursor create(@NonNull Cursor cursor, @NonNull Map<String, Object> redactions) { + final SparseArray<Object> internalRedactions = new SparseArray<>(); + + final String[] columns = cursor.getColumnNames(); + for (int i = 0; i < columns.length; i++) { + if (redactions.containsKey(columns[i])) { + internalRedactions.put(i, redactions.get(columns[i])); + } + } + + if (internalRedactions.size() == 0) { + return cursor; + } else { + return new RedactingCursor(cursor, internalRedactions); + } + } + + @Override + public void fillWindow(int position, CursorWindow window) { + // Fill window directly to ensure data is redacted + DatabaseUtils.cursorFillWindow(this, position, window); + } + + @Override + public CursorWindow getWindow() { + // Returning underlying window risks leaking redacted data + return null; + } + + @Override + public Cursor getWrappedCursor() { + throw new UnsupportedOperationException( + "Returning underlying cursor risks leaking redacted data"); + } + + @Override + public double getDouble(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (double) mRedactions.valueAt(i); + } else { + return super.getDouble(columnIndex); + } + } + + @Override + public float getFloat(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (float) mRedactions.valueAt(i); + } else { + return super.getFloat(columnIndex); + } + } + + @Override + public int getInt(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (int) mRedactions.valueAt(i); + } else { + return super.getInt(columnIndex); + } + } + + @Override + public long getLong(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (long) mRedactions.valueAt(i); + } else { + return super.getLong(columnIndex); + } + } + + @Override + public short getShort(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (short) mRedactions.valueAt(i); + } else { + return super.getShort(columnIndex); + } + } + + @Override + public String getString(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (String) mRedactions.valueAt(i); + } else { + return super.getString(columnIndex); + } + } + + @Override + public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + buffer.data = ((String) mRedactions.valueAt(i)).toCharArray(); + buffer.sizeCopied = buffer.data.length; + } else { + super.copyStringToBuffer(columnIndex, buffer); + } + } + + @Override + public byte[] getBlob(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return (byte[]) mRedactions.valueAt(i); + } else { + return super.getBlob(columnIndex); + } + } + + @Override + public int getType(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return DatabaseUtils.getTypeOfObject(mRedactions.valueAt(i)); + } else { + return super.getType(columnIndex); + } + } + + @Override + public boolean isNull(int columnIndex) { + final int i = mRedactions.indexOfKey(columnIndex); + if (i >= 0) { + return mRedactions.valueAt(i) == null; + } else { + return super.isNull(columnIndex); + } + } +} diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index d6d9764c7c38..e6b6acf7b8ee 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -39,11 +39,18 @@ import android.os.SystemProperties; public final class SQLiteGlobal { private static final String TAG = "SQLiteGlobal"; + /** @hide */ + public static final String SYNC_MODE_FULL = "FULL"; + private static final Object sLock = new Object(); + private static int sDefaultPageSize; private static native int nativeReleaseMemory(); + /** @hide */ + public static volatile String sDefaultSyncMode; + private SQLiteGlobal() { } @@ -103,6 +110,11 @@ public final class SQLiteGlobal { * Gets the default database synchronization mode when WAL is not in use. */ public static String getDefaultSyncMode() { + // Use the FULL synchronous mode for system processes by default. + String defaultMode = sDefaultSyncMode; + if (defaultMode != null) { + return defaultMode; + } return SystemProperties.get("debug.sqlite.syncmode", Resources.getSystem().getString( com.android.internal.R.string.db_default_sync_mode)); @@ -112,6 +124,11 @@ public final class SQLiteGlobal { * Gets the database synchronization mode when in WAL mode. */ public static String getWALSyncMode() { + // Use the FULL synchronous mode for system processes by default. + String defaultMode = sDefaultSyncMode; + if (defaultMode != null) { + return defaultMode; + } return SystemProperties.get("debug.sqlite.wal.syncmode", Resources.getSystem().getString( com.android.internal.R.string.db_wal_sync_mode)); diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 52a2354840c9..081d8d1290ac 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -372,7 +372,7 @@ public abstract class NetworkAgent extends Handler { if (score < 0) { throw new IllegalArgumentException("Score must be >= 0"); } - queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); + queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0); } /** diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 5752b6f54ce5..591370ff728b 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -241,6 +241,9 @@ public final class BinderProxy implements IBinder { } else { try { key = bp.getInterfaceDescriptor(); + if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) { + key = "<proxy to dead node>"; + } } catch (Throwable t) { key = "<exception during getDescriptor>"; } diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 9c3a40995c77..68572dd2a52e 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -469,6 +469,12 @@ public final class MediaStore { * The height of the image/video in pixels. */ public static final String HEIGHT = "height"; + + /** + * Package that contributed this media. + * @hide + */ + public static final String OWNER_PACKAGE_NAME = "owner_package_name"; } /** diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 131fe1395585..092702ca30cf 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -421,8 +421,8 @@ interface IWindowManager boolean isWindowTraceEnabled(); /** - * Requests that the WindowManager sends WindowManagerPolicy#ACTION_USER_ACTIVITY_NOTIFICATION - * on the next user activity. + * Requests that the WindowManager sends + * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity. */ void requestUserActivityNotification(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e2e2b000d2fd..65ab3ace8c26 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9008,8 +9008,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * composition. For more details see {@link AccessibilityDelegate}. * * @return The delegate, or null if none set. - * - * @hide */ public AccessibilityDelegate getAccessibilityDelegate() { return mAccessibilityDelegate; diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 17ab9563d372..e64d2afe7bf3 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -96,7 +96,7 @@ static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass) return toJavaStringArray(env, cStrings); } -static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::DisabledChecks checks) { +static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckFlags::Type checks) { std::vector<std::string> cPackageInfo; if (packageInfo) { size_t count = env->GetArrayLength(packageInfo); @@ -116,11 +116,11 @@ static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::Disabl } static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) { - return verify(env, packageInfo, ::android::vintf::ENABLE_ALL_CHECKS); + return verify(env, packageInfo, ::android::vintf::CheckFlags::ENABLE_ALL_CHECKS); } static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) { - return verify(env, nullptr, ::android::vintf::DISABLE_AVB_CHECK); + return verify(env, nullptr, ::android::vintf::CheckFlags::DISABLE_AVB_CHECK); } static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) { diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 48113df0c5ff..3db7f9d6b555 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -265,11 +265,10 @@ message WindowStateProto { optional int32 stack_id = 4; optional .android.view.WindowLayoutParamsProto attributes = 5; optional .android.graphics.RectProto given_content_insets = 6; - reserved 7 to 10; -// optional .android.graphics.RectProto frame = 7; -// optional .android.graphics.RectProto containing_frame = 8; -// optional .android.graphics.RectProto parent_frame = 9; -// optional .android.graphics.RectProto content_frame = 10; + optional .android.graphics.RectProto frame = 7 [deprecated=true]; + optional .android.graphics.RectProto containing_frame = 8 [deprecated=true]; + optional .android.graphics.RectProto parent_frame = 9 [deprecated=true]; + optional .android.graphics.RectProto content_frame = 10 [deprecated=true]; optional .android.graphics.RectProto content_insets = 11; optional .android.graphics.RectProto surface_insets = 12; optional WindowStateAnimatorProto animator = 13; @@ -282,18 +281,16 @@ message WindowStateProto { optional int32 system_ui_visibility = 21; optional bool has_surface = 22; optional bool is_ready_for_display = 23; - reserved 24 to 28; -// optional .android.graphics.RectProto display_frame = 24; -// optional .android.graphics.RectProto overscan_frame = 25; -// optional .android.graphics.RectProto visible_frame = 26; -// optional .android.graphics.RectProto decor_frame = 27; -// optional .android.graphics.RectProto outset_frame = 28; + optional .android.graphics.RectProto display_frame = 24 [deprecated=true]; + optional .android.graphics.RectProto overscan_frame = 25 [deprecated=true]; + optional .android.graphics.RectProto visible_frame = 26 [deprecated=true]; + optional .android.graphics.RectProto decor_frame = 27 [deprecated=true]; + optional .android.graphics.RectProto outset_frame = 28 [deprecated=true]; optional .android.graphics.RectProto overscan_insets = 29; optional .android.graphics.RectProto visible_insets = 30; optional .android.graphics.RectProto stable_insets = 31; optional .android.graphics.RectProto outsets = 32; - reserved 33; -// optional .android.view.DisplayCutoutProto cutout = 33; + optional .android.view.DisplayCutoutProto cutout = 33 [deprecated=true]; optional bool remove_on_exit = 34; optional bool destroying = 35; optional bool removed = 36; diff --git a/core/res/res/anim/keyguard_occlude_open_enter.xml b/core/res/res/anim/keyguard_occlude_open_enter.xml deleted file mode 100644 index e742616abec4..000000000000 --- a/core/res/res/anim/keyguard_occlude_open_enter.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false"> - <translate - android:fromYDelta="90%" - android:toYDelta="0%" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="400"/> - <alpha - android:fromAlpha="0.0" - android:toAlpha="1.0" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="300"/> -</set> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 140bb7d8704a..2f45cce18ff2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2156,7 +2156,6 @@ <java-symbol type="anim" name="push_down_out" /> <java-symbol type="anim" name="push_up_in" /> <java-symbol type="anim" name="push_up_out" /> - <java-symbol type="anim" name="keyguard_occlude_open_enter" /> <java-symbol type="anim" name="lock_screen_behind_enter" /> <java-symbol type="anim" name="lock_screen_behind_enter_wallpaper" /> <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" /> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 2a906ae158de..d704957a7666 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1301,6 +1301,11 @@ android:process=":MemoryFileProvider"> </provider> + <provider android:name="android.content.RedactingProvider" + android:authorities="android.content.RedactingProvider" + android:process=":RedactingProvider"> + </provider> + <!-- Application components used for os tests --> <service android:name="android.os.MessengerService" diff --git a/core/tests/coretests/src/android/content/RedactingProvider.java b/core/tests/coretests/src/android/content/RedactingProvider.java new file mode 100644 index 000000000000..e2ad44875e6c --- /dev/null +++ b/core/tests/coretests/src/android/content/RedactingProvider.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.database.Cursor; +import android.database.MatrixCursor; +import android.database.RedactingCursor; +import android.net.Uri; +import android.util.ArrayMap; + +public class RedactingProvider extends ContentProvider { + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + switch (uri.getLastPathSegment()) { + case "missing": { + final MatrixCursor cursor = new MatrixCursor( + new String[] { "name", "size", "_data" }); + cursor.addRow(new Object[] { "foo", 10, "/path/to/foo" }); + cursor.addRow(new Object[] { "bar", 20, "/path/to/bar" }); + + final ArrayMap<String, Object> redactions = new ArrayMap<>(); + redactions.put("missing", null); + return RedactingCursor.create(cursor, redactions); + } + case "single": { + final MatrixCursor cursor = new MatrixCursor( + new String[] { "name", "size", "_data" }); + cursor.addRow(new Object[] { "foo", 10, "/path/to/foo" }); + cursor.addRow(new Object[] { "bar", 20, "/path/to/bar" }); + + final ArrayMap<String, Object> redactions = new ArrayMap<>(); + redactions.put("name", null); + redactions.put("_data", "/dev/null"); + return RedactingCursor.create(cursor, redactions); + } + case "multiple": { + final MatrixCursor cursor = new MatrixCursor( + new String[] { "_data", "name", "_data" }); + cursor.addRow(new Object[] { "/path", "foo", "/path" }); + + final ArrayMap<String, Object> redactions = new ArrayMap<>(); + redactions.put("_data", null); + return RedactingCursor.create(cursor, redactions); + } + } + + throw new UnsupportedOperationException(); + } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException(); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException(); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException(); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException(); + } +} diff --git a/core/tests/coretests/src/android/database/RedactingCursorTest.java b/core/tests/coretests/src/android/database/RedactingCursorTest.java new file mode 100644 index 000000000000..93998f3db05f --- /dev/null +++ b/core/tests/coretests/src/android/database/RedactingCursorTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.database; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.net.Uri; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class RedactingCursorTest { + private Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Test + public void testMissing() throws Exception { + final Cursor redacting = getContext().getContentResolver().query( + Uri.parse("content://android.content.RedactingProvider/missing"), null, null, null); + + redacting.moveToNext(); + assertEquals("foo", redacting.getString(0)); + assertEquals(10, redacting.getInt(1)); + assertEquals("/path/to/foo", redacting.getString(2)); + redacting.moveToNext(); + assertEquals("bar", redacting.getString(0)); + assertEquals(20, redacting.getInt(1)); + assertEquals("/path/to/bar", redacting.getString(2)); + } + + @Test + public void testSingle() throws Exception { + final Cursor redacting = getContext().getContentResolver().query( + Uri.parse("content://android.content.RedactingProvider/single"), null, null, null); + + redacting.moveToNext(); + assertEquals(null, redacting.getString(0)); + assertEquals(10, redacting.getInt(1)); + assertEquals("/dev/null", redacting.getString(2)); + assertEquals(Cursor.FIELD_TYPE_NULL, redacting.getType(0)); + assertEquals(Cursor.FIELD_TYPE_INTEGER, redacting.getType(1)); + assertEquals(Cursor.FIELD_TYPE_STRING, redacting.getType(2)); + assertTrue(redacting.isNull(0)); + assertFalse(redacting.isNull(1)); + assertFalse(redacting.isNull(2)); + + redacting.moveToNext(); + assertEquals(null, redacting.getString(0)); + assertEquals(20, redacting.getInt(1)); + assertEquals("/dev/null", redacting.getString(2)); + } + + @Test + public void testMultiple() throws Exception { + final Cursor redacting = getContext().getContentResolver().query( + Uri.parse("content://android.content.RedactingProvider/multiple"), + null, null, null); + + redacting.moveToNext(); + assertEquals(null, redacting.getString(0)); + assertEquals("foo", redacting.getString(1)); + assertEquals(null, redacting.getString(2)); + } +} diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java index 7c1485d88a3e..6f82b7849a82 100644 --- a/location/java/android/location/Country.java +++ b/location/java/android/location/Country.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -78,6 +79,7 @@ public class Country implements Parcelable { * <li>{@link #COUNTRY_SOURCE_LOCALE}</li> * </ul> */ + @UnsupportedAppUsage public Country(final String countryIso, final int source) { if (countryIso == null || source < COUNTRY_SOURCE_NETWORK || source > COUNTRY_SOURCE_LOCALE) { @@ -107,6 +109,7 @@ public class Country implements Parcelable { /** * @return the ISO 3166-1 two letters country code */ + @UnsupportedAppUsage public final String getCountryIso() { return mCountryIso; } @@ -121,6 +124,7 @@ public class Country implements Parcelable { * <li>{@link #COUNTRY_SOURCE_LOCALE}</li> * </ul> */ + @UnsupportedAppUsage public final int getSource() { return mSource; } diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java index ec6dfb713b10..119d1e0071e5 100644 --- a/location/java/android/location/CountryDetector.java +++ b/location/java/android/location/CountryDetector.java @@ -19,6 +19,7 @@ package android.location; import java.util.HashMap; import android.annotation.SystemService; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Looper; @@ -87,6 +88,7 @@ public class CountryDetector { * create an instance of this class is using the factory * Context.getSystemService. */ + @UnsupportedAppUsage public CountryDetector(ICountryDetector service) { mService = service; mListeners = new HashMap<CountryListener, ListenerTransport>(); @@ -98,6 +100,7 @@ public class CountryDetector { * @return the country if it is available immediately, otherwise null will * be returned. */ + @UnsupportedAppUsage public Country detectCountry() { try { return mService.detectCountry(); @@ -116,6 +119,7 @@ public class CountryDetector { * implement the callback mechanism. If looper is null then the * callbacks will be called on the main thread. */ + @UnsupportedAppUsage public void addCountryListener(CountryListener listener, Looper looper) { synchronized (mListeners) { if (!mListeners.containsKey(listener)) { @@ -133,6 +137,7 @@ public class CountryDetector { /** * Remove the listener */ + @UnsupportedAppUsage public void removeCountryListener(CountryListener listener) { synchronized (mListeners) { ListenerTransport transport = mListeners.get(listener); diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java index e36db412eaec..70a83c5acdd9 100644 --- a/location/java/android/location/CountryListener.java +++ b/location/java/android/location/CountryListener.java @@ -16,6 +16,8 @@ package android.location; +import android.annotation.UnsupportedAppUsage; + /** * The listener for receiving the notification when the country is detected or * changed @@ -26,5 +28,6 @@ public interface CountryListener { /** * @param country the changed or detected country. */ + @UnsupportedAppUsage void onCountryDetected(Country country); } diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java index 174fe3e0af2e..d90e4b528f31 100644 --- a/location/java/android/location/GeocoderParams.java +++ b/location/java/android/location/GeocoderParams.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; @@ -53,6 +54,7 @@ public class GeocoderParams implements Parcelable { /** * returns the Geocoder's locale */ + @UnsupportedAppUsage public Locale getLocale() { return mLocale; } @@ -60,6 +62,7 @@ public class GeocoderParams implements Parcelable { /** * returns the package name of the Geocoder's client */ + @UnsupportedAppUsage public String getClientPackage() { return mPackageName; } diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java index 5de779a29cdd..ed2aa64879aa 100644 --- a/location/java/android/location/Geofence.java +++ b/location/java/android/location/Geofence.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -98,6 +99,7 @@ public final class Geofence implements Parcelable { } } + @UnsupportedAppUsage public static final Parcelable.Creator<Geofence> CREATOR = new Parcelable.Creator<Geofence>() { @Override public Geofence createFromParcel(Parcel in) { diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index b601cde35305..d90a597b1cbb 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.UnsupportedAppUsage; import android.util.SparseArray; import java.util.Iterator; @@ -206,6 +207,7 @@ public final class GpsStatus { status.mAzimuths); } + @UnsupportedAppUsage void setTimeToFirstFix(int ttff) { mTimeToFirstFix = ttff; } diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index 684cafa14005..70a97e1f7da0 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -18,6 +18,7 @@ package android.location; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -123,8 +124,10 @@ public class Location implements Parcelable { } }; + @UnsupportedAppUsage private String mProvider; private long mTime = 0; + @UnsupportedAppUsage private long mElapsedRealtimeNanos = 0; private double mLatitude = 0.0; private double mLongitude = 0.0; @@ -1156,6 +1159,7 @@ public class Location implements Parcelable { * @param value the Location to attach * @hide */ + @UnsupportedAppUsage public void setExtraLocation(String key, Location value) { if (mExtras == null) { mExtras = new Bundle(); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 30a07ef94b06..b5d94315f97f 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -29,6 +29,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -68,6 +69,7 @@ public class LocationManager { private static final String TAG = "LocationManager"; private final Context mContext; + @UnsupportedAppUsage private final ILocationManager mService; private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport; private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport; @@ -1004,6 +1006,7 @@ public class LocationManager { } } + @UnsupportedAppUsage private void requestLocationUpdates(LocationRequest request, LocationListener listener, Looper looper, PendingIntent intent) { @@ -2328,6 +2331,7 @@ public class LocationManager { * * @hide */ + @UnsupportedAppUsage public boolean sendNiResponse(int notifId, int userResponse) { try { return mService.sendNiResponse(notifId, userResponse); diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 96a0817ae561..2d7f7e309004 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -17,6 +17,7 @@ package android.location; import android.annotation.SystemApi; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -141,16 +142,26 @@ public final class LocationRequest implements Parcelable { */ private static final double FASTEST_INTERVAL_FACTOR = 6.0; // 6x + @UnsupportedAppUsage private int mQuality = POWER_LOW; + @UnsupportedAppUsage private long mInterval = 60 * 60 * 1000; // 60 minutes + @UnsupportedAppUsage private long mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR); // 10 minutes + @UnsupportedAppUsage private boolean mExplicitFastestInterval = false; + @UnsupportedAppUsage private long mExpireAt = Long.MAX_VALUE; // no expiry + @UnsupportedAppUsage private int mNumUpdates = Integer.MAX_VALUE; // no expiry + @UnsupportedAppUsage private float mSmallestDisplacement = 0.0f; // meters + @UnsupportedAppUsage private WorkSource mWorkSource = null; + @UnsupportedAppUsage private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps + @UnsupportedAppUsage private String mProvider = LocationManager.FUSED_PROVIDER; // for deprecated APIs that explicitly request a provider @@ -592,12 +603,14 @@ public final class LocationRequest implements Parcelable { return mHideFromAppOps; } + @UnsupportedAppUsage private static void checkInterval(long millis) { if (millis < 0) { throw new IllegalArgumentException("invalid interval: " + millis); } } + @UnsupportedAppUsage private static void checkQuality(int quality) { switch (quality) { case ACCURACY_FINE: @@ -612,12 +625,14 @@ public final class LocationRequest implements Parcelable { } } + @UnsupportedAppUsage private static void checkDisplacement(float meters) { if (meters < 0.0f) { throw new IllegalArgumentException("invalid displacement: " + meters); } } + @UnsupportedAppUsage private static void checkProvider(String name) { if (name == null) { throw new IllegalArgumentException("invalid provider: " + name); diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java index ede90dac517c..557f099c25c1 100644 --- a/media/java/android/mtp/MtpPropertyList.java +++ b/media/java/android/mtp/MtpPropertyList.java @@ -16,6 +16,7 @@ package android.mtp; +import android.annotation.UnsupportedAppUsage; import java.util.ArrayList; import java.util.List; @@ -49,6 +50,7 @@ class MtpPropertyList { mStringValues = new ArrayList<>(); } + @UnsupportedAppUsage public void append(int handle, int property, int type, long value) { mObjectHandles.add(handle); mPropertyCodes.add(property); @@ -57,6 +59,7 @@ class MtpPropertyList { mStringValues.add(null); } + @UnsupportedAppUsage public void append(int handle, int property, String value) { mObjectHandles.add(handle); mPropertyCodes.add(property); diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index 2625e0cc932c..c714b3cad296 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -16,6 +16,7 @@ package android.mtp; +import android.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; /** @@ -46,6 +47,7 @@ public class MtpStorage { * * @return the storage ID */ + @UnsupportedAppUsage public final int getStorageId() { return mStorageId; } @@ -55,6 +57,7 @@ public class MtpStorage { * * @return the storage file path */ + @UnsupportedAppUsage public final String getPath() { return mPath; } diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java index 53ec6c8980ef..728e6e18cc31 100644 --- a/opengl/java/android/opengl/EGL14.java +++ b/opengl/java/android/opengl/EGL14.java @@ -18,6 +18,7 @@ package android.opengl; +import android.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceView; @@ -163,6 +164,7 @@ public static final int EGL_CORE_NATIVE_ENGINE = 0x305B; /** * {@hide} */ + @UnsupportedAppUsage public static native EGLDisplay eglGetDisplay( long display_id ); diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java index 137f2f5c2c5e..d66e7ac84a3b 100644 --- a/opengl/java/android/opengl/GLES20.java +++ b/opengl/java/android/opengl/GLES20.java @@ -19,6 +19,8 @@ package android.opengl; +import android.annotation.UnsupportedAppUsage; + /** OpenGL ES 2.0 */ public class GLES20 { @@ -824,6 +826,7 @@ public class GLES20 { // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) /** @hide Method is broken, but used to be public (b/6006380) */ + @UnsupportedAppUsage public static native void glGetActiveAttrib( int program, int index, @@ -872,6 +875,7 @@ public class GLES20 { // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) /** @hide Method is broken, but used to be public (b/6006380) */ + @UnsupportedAppUsage public static native void glGetActiveUniform( int program, int index, diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 0f0a7e9d1314..8a3e6a0b0fd5 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -16,6 +16,7 @@ package android.opengl; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Trace; import android.util.AttributeSet; @@ -1235,6 +1236,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback EGLDisplay mEglDisplay; EGLSurface mEglSurface; EGLConfig mEglConfig; + @UnsupportedAppUsage EGLContext mEglContext; } @@ -1844,6 +1846,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback // End of member variables protected by the sGLThreadManager monitor. + @UnsupportedAppUsage private EglHelper mEglHelper; /** @@ -1919,7 +1922,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private final WeakReference<GLSurfaceView> mThisWeakRef = new WeakReference<GLSurfaceView>(this); + @UnsupportedAppUsage private GLThread mGLThread; + @UnsupportedAppUsage private Renderer mRenderer; private boolean mDetached; private EGLConfigChooser mEGLConfigChooser; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java index 01df0ecfdb11..dddfa7a3a9b4 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java @@ -102,17 +102,4 @@ public class BatteryMeterDrawableBaseTest { private boolean isRectZero(Rect r) { return r.left == 0 && r.top == 0 && r.right == 0 && r.bottom == 0; } - - @Test - public void testPlusPaint_isEqualToBoltPaint() { - // Before setting color - assertTrue(mBatteryDrawable.mPlusPaint.hasEqualAttributes(mBatteryDrawable.mBoltPaint)); - - final int fakeFillColor = 123; - final int fakeBackgrundColor = 456; - - // After - mBatteryDrawable.setColors(fakeFillColor, fakeBackgrundColor); - assertTrue(mBatteryDrawable.mPlusPaint.hasEqualAttributes(mBatteryDrawable.mBoltPaint)); - } } diff --git a/packages/SystemUI/docs/plugin_hooks.md b/packages/SystemUI/docs/plugin_hooks.md index 5b08bfc387db..9fe2e181971a 100644 --- a/packages/SystemUI/docs/plugin_hooks.md +++ b/packages/SystemUI/docs/plugin_hooks.md @@ -51,6 +51,10 @@ Expected interface: [NotificationSwipeActionHelper](/packages/SystemUI/plugin/sr Use: Control over swipes/input for notification views, can be used to control what happens when you swipe/long-press +### Action: com.android.systemui.action.PLUGIN_CLOCK +Expected interface: [ClockPlugin](/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java) + +Use: Allows replacement of the keyguard main clock. # Global plugin dependencies These classes can be accessed by any plugin using PluginDependency as long as they @Requires them. diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java new file mode 100644 index 000000000000..b4fc82018303 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.plugins; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +import android.graphics.Paint.Style; +import android.view.View; + +/** + * This plugin is used to replace main clock in keyguard. + */ +@ProvidesInterface(action = ClockPlugin.ACTION, version = ClockPlugin.VERSION) +public interface ClockPlugin extends Plugin { + + String ACTION = "com.android.systemui.action.PLUGIN_CLOCK"; + int VERSION = 1; + + /** + * Get clock view. + * @return clock view from plugin. + */ + View getView(); + + /** + * Set clock paint style. + * @param style The new style to set in the paint. + */ + void setStyle(Style style); + + /** + * Set clock text color. + * @param color A color value. + */ + void setTextColor(int color); +} diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml new file mode 100644 index 000000000000..89b873e7ffda --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2018, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License") +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- This is a view that shows clock information in Keyguard. --> +<com.android.keyguard.KeyguardClockSwitch + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_alignParentTop="true"> + <TextClock + android:id="@+id/default_clock_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:letterSpacing="0.03" + android:textColor="?attr/wallpaperTextColor" + android:singleLine="true" + style="@style/widget_big_thin" + android:format12Hour="@string/keyguard_widget_12_hours_format" + android:format24Hour="@string/keyguard_widget_24_hours_format" /> +</com.android.keyguard.KeyguardClockSwitch> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml index 87983b9186db..a795442c62f9 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml @@ -38,19 +38,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|top"> - <TextClock - android:id="@+id/clock_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_centerHorizontal="true" - android:layout_alignParentTop="true" - android:letterSpacing="0.03" - android:textColor="?attr/wallpaperTextColor" - android:singleLine="true" - style="@style/widget_big_thin" - android:format12Hour="@string/keyguard_widget_12_hours_format" - android:format24Hour="@string/keyguard_widget_24_hours_format" /> + <include layout="@layout/keyguard_clock_switch" + android:id="@+id/clock_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> <View android:id="@+id/clock_separator" android:layout_width="@dimen/widget_separator_width" diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml index ba05ccf5ce46..4ae2d4181656 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml @@ -55,19 +55,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|top"> - <TextClock - android:id="@+id/clock_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_centerHorizontal="true" - android:layout_alignParentTop="true" - android:letterSpacing="0.03" - android:textColor="?attr/wallpaperTextColor" - android:singleLine="true" - style="@style/widget_big_thin" - android:format12Hour="@string/keyguard_widget_12_hours_format" - android:format24Hour="@string/keyguard_widget_24_hours_format" /> + <include layout="@layout/keyguard_clock_switch" + android:id="@+id/clock_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> <View android:id="@+id/clock_separator" android:layout_width="@dimen/widget_separator_width" diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml index baaf699c278a..d72021e27e0b 100644 --- a/packages/SystemUI/res/layout/navigation_layout.xml +++ b/packages/SystemUI/res/layout/navigation_layout.xml @@ -18,14 +18,16 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:layout_marginStart="@dimen/rounded_corner_content_padding" + android:layout_marginEnd="@dimen/rounded_corner_content_padding" + android:paddingStart="@dimen/nav_content_padding" + android:paddingEnd="@dimen/nav_content_padding"> <com.android.systemui.statusbar.phone.NearestTouchFrame android:id="@+id/nav_buttons" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingStart="@dimen/rounded_corner_content_padding" - android:paddingEnd="@dimen/rounded_corner_content_padding" android:clipChildren="false" android:clipToPadding="false"> @@ -34,8 +36,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:paddingStart="@dimen/nav_content_padding" - android:paddingEnd="@dimen/nav_content_padding" android:clipToPadding="false" android:clipChildren="false" /> @@ -46,8 +46,6 @@ android:layout_gravity="center" android:gravity="center" android:orientation="horizontal" - android:paddingStart="@dimen/nav_content_padding" - android:paddingEnd="@dimen/nav_content_padding" android:clipToPadding="false" android:clipChildren="false" /> diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml index 6d5b77885a09..24a0c71f3bad 100644 --- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml +++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml @@ -18,14 +18,16 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/rounded_corner_content_padding" + android:layout_marginBottom="@dimen/rounded_corner_content_padding" + android:paddingTop="@dimen/nav_content_padding" + android:paddingBottom="@dimen/nav_content_padding"> <com.android.systemui.statusbar.phone.NearestTouchFrame android:id="@+id/nav_buttons" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingTop="@dimen/rounded_corner_content_padding" - android:paddingBottom="@dimen/rounded_corner_content_padding" android:clipChildren="false" android:clipToPadding="false"> @@ -34,10 +36,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:paddingTop="@dimen/nav_content_padding" - android:paddingBottom="@dimen/nav_content_padding" - android:clipChildren="false" - android:clipToPadding="false" /> + android:clipToPadding="false" + android:clipChildren="false" /> <com.android.systemui.statusbar.phone.ReverseLinearLayout android:id="@+id/center_group" @@ -45,10 +45,8 @@ android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" - android:paddingTop="@dimen/nav_content_padding" - android:paddingBottom="@dimen/nav_content_padding" - android:clipChildren="false" - android:clipToPadding="false" /> + android:clipToPadding="false" + android:clipChildren="false" /> </com.android.systemui.statusbar.phone.NearestTouchFrame> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java new file mode 100644 index 000000000000..5bbbc52f4cbc --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -0,0 +1,155 @@ +package com.android.keyguard; + +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextClock; + +import androidx.annotation.VisibleForTesting; + +import com.android.systemui.Dependency; +import com.android.systemui.plugins.ClockPlugin; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; + +/** + * Switch to show plugin clock when plugin is connected, otherwise it will show default clock. + */ +public class KeyguardClockSwitch extends FrameLayout { + /** + * Optional/alternative clock injected via plugin. + */ + private ClockPlugin mClockPlugin; + /** + * Default clock. + */ + private TextClock mClockView; + + private final PluginListener<ClockPlugin> mClockPluginListener = + new PluginListener<ClockPlugin>() { + @Override + public void onPluginConnected(ClockPlugin plugin, Context pluginContext) { + View view = plugin.getView(); + if (view != null) { + mClockPlugin = plugin; + addView(view, -1, + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + initPluginParams(); + mClockView.setVisibility(View.GONE); + } + } + + @Override + public void onPluginDisconnected(ClockPlugin plugin) { + View view = plugin.getView(); + if (view != null) { + mClockPlugin = null; + removeView(view); + mClockView.setVisibility(View.VISIBLE); + } + } + }; + + public KeyguardClockSwitch(Context context) { + this(context, null); + } + + public KeyguardClockSwitch(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mClockView = findViewById(R.id.default_clock_view); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener, + ClockPlugin.class); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener); + } + + /** + * It will also update plugin setStyle if plugin is connected. + */ + public void setStyle(Style style) { + mClockView.getPaint().setStyle(style); + if (mClockPlugin != null) { + mClockPlugin.setStyle(style); + } + } + + /** + * It will also update plugin setTextColor if plugin is connected. + */ + public void setTextColor(int color) { + mClockView.setTextColor(color); + if (mClockPlugin != null) { + mClockPlugin.setTextColor(color); + } + } + + public void setShowCurrentUserTime(boolean showCurrentUserTime) { + mClockView.setShowCurrentUserTime(showCurrentUserTime); + } + + public void setElegantTextHeight(boolean elegant) { + mClockView.setElegantTextHeight(elegant); + } + + public void setTextSize(int unit, float size) { + mClockView.setTextSize(unit, size); + } + + public void setFormat12Hour(CharSequence format) { + mClockView.setFormat12Hour(format); + } + + public void setFormat24Hour(CharSequence format) { + mClockView.setFormat24Hour(format); + } + + public Paint getPaint() { + return mClockView.getPaint(); + } + + public int getCurrentTextColor() { + return mClockView.getCurrentTextColor(); + } + + public float getTextSize() { + return mClockView.getTextSize(); + } + + public void refresh() { + mClockView.refresh(); + } + + /** + * When plugin changes, set all kept parameters into newer plugin. + */ + private void initPluginParams() { + if (mClockPlugin != null) { + mClockPlugin.setStyle(getPaint().getStyle()); + mClockPlugin.setTextColor(getCurrentTextColor()); + } + } + + @VisibleForTesting (otherwise = VisibleForTesting.NONE) + PluginListener getClockPluginListener() { + return mClockPluginListener; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 6da143c0e083..6d1313c15106 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -39,7 +39,6 @@ import android.util.TypedValue; import android.view.View; import android.widget.GridLayout; import android.widget.RelativeLayout; -import android.widget.TextClock; import android.widget.TextView; import com.android.internal.widget.LockPatternUtils; @@ -64,7 +63,7 @@ public class KeyguardStatusView extends GridLayout implements private final float mSmallClockScale; private TextView mLogoutView; - private TextClock mClockView; + private KeyguardClockSwitch mClockView; private View mClockSeparator; private TextView mOwnerInfo; private KeyguardSliceView mKeyguardSlice; @@ -248,7 +247,7 @@ public class KeyguardStatusView extends GridLayout implements .scaleX(clockScale) .scaleY(clockScale) .withEndAction(() -> { - mClockView.getPaint().setStyle(style); + mClockView.setStyle(style); mClockView.invalidate(); }) .start(); @@ -256,7 +255,7 @@ public class KeyguardStatusView extends GridLayout implements mClockView.setY(top); mClockView.setScaleX(clockScale); mClockView.setScaleY(clockScale); - mClockView.getPaint().setStyle(style); + mClockView.setStyle(style); mClockView.invalidate(); } } else if (view == mClockSeparator) { diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 3c44eb42ffca..0864ff03a9db 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -55,6 +55,7 @@ import java.util.List; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP; +import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; /** @@ -69,6 +70,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private static final long BACKOFF_MILLIS = 1000; private static final long DEFERRED_CALLBACK_MILLIS = 5000; + // Default interaction flags if swipe up is disabled before connecting to launcher + private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP + | FLAG_SHOW_OVERVIEW_BUTTON; + private final Context mContext; private final Handler mHandler; private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser; @@ -220,7 +225,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis // When launcher service is disabled, reset interaction flags because it is inactive if (!isEnabled()) { - mInteractionFlags = 0; + mInteractionFlags = getDefaultInteractionFlags(); Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS); } @@ -300,7 +305,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis com.android.internal.R.string.config_recentsComponentName)); mQuickStepIntent = new Intent(ACTION_QUICKSTEP) .setPackage(mRecentsComponentName.getPackageName()); - mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, 0); + mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, + getDefaultInteractionFlags()); // Listen for the package update changes. if (SystemServicesProxy.getInstance(context) @@ -397,6 +403,15 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } + private int getDefaultInteractionFlags() { + // If there is no settings available use device default or get it from settings + final boolean defaultState = getSwipeUpDefaultValue(); + final boolean swipeUpEnabled = getSwipeUpSettingAvailable() + ? getSwipeUpEnabledFromSettings(defaultState) + : defaultState; + return swipeUpEnabled ? 0 : DEFAULT_DISABLE_SWIPE_UP_STATE; + } + private void notifyBackButtonAlphaChanged(float alpha, boolean animate) { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate); @@ -427,6 +442,21 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis ActivityManagerWrapper.getInstance().getCurrentUserId()) != null; } + private boolean getSwipeUpDefaultValue() { + return mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default); + } + + private boolean getSwipeUpSettingAvailable() { + return mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_setting_available); + } + + private boolean getSwipeUpEnabledFromSettings(boolean defaultValue) { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, defaultValue ? 1 : 0) == 1; + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(TAG_OPS + " state:"); @@ -440,12 +470,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis pw.print(" quickStepIntent="); pw.println(mQuickStepIntent); pw.print(" quickStepIntentResolved="); pw.println(isEnabled()); - final int swipeUpDefaultValue = mContext.getResources() - .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default) ? 1 : 0; - final int swipeUpEnabled = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, swipeUpDefaultValue); - pw.print(" swipeUpSetting="); pw.println(swipeUpEnabled != 0); - pw.print(" swipeUpSettingDefault="); pw.println(swipeUpDefaultValue != 0); + final boolean swipeUpDefaultValue = getSwipeUpDefaultValue(); + final boolean swipeUpEnabled = getSwipeUpEnabledFromSettings(swipeUpDefaultValue); + pw.print(" swipeUpSetting="); pw.println(swipeUpEnabled); + pw.print(" swipeUpSettingDefault="); pw.println(swipeUpDefaultValue); } public interface OverviewProxyListener { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index fe8ea34f34c5..c96aa7303236 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -45,6 +45,7 @@ import java.util.Date; import java.util.Locale; import java.util.concurrent.TimeUnit; +import androidx.core.graphics.drawable.IconCompat; import androidx.slice.Slice; import androidx.slice.SliceProvider; import androidx.slice.builders.ListBuilder; @@ -127,8 +128,8 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public Slice onBindSlice(Uri sliceUri) { - ListBuilder builder = new ListBuilder(getContext(), mSliceUri); - builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText)); + ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); + builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText)); addNextAlarm(builder); addZenMode(builder); addPrimaryAction(builder); @@ -139,11 +140,13 @@ public class KeyguardSliceProvider extends SliceProvider implements // Add simple action because API requires it; Keyguard handles presenting // its own slices so this action + icon are actually never used. PendingIntent pi = PendingIntent.getActivity(getContext(), 0, new Intent(), 0); - Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big); - SliceAction action = new SliceAction(pi, icon, mLastText); + IconCompat icon = IconCompat.createWithResource(getContext(), + R.drawable.ic_access_alarms_big); + SliceAction action = SliceAction.createDeeplink(pi, icon, + ListBuilder.ICON_IMAGE, mLastText); - RowBuilder primaryActionRow = new RowBuilder(builder, Uri.parse(KEYGUARD_ACTION_URI)) - .setPrimaryAction(action); + RowBuilder primaryActionRow = new RowBuilder(Uri.parse(KEYGUARD_ACTION_URI)) + .setPrimaryAction(action); builder.addRow(primaryActionRow); } @@ -152,10 +155,11 @@ public class KeyguardSliceProvider extends SliceProvider implements return; } - Icon alarmIcon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big); - RowBuilder alarmRowBuilder = new RowBuilder(builder, mAlarmUri) + IconCompat alarmIcon = IconCompat.createWithResource(getContext(), + R.drawable.ic_access_alarms_big); + RowBuilder alarmRowBuilder = new RowBuilder(mAlarmUri) .setTitle(mNextAlarm) - .addEndItem(alarmIcon); + .addEndItem(alarmIcon, ListBuilder.ICON_IMAGE); builder.addRow(alarmRowBuilder); } @@ -167,10 +171,11 @@ public class KeyguardSliceProvider extends SliceProvider implements if (!isDndSuppressingNotifications()) { return; } - RowBuilder dndBuilder = new RowBuilder(builder, mDndUri) + RowBuilder dndBuilder = new RowBuilder(mDndUri) .setContentDescription(getContext().getResources() .getString(R.string.accessibility_quick_settings_dnd)) - .addEndItem(Icon.createWithResource(getContext(), R.drawable.stat_sys_dnd)); + .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd), + ListBuilder.ICON_IMAGE); builder.addRow(dndBuilder); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index af0ed284847d..506d69719e82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -40,7 +40,6 @@ public class FullscreenUserSwitcher { private final int mShortAnimDuration; private final StatusBar mStatusBar; private final UserManagerHelper mUserManagerHelper; - private int mCurrentForegroundUserId; private boolean mShowing; public FullscreenUserSwitcher(StatusBar statusBar, ViewStub containerStub, Context context) { @@ -55,7 +54,6 @@ public class FullscreenUserSwitcher { mUserGridView.setUserSelectionListener(this::onUserSelected); mUserManagerHelper = new UserManagerHelper(context); - updateCurrentForegroundUser(); mShortAnimDuration = mContainer.getResources() .getInteger(android.R.integer.config_shortAnimTime); @@ -78,22 +76,8 @@ public class FullscreenUserSwitcher { } public void onUserSwitched(int newUserId) { - // The logic for foreground user change is needed here to exclude the reboot case. On - // reboot, system fires ACTION_USER_SWITCHED change from -1 to 0 user. This is not an actual - // user switch. We only want to trigger keyguard dismissal when foreground user changes. - if (foregroundUserChanged()) { - toggleSwitchInProgress(false); - updateCurrentForegroundUser(); - mParent.post(this::dismissKeyguard); - } - } - - private boolean foregroundUserChanged() { - return mCurrentForegroundUserId != mUserManagerHelper.getForegroundUserId(); - } - - private void updateCurrentForegroundUser() { - mCurrentForegroundUserId = mUserManagerHelper.getForegroundUserId(); + toggleSwitchInProgress(false); + mParent.post(this::dismissKeyguard); } private void onUserSelected(UserGridRecyclerView.UserRecord record) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 8f552e31f5a5..92a9efe743d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -40,6 +40,8 @@ public class DozeParameters implements TunerService.Tunable { public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully"; public static final boolean FORCE_NO_BLANKING = SystemProperties.getBoolean("debug.force_no_blanking", false); + public static final boolean FORCE_BLANKING = + SystemProperties.getBoolean("debug.force_blanking", false); private static IntInOutMatcher sPickupSubtypePerformsProxMatcher; private static DozeParameters sInstance; @@ -183,7 +185,7 @@ public class DozeParameters implements TunerService.Tunable { * @return {@code true} if screen needs to be completely black before a power transition. */ public boolean getDisplayNeedsBlanking() { - return !FORCE_NO_BLANKING && mContext.getResources().getBoolean( + return FORCE_BLANKING || !FORCE_NO_BLANKING && mContext.getResources().getBoolean( com.android.internal.R.bool.config_displayBlanksAfterDoze); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index b80cd30914a1..042e4ff16d3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -103,9 +103,9 @@ public class KeyguardClockPositionAlgorithm { private float mDarkAmount; /** - * If keyguard will just fade away or will require a password. + * If keyguard will require a password or just fade away. */ - private boolean mFadeAway; + private boolean mCurrentlySecure; /** * Dozing and receiving a notification (AOD notification.) @@ -135,7 +135,7 @@ public class KeyguardClockPositionAlgorithm { public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight, float panelExpansion, int parentHeight, - int keyguardStatusHeight, float dark, boolean fadeAway, boolean pulsing, + int keyguardStatusHeight, float dark, boolean secure, boolean pulsing, int bouncerTop) { mMinTopMargin = minTopMargin + mContainerTopPadding; mMaxShadeBottom = maxShadeBottom; @@ -144,7 +144,7 @@ public class KeyguardClockPositionAlgorithm { mHeight = parentHeight; mKeyguardStatusHeight = keyguardStatusHeight; mDarkAmount = dark; - mFadeAway = fadeAway; + mCurrentlySecure = secure; mPulsing = pulsing; mBouncerTop = bouncerTop; } @@ -198,7 +198,7 @@ public class KeyguardClockPositionAlgorithm { float clockYRegular = getExpandedClockPosition(); boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop; - float clockYTarget = !mFadeAway && hasEnoughSpace ? + float clockYTarget = mCurrentlySecure && hasEnoughSpace ? mMinTopMargin : -mKeyguardStatusHeight; // Move clock up while collapsing the shade @@ -218,11 +218,11 @@ public class KeyguardClockPositionAlgorithm { */ private float getClockAlpha(int y) { float alphaKeyguard; - if (mFadeAway) { + if (mCurrentlySecure) { + alphaKeyguard = 1; + } else { alphaKeyguard = Math.max(0, y / Math.max(1f, getExpandedClockPosition())); alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard); - } else { - alphaKeyguard = 1; } return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 7db580205ab9..747696376f8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -92,6 +92,21 @@ public class NotificationPanelView extends PanelView implements private static final boolean DEBUG = false; + /** + * Fling expanding QS. + */ + public static final int FLING_EXPAND = 0; + + /** + * Fling collapsing QS, potentially stopping when QS becomes QQS. + */ + public static final int FLING_COLLAPSE = 1; + + /** + * Fing until QS is completely hidden. + */ + public static final int FLING_HIDE = 2; + // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is // changed. private static final int CAP_HEIGHT = 1456; @@ -524,8 +539,7 @@ public class NotificationPanelView extends PanelView implements totalHeight, mKeyguardStatusView.getHeight(), mInterpolatedDarkAmount, - !mStatusBar.isKeyguardCurrentlySecure() - || mStatusBar.isKeyguardOccludeAnimationRunning(), + mStatusBar.isKeyguardCurrentlySecure(), mPulsing, mBouncerTop); mClockPositionAlgorithm.run(mClockPositionResult); @@ -624,7 +638,7 @@ public class NotificationPanelView extends PanelView implements } @Override - public void resetViews() { + public void resetViews(boolean animate) { mIsLaunchTransitionFinished = false; mBlockTouches = false; mUnlockIconActive = false; @@ -632,11 +646,15 @@ public class NotificationPanelView extends PanelView implements mAffordanceHelper.reset(false); mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; } - closeQs(); mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */, true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */); - mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */, - true /* cancelAnimators */); + if (animate) { + animateCloseQs(true /* animateAway */); + } else { + closeQs(); + } + mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, animate, + !animate /* cancelAnimators */); mNotificationStackScroller.resetScrollPosition(); } @@ -658,7 +676,13 @@ public class NotificationPanelView extends PanelView implements setQsExpansion(mQsMinExpansionHeight); } - public void animateCloseQs() { + /** + * Animate QS closing by flinging it. + * If QS is expanded, it will collapse into QQS and stop. + * + * @param animateAway Do not stop when QS becomes QQS. Fling until QS isn't visible anymore. + */ + public void animateCloseQs(boolean animateAway) { if (mQsExpansionAnimator != null) { if (!mQsAnimatorExpand) { return; @@ -667,14 +691,7 @@ public class NotificationPanelView extends PanelView implements mQsExpansionAnimator.cancel(); setQsExpansion(height); } - flingSettings(0 /* vel */, false); - } - - public void openQs() { - cancelQsAnimation(); - if (mQsExpansionEnabled) { - setQsExpansion(mQsMaxExpansionHeight); - } + flingSettings(0 /* vel */, animateAway ? FLING_HIDE : FLING_COLLAPSE); } public void expandWithQs() { @@ -687,7 +704,7 @@ public class NotificationPanelView extends PanelView implements public void expandWithoutQs() { if (isQsExpanded()) { - flingSettings(0 /* velocity */, false /* expand */); + flingSettings(0 /* velocity */, FLING_COLLAPSE); } else { expand(true /* animate */); } @@ -831,7 +848,7 @@ public class NotificationPanelView extends PanelView implements if (expandsQs) { logQsSwipeDown(y); } - flingSettings(vel, expandsQs && !isCancelMotionEvent); + flingSettings(vel, expandsQs && !isCancelMotionEvent ? FLING_EXPAND : FLING_COLLAPSE); } private void logQsSwipeDown(float y) { @@ -1100,7 +1117,8 @@ public class NotificationPanelView extends PanelView implements mLastOverscroll = 0f; mQsExpansionFromOverscroll = false; setQsExpansion(mQsExpansionHeight); - flingSettings(!mQsExpansionEnabled && open ? 0f : velocity, open && mQsExpansionEnabled, + flingSettings(!mQsExpansionEnabled && open ? 0f : velocity, + open && mQsExpansionEnabled ? FLING_EXPAND : FLING_COLLAPSE, new Runnable() { @Override public void run() { @@ -1467,13 +1485,35 @@ public class NotificationPanelView extends PanelView implements } } - public void flingSettings(float vel, boolean expand) { - flingSettings(vel, expand, null, false /* isClick */); + /** + * @see #flingSettings(float, int, Runnable, boolean) + */ + public void flingSettings(float vel, int type) { + flingSettings(vel, type, null, false /* isClick */); } - protected void flingSettings(float vel, boolean expand, final Runnable onFinishRunnable, + /** + * Animates QS or QQS as if the user had swiped up or down. + * + * @param vel Finger velocity or 0 when not initiated by touch events. + * @param type Either {@link #FLING_EXPAND}, {@link #FLING_COLLAPSE} or {@link #FLING_HIDE}. + * @param onFinishRunnable Runnable to be executed at the end of animation. + * @param isClick If originated by click (different interpolator and duration.) + */ + protected void flingSettings(float vel, int type, final Runnable onFinishRunnable, boolean isClick) { - float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight; + float target; + switch (type) { + case FLING_EXPAND: + target = mQsMaxExpansionHeight; + break; + case FLING_COLLAPSE: + target = mQsMinExpansionHeight; + break; + case FLING_HIDE: + default: + target = 0; + } if (target == mQsExpansionHeight) { if (onFinishRunnable != null) { onFinishRunnable.run(); @@ -1483,7 +1523,8 @@ public class NotificationPanelView extends PanelView implements // If we move in the opposite direction, reset velocity and use a different duration. boolean oppositeDirection = false; - if (vel > 0 && !expand || vel < 0 && expand) { + boolean expanding = type == FLING_EXPAND; + if (vel > 0 && !expanding || vel < 0 && expanding) { vel = 0; oppositeDirection = true; } @@ -1497,11 +1538,8 @@ public class NotificationPanelView extends PanelView implements if (oppositeDirection) { animator.setDuration(350); } - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - setQsExpansion((Float) animation.getAnimatedValue()); - } + animator.addUpdateListener(animation -> { + setQsExpansion((Float) animation.getAnimatedValue()); }); animator.addListener(new AnimatorListenerAdapter() { @Override @@ -1515,7 +1553,7 @@ public class NotificationPanelView extends PanelView implements }); animator.start(); mQsExpansionAnimator = animator; - mQsAnimatorExpand = expand; + mQsAnimatorExpand = expanding; } /** @@ -2001,10 +2039,12 @@ public class NotificationPanelView extends PanelView implements public void onClick(View v) { onQsExpansionStarted(); if (mQsExpanded) { - flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */); + flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */, + true /* isClick */); } else if (mQsExpansionEnabled) { mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0); - flingSettings(0 /* vel */, true /* expand */, null, true /* isClick */); + flingSettings(0 /* vel */, FLING_EXPAND, null /* onFinishRunnable */, + true /* isClick */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 5d234947de29..deac669e31d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -194,7 +194,7 @@ public abstract class PanelBar extends FrameLayout { pv.collapse(delayed, speedUpFactor); waiting = true; } else { - pv.resetViews(); + pv.resetViews(false /* animate */); pv.setExpandedFraction(0); // just in case pv.cancelPeek(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index e4eeec11fdfd..1f09835a8eb9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -1240,7 +1240,7 @@ public abstract class PanelView extends FrameLayout { )); } - public abstract void resetViews(); + public abstract void resetViews(boolean animate); protected abstract float getPeekHeight(); /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index dd4ea3d903fd..3c351abc1fda 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -322,8 +322,6 @@ public class StatusBar extends SystemUI implements DemoMode, public static final int FADE_KEYGUARD_START_DELAY = 100; public static final int FADE_KEYGUARD_DURATION = 300; public static final int FADE_KEYGUARD_DURATION_PULSING = 96; - public static final int FADE_BACKDROP_DURATION = 300; - public static final int FADE_BACKDROP_DURATION_FAST = 240; /** If true, the system is in the half-boot-to-decryption-screen state. * Prudently disable QS and notifications. */ @@ -545,7 +543,6 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mIsOccluded; private boolean mWereIconsJustHidden; private boolean mBouncerWasShowingWhenHidden; - private boolean mKeyguardOccludeAnimationRunning; // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over, // this animation is tied to the scrim for historic reasons. @@ -1644,7 +1641,7 @@ public class StatusBar extends SystemUI implements DemoMode, boolean wakeAndUnlock = mBiometricUnlockController != null && mBiometricUnlockController.isWakeAndUnlock(); - if (mLaunchTransitionFadingAway && !mIsOccluded || wakeAndUnlock) { + if (mLaunchTransitionFadingAway || wakeAndUnlock) { mBackdrop.setVisibility(View.INVISIBLE); Trace.endSection(); return; @@ -1763,8 +1760,7 @@ public class StatusBar extends SystemUI implements DemoMode, boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange(); if (mBiometricUnlockController.getMode() == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING - || hideBecauseOccluded && !mKeyguardOccludeAnimationRunning - || cannotAnimateDoze) { + || hideBecauseOccluded || cannotAnimateDoze) { // We are unlocking directly - no animation! mBackdrop.setVisibility(View.GONE); @@ -1775,9 +1771,7 @@ public class StatusBar extends SystemUI implements DemoMode, mBackdrop.animate() .alpha(SRC_MIN_ALPHA) .setInterpolator(Interpolators.ACCELERATE_DECELERATE) - .setDuration( - mKeyguardOccludeAnimationRunning - ? FADE_BACKDROP_DURATION_FAST : FADE_BACKDROP_DURATION) + .setDuration(300) .setStartDelay(0) .withEndAction(() -> { mBackdrop.setVisibility(View.GONE); @@ -2245,7 +2239,8 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanel.expand(true /* animate */); mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1); } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){ - mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */); + mNotificationPanel.flingSettings(0 /* velocity */, + NotificationPanelView.FLING_EXPAND); mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1); } } @@ -3674,27 +3669,6 @@ public class StatusBar extends SystemUI implements DemoMode, } /** - * Is keyguard being occluded by a newly launched activity. - */ - public boolean isKeyguardOccludeAnimationRunning() { - return mKeyguardOccludeAnimationRunning; - } - - /** - * Plays the animation when new activity is launched over keyguard. - */ - public void animateKeyguardOccluding() { - mKeyguardOccludeAnimationRunning = true; - addPostCollapseAction(() -> { - mStatusBarKeyguardViewManager.reset(true /* hideBouncerWhenShowing */); - mKeyguardOccludeAnimationRunning = false; - }); - mStatusBarKeyguardViewManager.animateCollapsePanels(1.0f /* speedfactor */); - updateScrimController(); - updateMediaMetaData(false /* metaDataChanged */, true /* allowEnterAnimation */); - } - - /** * Plays the animation when an activity that was occluding Keyguard goes away. */ public void animateKeyguardUnoccluding() { @@ -3716,7 +3690,7 @@ public class StatusBar extends SystemUI implements DemoMode, Log.w(TAG, "Launch transition: Timeout!"); mNotificationPanel.onAffordanceLaunchEnded(); releaseGestureWakeLock(); - mNotificationPanel.resetViews(); + mNotificationPanel.resetViews(false /* animate */); } private void runLaunchTransitionEndRunnable() { @@ -3869,7 +3843,9 @@ public class StatusBar extends SystemUI implements DemoMode, Trace.beginSection("StatusBar#updateKeyguardState"); if (mState == StatusBarState.KEYGUARD) { mKeyguardIndicationController.setVisible(true); - mNotificationPanel.resetViews(); + boolean dozingAnimated = mDozingRequested + && DozeParameters.getInstance(mContext).shouldControlScreenOff(); + mNotificationPanel.resetViews(dozingAnimated); if (mKeyguardUserSwitcher != null) { mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); } @@ -4014,7 +3990,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mNotificationPanel.isQsDetailShowing()) { mNotificationPanel.closeQsDetail(); } else { - mNotificationPanel.animateCloseQs(); + mNotificationPanel.animateCloseQs(false /* animateAway */); } return true; } @@ -4039,7 +4015,7 @@ public class StatusBar extends SystemUI implements DemoMode, private void showBouncerIfKeyguard() { if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) - && !mKeyguardViewMediator.isHiding() && !mKeyguardOccludeAnimationRunning) { + && !mKeyguardViewMediator.isHiding()) { showBouncer(true /* scrimmed */); } } @@ -4539,11 +4515,6 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onStartedGoingToSleep() { - // in case we start going to sleep while new animation is launching over keyguard, make - // sure to finish it - if (mKeyguardOccludeAnimationRunning) { - runPostCollapseRunnables(); - } notifyHeadsUpGoingToSleep(); dismissVolumeDialog(); } @@ -4785,7 +4756,7 @@ public class StatusBar extends SystemUI implements DemoMode, ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER; mScrimController.transitionTo(state); } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn - || launchingAffordanceWithPreview || mKeyguardOccludeAnimationRunning) { + || launchingAffordanceWithPreview) { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } else if (mBrightnessMirrorVisible) { mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 97088bd0ce84..c4424d8e3c97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -365,11 +365,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } }); return; - } else if (animate) { - mOccluded = true; - mStatusBar.animateKeyguardOccluding(); - mStatusBarWindowManager.setKeyguardOccluded(mOccluded); - return; } } else if (!occluded && mOccluded && mShowing) { StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index f83fb43af8f3..a38328a8161e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -144,8 +144,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D state.scrimsVisibility == ScrimController.VISIBILITY_FULLY_OPAQUE; final boolean keyguardOrAod = state.keyguardShowing || (state.dozing && mDozeParameters.getAlwaysOn()); - if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper - && !state.keyguardOccluded) { + if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) { mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; } else { mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index 1bdb7ad3c3fc..196d9bc32e75 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -119,7 +119,9 @@ public class TunerServiceImpl extends TunerService { // 3 Removed because of a revert. if (oldVersion < 4) { // Delay this so that we can wait for everything to be registered first. - new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(() -> clearAll(), 5000); + final int user = mCurrentUser; + new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed( + () -> clearAllFromUser(user), 5000); } setValue(TUNER_VERSION, newVersion); } @@ -221,6 +223,10 @@ public class TunerServiceImpl extends TunerService { @Override public void clearAll() { + clearAllFromUser(mCurrentUser); + } + + public void clearAllFromUser(int user) { // A couple special cases. Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null); Intent intent = new Intent(DemoMode.ACTION_DEMO); @@ -231,7 +237,7 @@ public class TunerServiceImpl extends TunerService { if (ArrayUtils.contains(RESET_BLACKLIST, key)) { continue; } - Settings.Secure.putString(mContentResolver, key, null); + Settings.Secure.putStringForUser(mContentResolver, key, null, user); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java new file mode 100644 index 000000000000..e6e485740a7b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.keyguard; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import android.graphics.Color; +import android.graphics.Paint.Style; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.text.TextPaint; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextClock; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ClockPlugin; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWithLooper(setAsMainLooper = true) +@RunWith(AndroidTestingRunner.class) +public class KeyguardClockSwitchTest extends SysuiTestCase { + private PluginManager mPluginManager; + + @Mock + TextClock mClockView; + @InjectMocks + KeyguardClockSwitch mKeyguardClockSwitch; + + @Before + public void setUp() { + mPluginManager = mDependency.injectMockDependency(PluginManager.class); + LayoutInflater layoutInflater = LayoutInflater.from(getContext()); + mKeyguardClockSwitch = + (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); + MockitoAnnotations.initMocks(this); + } + + @Test + public void onAttachToWindow_addPluginListener() { + mKeyguardClockSwitch.onAttachedToWindow(); + + ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class); + verify(mPluginManager).addPluginListener(listener.capture(), eq(ClockPlugin.class)); + } + + @Test + public void onDetachToWindow_removePluginListener() { + mKeyguardClockSwitch.onDetachedFromWindow(); + + ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class); + verify(mPluginManager).removePluginListener(listener.capture()); + } + + @Test + public void onPluginConnected_showPluginClock() { + ClockPlugin plugin = mock(ClockPlugin.class); + TextClock pluginView = new TextClock(getContext()); + when(plugin.getView()).thenReturn(pluginView); + TextPaint paint = mock(TextPaint.class); + doReturn(paint).when(mClockView).getPaint(); + PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); + + listener.onPluginConnected(plugin, null); + + verify(mClockView).setVisibility(GONE); + assertThat(plugin.getView().getParent()).isEqualTo(mKeyguardClockSwitch); + } + + @Test + public void onPluginDisconnected_showDefaultClock() { + ClockPlugin plugin = mock(ClockPlugin.class); + TextClock pluginView = new TextClock(getContext()); + when(plugin.getView()).thenReturn(pluginView); + mClockView.setVisibility(GONE); + mKeyguardClockSwitch.addView(plugin.getView(), -1, + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); + + listener.onPluginDisconnected(plugin); + + verify(mClockView).setVisibility(VISIBLE); + assertThat(plugin.getView().getParent()).isNull(); + } + + @Test + public void setTextColor_defaultClockSetTextColor() { + mKeyguardClockSwitch.setTextColor(Color.YELLOW); + + verify(mClockView).setTextColor(Color.YELLOW); + } + + @Test + public void setTextColor_pluginClockSetTextColor() { + ClockPlugin plugin = mock(ClockPlugin.class); + TextClock pluginView = new TextClock(getContext()); + when(plugin.getView()).thenReturn(pluginView); + TextPaint paint = mock(TextPaint.class); + doReturn(paint).when(mClockView).getPaint(); + PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); + listener.onPluginConnected(plugin, null); + + mKeyguardClockSwitch.setTextColor(Color.WHITE); + + verify(plugin).setTextColor(Color.WHITE); + } + + @Test + public void setStyle_defaultClockSetStyle() { + TextPaint paint = mock(TextPaint.class); + Style style = mock(Style.class); + doReturn(paint).when(mClockView).getPaint(); + + mKeyguardClockSwitch.setStyle(style); + + verify(paint).setStyle(style); + } + + @Test + public void setStyle_pluginClockSetStyle() { + ClockPlugin plugin = mock(ClockPlugin.class); + TextClock pluginView = new TextClock(getContext()); + when(plugin.getView()).thenReturn(pluginView); + TextPaint paint = mock(TextPaint.class); + doReturn(paint).when(mClockView).getPaint(); + Style style = mock(Style.class); + PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); + listener.onPluginConnected(plugin, null); + + mKeyguardClockSwitch.setStyle(style); + + verify(plugin).setStyle(style); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java index d2e837158872..4ec30fde40e4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java @@ -55,7 +55,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Test public void showSlice_notifiesListener() { - ListBuilder builder = new ListBuilder(getContext(), mSliceUri); + ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); AtomicBoolean notified = new AtomicBoolean(); mKeyguardSliceView.setContentChangeListener(()-> notified.set(true)); mKeyguardSliceView.onChanged(builder.build()); @@ -74,13 +74,11 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Test public void hasHeader_readsSliceData() { - ListBuilder builder = new ListBuilder(getContext(), mSliceUri); + ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); mKeyguardSliceView.onChanged(builder.build()); Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader()); - builder.setHeader((ListBuilder.HeaderBuilder headerBuilder) -> { - headerBuilder.setTitle("header title!"); - }); + builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!")); mKeyguardSliceView.onChanged(builder.build()); Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader()); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index 1d8de2fbbcca..9e96df2c30cf 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -22,7 +22,6 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; -import android.widget.TextClock; import com.android.systemui.SysuiTestCase; @@ -40,7 +39,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase { @Mock KeyguardSliceView mKeyguardSlice; @Mock - TextClock mClockView; + KeyguardClockSwitch mClockView; @InjectMocks KeyguardStatusView mKeyguardStatusView; diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index 46e2bfbb1431..a26b1b55b30c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -137,7 +137,8 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void addZenMode_addedToSlice() { - ListBuilder listBuilder = spy(new ListBuilder(getContext(), mProvider.getUri())); + ListBuilder listBuilder = spy(new ListBuilder(getContext(), mProvider.getUri(), + ListBuilder.INFINITY)); mProvider.addZenMode(listBuilder); verify(listBuilder, never()).addRow(any(ListBuilder.RowBuilder.class)); diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml index 89e9d6ab8685..14e6e91e3a25 100644 --- a/packages/WAPPushManager/AndroidManifest.xml +++ b/packages/WAPPushManager/AndroidManifest.xml @@ -24,7 +24,8 @@ android:protectionLevel="signatureOrSystem" /> <original-package android:name="com.android.smspush" /> - <application> + <application + android:allowClearUserData="false"> <service android:name=".WapPushManager" android:permission="com.android.smspush.WAPPUSH_MANAGER_BIND" android:exported="true"> diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 6cc6221e50d5..f8b4d744efa9 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -941,9 +941,10 @@ message MetricsEvent { // OS: 6.0 NOTIFICATION_ZEN_MODE_EVENT_RULE = 146; - // ACTION: App notification settings > Block Notifications + // ACTION: App notification settings > Block Notifications or long press on + // notification blocks. // CATEGORY: SETTINGS - // OS: 6.0 + // OS: 9.0 ACTION_BAN_APP_NOTES = 147; // ACTION: Notification shade > Dismiss all button @@ -6425,6 +6426,10 @@ message MetricsEvent { // OS: Q (will also ship in PQ1A) FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH = 1553; + // OPEN: Settings > Add face + // OS: Q + FACE_ENROLL_PREVIEW = 1554; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index a40afc3cfa4d..f7c1c109266a 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -136,7 +136,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba CountDownLatch mLatch; FullBackupJob mJob; // if a scheduled job needs to be finished afterwards IBackupObserver mBackupObserver; - IBackupManagerMonitor mMonitor; + @Nullable private IBackupManagerMonitor mMonitor; boolean mUserInitiated; SinglePackageBackupRunner mBackupRunner; private final int mBackupRunnerOpToken; @@ -154,7 +154,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, - IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener, + @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener, boolean userInitiated) { super(observer); this.backupManagerService = backupManagerService; diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java new file mode 100644 index 000000000000..8c83e6756d1c --- /dev/null +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +import android.annotation.Nullable; +import android.app.backup.BackupManager; +import android.app.backup.BackupManagerMonitor; +import android.app.backup.BackupTransport; +import android.app.backup.IBackupManagerMonitor; +import android.app.backup.IBackupObserver; +import android.content.pm.PackageInfo; +import android.util.EventLog; +import android.util.Slog; + +import com.android.server.EventLogTags; +import com.android.server.backup.BackupManagerService; +import com.android.server.backup.DataChangedJournal; +import com.android.server.backup.remote.RemoteResult; +import com.android.server.backup.utils.BackupManagerMonitorUtils; +import com.android.server.backup.utils.BackupObserverUtils; + +import java.io.File; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +/** + * Reports events that happen during a key-value backup task to: + * + * <ul> + * <li>Logcat (main and event buffers). + * <li>Backup observer (see {@link IBackupObserver}). + * <li>Backup manager monitor (see {@link IBackupManagerMonitor}). + * </ul> + */ +// TODO: In KeyValueBackupTaskTest, remove direct assertions on logcat, observer or monitor and +// verify calls to this object. Add these and more assertions to the test of this class. +class KeyValueBackupReporter { + private static final String TAG = "KeyValueBackupTask"; + private static final boolean DEBUG = BackupManagerService.DEBUG; + private static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || true; + + private final BackupManagerService mBackupManagerService; + private final IBackupObserver mObserver; + @Nullable private IBackupManagerMonitor mMonitor; + + KeyValueBackupReporter( + BackupManagerService backupManagerService, + IBackupObserver observer, + IBackupManagerMonitor monitor) { + mBackupManagerService = backupManagerService; + mObserver = observer; + mMonitor = monitor; + } + + /** Returns the monitor or {@code null} if we lost connection to it. */ + @Nullable + IBackupManagerMonitor getMonitor() { + return mMonitor; + } + + void onSkipBackup() { + if (DEBUG) { + Slog.d(TAG, "Skipping backup since one is already in progress"); + } + } + + void onEmptyQueueAtStart() { + Slog.w(TAG, "Backup begun with an empty queue, nothing to do"); + } + + void onPmFoundInQueue() { + if (MORE_DEBUG) { + Slog.i(TAG, "PM metadata in queue, removing"); + } + } + + void onQueueReady(List<BackupRequest> queue) { + if (DEBUG) { + Slog.v(TAG, "Beginning backup of " + queue.size() + " targets"); + } + } + + void onTransportReady(String transportName) { + EventLog.writeEvent(EventLogTags.BACKUP_START, transportName); + } + + void onInitializeTransport(String transportName) { + Slog.i(TAG, "Initializing transport and resetting backup state"); + } + + void onTransportInitialized(int status) { + if (status == BackupTransport.TRANSPORT_OK) { + EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE); + } else { + EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)"); + Slog.e(TAG, "Transport error in initializeDevice()"); + } + } + + void onInitializeTransportError(Exception e) { + Slog.e(TAG, "Error during initialization", e); + } + + void onSkipPm() { + Slog.d(TAG, "Skipping backup of PM metadata"); + } + + void onInvokePmAgentError(Exception e) { + Slog.e(TAG, "Error during PM metadata backup", e); + } + + void onEmptyQueue() { + if (MORE_DEBUG) { + Slog.i(TAG, "Queue now empty"); + } + } + + void onStartPackageBackup(String packageName) { + Slog.d(TAG, "Starting key-value backup of " + packageName); + } + + void onPackageNotEligibleForBackup(String packageName) { + Slog.i(TAG, "Package " + packageName + " no longer supports backup, skipping"); + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED); + } + + void onPackageEligibleForFullBackup(String packageName) { + Slog.i( + TAG, + "Package " + packageName + " performs full-backup rather than key-value, skipping"); + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED); + } + + void onPackageStopped(String packageName) { + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED); + } + + void onBindAgentError(SecurityException e) { + Slog.d(TAG, "Error in bind/backup", e); + } + + void onAgentUnknown(String packageName) { + Slog.d(TAG, "Package does not exist, skipping"); + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND); + } + + void onAgentError(String packageName) { + if (MORE_DEBUG) { + Slog.i(TAG, "Agent failure for " + packageName + ", re-staging"); + } + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE); + } + + void onInvokeAgent(String packageName) { + if (DEBUG) { + Slog.d(TAG, "Invoking agent on " + packageName); + } + } + + void onAgentFilesReady(File backupDataFile) { + if (MORE_DEBUG) { + Slog.d(TAG, "Data file: " + backupDataFile); + } + } + + void onRestoreconFailed(File backupDataFile) { + Slog.e(TAG, "SELinux restorecon failed on " + backupDataFile); + } + + void onCallAgentDoBackupError(String packageName, boolean callingAgent, Exception e) { + if (callingAgent) { + Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e); + } else { + Slog.e(TAG, "Error before invoking agent on " + packageName + ": " + e); + } + EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString()); + } + + void onFailAgentError(String packageName) { + Slog.w(TAG, "Error conveying failure to " + packageName); + } + + void onAgentIllegalKey(PackageInfo packageInfo, String key) { + String packageName = packageInfo.packageName; + EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, "bad key"); + mMonitor = + BackupManagerMonitorUtils.monitorEvent( + mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY, + packageInfo, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + BackupManagerMonitorUtils.putMonitoringExtra( + null, BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY, key)); + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE); + if (MORE_DEBUG) { + Slog.i( + TAG, + "Agent failure for " + packageName + " with illegal key " + key + ", dropped"); + } + } + + void onReadAgentDataError(String packageName, IOException e) { + Slog.w(TAG, "Unable read backup data for " + packageName + ": " + e); + } + + void onWriteWidgetDataError(String packageName, IOException e) { + Slog.w(TAG, "Unable to save widget data for " + packageName + ": " + e); + } + + void onDigestError(NoSuchAlgorithmException e) { + Slog.e(TAG, "Unable to use SHA-1!"); + } + + void onWriteWidgetData(boolean priorStateExists, @Nullable byte[] widgetState) { + if (MORE_DEBUG) { + Slog.i( + TAG, + "Checking widget update: state=" + + (widgetState != null) + + " prior=" + + priorStateExists); + } + } + + void onTruncateDataError() { + Slog.w(TAG, "Unable to roll back"); + } + + void onSendDataToTransport(String packageName) { + if (MORE_DEBUG) { + Slog.v(TAG, "Sending non-empty data to transport for " + packageName); + } + } + + void onNonIncrementalAndNonIncrementalRequired() { + Slog.e(TAG, "Transport requested non-incremental but already the case"); + } + + void onEmptyData(PackageInfo packageInfo) { + if (MORE_DEBUG) { + Slog.i(TAG, "No backup data written, not calling transport"); + } + mMonitor = + BackupManagerMonitorUtils.monitorEvent( + mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND, + packageInfo, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); + } + + void onPackageBackupComplete(String packageName, long size) { + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.SUCCESS); + EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, packageName, size); + mBackupManagerService.logBackupComplete(packageName); + } + + void onPackageBackupRejected(String packageName) { + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); + EventLogTags.writeBackupAgentFailure(packageName, "Transport rejected"); + } + + void onPackageBackupQuotaExceeded(String packageName) { + if (MORE_DEBUG) { + Slog.d(TAG, "Package " + packageName + " hit quota limit on key-value backup"); + } + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); + EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, packageName); + } + + void onAgentDoQuotaExceededError(Exception e) { + Slog.e(TAG, "Unable to notify about quota exceeded: " + e); + } + + void onPackageBackupNonIncrementalRequired(PackageInfo packageInfo) { + Slog.i(TAG, "Transport lost data, retrying package"); + BackupManagerMonitorUtils.monitorEvent( + mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED, + packageInfo, + BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, + /* extras */ null); + } + + void onPackageBackupTransportFailure(String packageName) { + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED); + EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName); + } + + void onPackageBackupError(String packageName, Exception e) { + Slog.e(TAG, "Transport error backing up " + packageName, e); + BackupObserverUtils.sendBackupOnPackageResult( + mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED); + EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName); + } + + void onCloseFileDescriptorError(String logName) { + Slog.w(TAG, "Error closing " + logName + " file-descriptor"); + } + + void onCancel() { + if (MORE_DEBUG) { + Slog.v(TAG, "Cancel received"); + } + } + + void onAgentTimedOut(@Nullable PackageInfo packageInfo) { + String packageName = getPackageName(packageInfo); + Slog.i(TAG, "Agent " + packageName + " timed out"); + EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); + // Time-out used to be implemented as cancel w/ cancelAll = false. + // TODO: Change monitoring event to reflect time-out as an event itself. + mMonitor = + BackupManagerMonitorUtils.monitorEvent( + mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL, + packageInfo, + BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, + BackupManagerMonitorUtils.putMonitoringExtra( + null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, false)); + } + + void onAgentCancelled(@Nullable PackageInfo packageInfo) { + String packageName = getPackageName(packageInfo); + Slog.i(TAG, "Cancel backing up " + packageName); + EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); + mMonitor = + BackupManagerMonitorUtils.monitorEvent( + mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL, + packageInfo, + BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, + BackupManagerMonitorUtils.putMonitoringExtra( + null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, true)); + } + + private String getPackageName(@Nullable PackageInfo packageInfo) { + return (packageInfo != null) ? packageInfo.packageName : "no_package_yet"; + } + + void onRevertBackup() { + if (MORE_DEBUG) { + Slog.i(TAG, "Reverting backup queue, re-staging everything"); + } + } + + void onTransportRequestBackupTimeError(Exception e) { + Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e); + } + + void onRemoteCallReturned(RemoteResult result) { + if (MORE_DEBUG) { + Slog.v(TAG, "Agent call returned " + result); + } + } + + void onJournalDeleteFailed(DataChangedJournal journal) { + Slog.e(TAG, "Unable to remove backup journal file " + journal); + } + + void onSetCurrentTokenError(Exception e) { + Slog.e(TAG, "Transport threw reporting restore set: " + e); + } + + void onTransportNotInitialized() { + if (MORE_DEBUG) { + Slog.d(TAG, "Transport requires initialization, rerunning"); + } + } + + void onPendingInitializeTransportError(Exception e) { + Slog.w(TAG, "Failed to query transport name for pending init: " + e); + } + + void onBackupFinished(int status) { + BackupObserverUtils.sendBackupFinished(mObserver, status); + } + + void onStartFullBackup(List<String> pendingFullBackups) { + Slog.d(TAG, "Starting full backups for: " + pendingFullBackups); + } + + void onKeyValueBackupFinished() { + Slog.i(TAG, "K/V backup pass finished"); + } +} diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index 1cb99334dfeb..41013aafa504 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -16,7 +16,11 @@ package com.android.server.backup.keyvalue; -import static com.android.server.backup.BackupManagerService.DEBUG_BACKUP_TRACE; +import static android.os.ParcelFileDescriptor.MODE_CREATE; +import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; +import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; +import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; + import static com.android.server.backup.BackupManagerService.KEY_WIDGET_STATE; import static com.android.server.backup.BackupManagerService.OP_PENDING; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; @@ -29,7 +33,6 @@ import android.app.backup.BackupAgent; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupManager; -import android.app.backup.BackupManagerMonitor; import android.app.backup.BackupTransport; import android.app.backup.IBackupCallback; import android.app.backup.IBackupManager; @@ -47,7 +50,6 @@ import android.os.UserHandle; import android.os.WorkSource; import android.system.ErrnoException; import android.system.Os; -import android.util.EventLog; import android.util.Pair; import android.util.Slog; @@ -55,12 +57,12 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.backup.IBackupTransport; import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; -import com.android.server.EventLogTags; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; +import com.android.server.backup.TransportManager; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.internal.Operation; @@ -69,9 +71,8 @@ import com.android.server.backup.remote.RemoteCallable; import com.android.server.backup.remote.RemoteResult; import com.android.server.backup.transport.TransportClient; import com.android.server.backup.utils.AppBackupUtils; -import com.android.server.backup.utils.BackupManagerMonitorUtils; -import com.android.server.backup.utils.BackupObserverUtils; +import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -172,7 +173,7 @@ import java.util.concurrent.atomic.AtomicInteger; // TODO: Distinguish between cancel and time-out where possible for logging/monitoring/observing public class KeyValueBackupTask implements BackupRestoreTask, Runnable { private static final String TAG = "KeyValueBackupTask"; - private static final boolean DEBUG = BackupManagerService.DEBUG || true; + private static final boolean DEBUG = BackupManagerService.DEBUG; private static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || false; private static final int THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND; private static final AtomicInteger THREAD_COUNT = new AtomicInteger(); @@ -212,8 +213,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { List<BackupRequest> queue, @Nullable DataChangedJournal dataChangedJournal, IBackupObserver observer, - IBackupManagerMonitor monitor, - @Nullable OnTaskFinishedListener listener, + @Nullable IBackupManagerMonitor monitor, + OnTaskFinishedListener listener, List<String> pendingFullBackups, boolean userInitiated, boolean nonIncremental) { @@ -239,10 +240,13 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { } private final BackupManagerService mBackupManagerService; + private final PackageManager mPackageManager; + private final TransportManager mTransportManager; private final TransportClient mTransportClient; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private final IBackupObserver mObserver; - private final OnTaskFinishedListener mListener; + private final KeyValueBackupReporter mReporter; + private final OnTaskFinishedListener mTaskFinishedListener; private final boolean mUserInitiated; private final boolean mNonIncremental; private final int mCurrentOpToken; @@ -251,7 +255,6 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { private final List<BackupRequest> mQueue; private final List<String> mPendingFullBackups; @Nullable private final DataChangedJournal mJournal; - private IBackupManagerMonitor mMonitor; @Nullable private PerformFullTransportBackupTask mFullBackupTask; private IBackupAgent mAgentBinder; @@ -294,20 +297,22 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { List<BackupRequest> queue, @Nullable DataChangedJournal journal, IBackupObserver observer, - IBackupManagerMonitor monitor, - @Nullable OnTaskFinishedListener listener, + @Nullable IBackupManagerMonitor monitor, + OnTaskFinishedListener taskFinishedListener, List<String> pendingFullBackups, boolean userInitiated, boolean nonIncremental) { mBackupManagerService = backupManagerService; + mTransportManager = backupManagerService.getTransportManager(); + mPackageManager = backupManagerService.getPackageManager(); mTransportClient = transportClient; mOriginalQueue = queue; // We need to retain the original queue contents in case of transport failure - mQueue = new ArrayList<>(mOriginalQueue); + mQueue = new ArrayList<>(queue); mJournal = journal; mObserver = observer; - mMonitor = monitor; - mListener = (listener != null) ? listener : OnTaskFinishedListener.NOP; + mReporter = new KeyValueBackupReporter(backupManagerService, observer, monitor); + mTaskFinishedListener = taskFinishedListener; mPendingFullBackups = pendingFullBackups; mUserInitiated = userInitiated; mNonIncremental = nonIncremental; @@ -332,7 +337,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { public void run() { Process.setThreadPriority(THREAD_PRIORITY); - BackupState state = beginBackup(); + BackupState state = startBackup(); while (state == BackupState.RUNNING_QUEUE || state == BackupState.BACKUP_PM) { if (mCancelled) { state = BackupState.CANCELLED; @@ -342,24 +347,24 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { state = backupPm(); break; case RUNNING_QUEUE: - Pair<BackupState, RemoteResult> stateAndResult = invokeNextAgent(); + Pair<BackupState, RemoteResult> stateAndResult = extractNextAgentData(); state = stateAndResult.first; if (state == null) { - state = processAgentInvocation(stateAndResult.second); + state = handleAgentResult(stateAndResult.second); } break; } } if (state == BackupState.CANCELLED) { - finalizeCancelledBackup(); + finishCancelledBackup(); } else { - finalizeBackup(); + finishBackup(); } } - private BackupState processAgentInvocation(RemoteResult result) { + private BackupState handleAgentResult(RemoteResult result) { if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) { - // Not an explicit cancel, we need to flag it + // Not an explicit cancel, we need to flag it. mCancelled = true; handleAgentCancelled(); return BackupState.CANCELLED; @@ -373,7 +378,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { return BackupState.RUNNING_QUEUE; } Preconditions.checkState(result.succeeded()); - return handleAgentResult(result.get()); + return sendDataToTransport(result.get()); } @Override @@ -382,24 +387,10 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { @Override public void operationComplete(long unusedResult) {} - private BackupState beginBackup() { - if (DEBUG_BACKUP_TRACE) { - mBackupManagerService.clearBackupTrace(); - StringBuilder b = new StringBuilder(256); - b.append("beginBackup: ["); - for (BackupRequest req : mOriginalQueue) { - b.append(' '); - b.append(req.packageName); - } - b.append(" ]"); - mBackupManagerService.addBackupTrace(b.toString()); - } + private BackupState startBackup() { synchronized (mBackupManagerService.getCurrentOpLock()) { if (mBackupManagerService.isBackupOperationInProgress()) { - if (DEBUG) { - Slog.d(TAG, "Skipping backup since one is already in progress"); - } - mBackupManagerService.addBackupTrace("Skipped. Backup already in progress."); + mReporter.onSkipBackup(); return BackupState.FINAL; } } @@ -415,19 +406,17 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { /* runningJob */ null, new CountDownLatch(1), mObserver, - mMonitor, - mListener, + mReporter.getMonitor(), + mTaskFinishedListener, mUserInitiated); registerTask(); - mBackupManagerService.addBackupTrace("STATE => INITIAL"); mAgentBinder = null; mStatus = BackupTransport.TRANSPORT_OK; // Sanity check: if the queue is empty we have no work to do. if (mOriginalQueue.isEmpty() && mPendingFullBackups.isEmpty()) { - Slog.w(TAG, "Backup begun with an empty queue, nothing to do."); - mBackupManagerService.addBackupTrace("queue empty at begin"); + mReporter.onEmptyQueueAtStart(); return BackupState.FINAL; } @@ -441,55 +430,39 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { // we're committed to evaluating it for backup regardless. for (int i = 0; i < mQueue.size(); i++) { if (PACKAGE_MANAGER_SENTINEL.equals(mQueue.get(i).packageName)) { - if (MORE_DEBUG) { - Slog.i(TAG, "PM metadata in queue, removing"); - } + mReporter.onPmFoundInQueue(); mQueue.remove(i); skipPm = false; break; } } + mReporter.onQueueReady(mQueue); - if (DEBUG) { - Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets"); - } File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL); try { - IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.beginBackup()"); + IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.startBackup()"); String transportName = transport.name(); - EventLog.writeEvent(EventLogTags.BACKUP_START, transportName); + mReporter.onTransportReady(transportName); - // If we haven't stored package manager metadata yet, we must init the transport. + // If we haven't stored PM metadata yet, we must initialize the transport. if (pmState.length() <= 0) { - Slog.i(TAG, "Initializing transport and resetting backup state"); - mBackupManagerService.addBackupTrace("initializing transport " + transportName); - mBackupManagerService.resetBackupState(mStateDir); // Just to make sure. + mReporter.onInitializeTransport(transportName); + mBackupManagerService.resetBackupState(mStateDir); mStatus = transport.initializeDevice(); - - mBackupManagerService.addBackupTrace("transport.initializeDevice() == " + mStatus); - if (mStatus == BackupTransport.TRANSPORT_OK) { - EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE); - } else { - EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)"); - Slog.e(TAG, "Transport error in initializeDevice()"); - } + mReporter.onTransportInitialized(mStatus); } } catch (Exception e) { - Slog.e(TAG, "Error during initialization", e); - mBackupManagerService.addBackupTrace("Exception in backup thread during init: " + e); + mReporter.onInitializeTransportError(e); mStatus = BackupTransport.TRANSPORT_ERROR; } - mBackupManagerService.addBackupTrace("exiting prelim: " + mStatus); if (mStatus != BackupTransport.TRANSPORT_OK) { - // if things went wrong at this point, we need to - // restage everything and try again later. - mBackupManagerService.resetBackupState(mStateDir); // Just to make sure. + mBackupManagerService.resetBackupState(mStateDir); return BackupState.FINAL; } if (skipPm) { - Slog.d(TAG, "Skipping backup of PM metadata"); + mReporter.onSkipPm(); return BackupState.RUNNING_QUEUE; } @@ -498,38 +471,27 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { private BackupState backupPm() { RemoteResult agentResult = null; - BackupState nextState; try { - // The package manager doesn't have a proper <application> etc, but since it's running - // here in the system process we can just set up its agent directly and use a synthetic - // BackupRequest. + // Since PM is running in the system process we can set up its agent directly. BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent(); Pair<Integer, RemoteResult> statusAndResult = - invokeAgentForBackup( + extractAgentData( PACKAGE_MANAGER_SENTINEL, IBackupAgent.Stub.asInterface(pmAgent.onBind())); mStatus = statusAndResult.first; agentResult = statusAndResult.second; - - mBackupManagerService.addBackupTrace("PM agent invoke: " + mStatus); } catch (Exception e) { - Slog.e(TAG, "Error during PM metadata backup", e); - mBackupManagerService.addBackupTrace("Exception in backup thread during pm: " + e); + mReporter.onInvokePmAgentError(e); mStatus = BackupTransport.TRANSPORT_ERROR; } - mBackupManagerService.addBackupTrace("exiting backupPm: " + mStatus); - if (mStatus == BackupTransport.TRANSPORT_OK) { - Preconditions.checkNotNull(agentResult); - nextState = processAgentInvocation(agentResult); - } else { - // if things went wrong at this point, we need to - // restage everything and try again later. - mBackupManagerService.resetBackupState(mStateDir); // Just to make sure. - nextState = BackupState.FINAL; + if (mStatus != BackupTransport.TRANSPORT_OK) { + mBackupManagerService.resetBackupState(mStateDir); + return BackupState.FINAL; } - return nextState; + Preconditions.checkNotNull(agentResult); + return handleAgentResult(agentResult); } /** @@ -540,250 +502,183 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { * <li>({@code null}, agent result): In case we successfully called the agent. * </ul> */ - private Pair<BackupState, RemoteResult> invokeNextAgent() { + private Pair<BackupState, RemoteResult> extractNextAgentData() { mStatus = BackupTransport.TRANSPORT_OK; - mBackupManagerService.addBackupTrace("invoke q=" + mQueue.size()); - // Sanity check that we have work to do. If not, skip to the end where - // we reestablish the wakelock invariants etc. if (mQueue.isEmpty()) { - if (MORE_DEBUG) { - Slog.i(TAG, "Queue now empty"); - } + mReporter.onEmptyQueue(); return Pair.create(BackupState.FINAL, null); } - // pop the entry we're going to process on this step BackupRequest request = mQueue.remove(0); + String packageName = request.packageName; + mReporter.onStartPackageBackup(packageName); - Slog.d(TAG, "Starting key-value backup of " + request); - mBackupManagerService.addBackupTrace("launch agent for " + request.packageName); - - // Verify that the requested app exists; it might be something that - // requested a backup but was then uninstalled. The request was - // journalled and rather than tamper with the journal it's safer - // to sanity-check here. This also gives us the classname of the - // package's backup agent. + // Verify that the requested app is eligible for key-value backup. RemoteResult agentResult = null; try { - PackageManager pm = mBackupManagerService.getPackageManager(); - mCurrentPackage = pm.getPackageInfo(request.packageName, - PackageManager.GET_SIGNING_CERTIFICATES); - if (!AppBackupUtils.appIsEligibleForBackup(mCurrentPackage.applicationInfo, pm)) { - // The manifest has changed but we had a stale backup request pending. This won't - // happen again because the app won't be requesting further backups. - Slog.i(TAG, "Package " + request.packageName - + " no longer supports backup, skipping"); - mBackupManagerService.addBackupTrace("skipping - not eligible, completion is noop"); - // Shouldn't happen in case of requested backup, as pre-check was done in - // #requestBackup(), except to app update done concurrently - BackupObserverUtils.sendBackupOnPackageResult(mObserver, - mCurrentPackage.packageName, - BackupManager.ERROR_BACKUP_NOT_ALLOWED); + mCurrentPackage = mPackageManager.getPackageInfo( + request.packageName, PackageManager.GET_SIGNING_CERTIFICATES); + ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo; + if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) { + // The manifest has changed. This won't happen again because the app won't be + // requesting further backups. + mReporter.onPackageNotEligibleForBackup(packageName); return Pair.create(BackupState.RUNNING_QUEUE, null); } if (AppBackupUtils.appGetsFullBackup(mCurrentPackage)) { - // It's possible that this app *formerly* was enqueued for key-value backup, but has - // since been updated and now only supports the full-backup path. Don't proceed with - // a key-value backup for it in this case. - Slog.i(TAG, "Package " + request.packageName - + " performs full-backup rather than key-value, skipping"); - mBackupManagerService.addBackupTrace( - "skipping - fullBackupOnly, completion is noop"); - // Shouldn't happen in case of requested backup, as pre-check was done in - // #requestBackup() - BackupObserverUtils.sendBackupOnPackageResult(mObserver, - mCurrentPackage.packageName, - BackupManager.ERROR_BACKUP_NOT_ALLOWED); + // Initially enqueued for key-value backup, but only supports full-backup now. + mReporter.onPackageEligibleForFullBackup(packageName); return Pair.create(BackupState.RUNNING_QUEUE, null); } - if (AppBackupUtils.appIsStopped(mCurrentPackage.applicationInfo)) { - // The app has been force-stopped or cleared or just installed, - // and not yet launched out of that state, so just as it won't - // receive broadcasts, we won't run it for backup. - mBackupManagerService.addBackupTrace("skipping - stopped"); - BackupObserverUtils.sendBackupOnPackageResult(mObserver, - mCurrentPackage.packageName, - BackupManager.ERROR_BACKUP_NOT_ALLOWED); + if (AppBackupUtils.appIsStopped(applicationInfo)) { + // Just as it won't receive broadcasts, we won't run it for backup. + mReporter.onPackageStopped(packageName); return Pair.create(BackupState.RUNNING_QUEUE, null); } try { - mBackupManagerService.setWorkSource( - new WorkSource(mCurrentPackage.applicationInfo.uid)); + mBackupManagerService.setWorkSource(new WorkSource(applicationInfo.uid)); IBackupAgent agent = mBackupManagerService.bindToAgentSynchronous( - mCurrentPackage.applicationInfo, + applicationInfo, ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); - mBackupManagerService.addBackupTrace("agent bound; a? = " + (agent != null)); if (agent != null) { mAgentBinder = agent; Pair<Integer, RemoteResult> statusAndResult = - invokeAgentForBackup(request.packageName, agent); + extractAgentData(request.packageName, agent); mStatus = statusAndResult.first; agentResult = statusAndResult.second; } else { - // Timeout waiting for the agent + // Timeout waiting for the agent to bind. mStatus = BackupTransport.AGENT_ERROR; } - } catch (SecurityException se) { - // Try for the next one. - Slog.d(TAG, "Error in bind/backup", se); + } catch (SecurityException e) { + mReporter.onBindAgentError(e); mStatus = BackupTransport.AGENT_ERROR; - mBackupManagerService.addBackupTrace("agent SE"); } } catch (PackageManager.NameNotFoundException e) { - Slog.d(TAG, "Package does not exist, skipping"); - mBackupManagerService.addBackupTrace("no such package"); mStatus = BackupTransport.AGENT_UNKNOWN; } finally { mBackupManagerService.setWorkSource(null); } if (mStatus != BackupTransport.TRANSPORT_OK) { - BackupState nextState = BackupState.RUNNING_QUEUE; mAgentBinder = null; - // An agent-level failure means we re-enqueue this one agent for - // a later retry, but otherwise proceed normally. if (mStatus == BackupTransport.AGENT_ERROR) { - if (MORE_DEBUG) { - Slog.i(TAG, "Agent failure for " + request.packageName + ", re-staging"); - } + mReporter.onAgentError(packageName); mBackupManagerService.dataChangedImpl(request.packageName); mStatus = BackupTransport.TRANSPORT_OK; - BackupObserverUtils - .sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName, - BackupManager.ERROR_AGENT_FAILURE); - } else if (mStatus == BackupTransport.AGENT_UNKNOWN) { - // Failed lookup of the app, so we couldn't bring up an agent, but - // we're otherwise fine. Just drop it and go on to the next as usual. + return Pair.create(BackupState.RUNNING_QUEUE, null); + } + + if (mStatus == BackupTransport.AGENT_UNKNOWN) { + mReporter.onAgentUnknown(packageName); mStatus = BackupTransport.TRANSPORT_OK; - BackupObserverUtils - .sendBackupOnPackageResult(mObserver, request.packageName, - BackupManager.ERROR_PACKAGE_NOT_FOUND); - } else { - // Transport-level failure means we re-enqueue everything - revertAndEndBackup(); - nextState = BackupState.FINAL; + return Pair.create(BackupState.RUNNING_QUEUE, null); } - return Pair.create(nextState, null); + // Transport-level failure, re-enqueue everything. + revertBackup(); + return Pair.create(BackupState.FINAL, null); } // Success: caller will figure out the state based on call result - mBackupManagerService.addBackupTrace("call made; result = " + agentResult); return Pair.create(null, agentResult); } - private void finalizeBackup() { - mBackupManagerService.addBackupTrace("finishing"); - - // Mark packages that we didn't backup (because backup was cancelled, etc.) as needing - // backup. - for (BackupRequest req : mQueue) { - mBackupManagerService.dataChangedImpl(req.packageName); + private void finishBackup() { + // Mark packages that we couldn't backup as pending backup. + for (BackupRequest request : mQueue) { + mBackupManagerService.dataChangedImpl(request.packageName); } - // Either backup was successful, in which case we of course do not need - // this pass's journal any more; or it failed, in which case we just - // re-enqueued all of these packages in the current active journal. - // Either way, we no longer need this pass's journal. + // If backup succeeded, we just invalidated this journal. If not, we've already re-enqueued + // the packages and also don't need the journal. if (mJournal != null && !mJournal.delete()) { - Slog.e(TAG, "Unable to remove backup journal file " + mJournal); + mReporter.onJournalDeleteFailed(mJournal); } - // If everything actually went through and this is the first time we've - // done a backup, we can now record what the current backup dataset token - // is. - String callerLogString = "KVBT.finalizeBackup()"; - if ((mBackupManagerService.getCurrentToken() == 0) && (mStatus - == BackupTransport.TRANSPORT_OK)) { - mBackupManagerService.addBackupTrace("success; recording token"); + String callerLogString = "KVBT.finishBackup()"; + + // If we succeeded and this is the first time we've done a backup, we can record the current + // backup dataset token. + long currentToken = mBackupManagerService.getCurrentToken(); + if ((mStatus == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) { try { IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString); mBackupManagerService.setCurrentToken(transport.getCurrentRestoreSet()); mBackupManagerService.writeRestoreTokens(); } catch (Exception e) { - // nothing for it at this point, unfortunately, but this will be - // recorded the next time we fully succeed. - Slog.e(TAG, "Transport threw reporting restore set: " + e); - mBackupManagerService.addBackupTrace("transport threw returning token"); + // This will be recorded the next time we succeed. + mReporter.onSetCurrentTokenError(e); } } - // Set up the next backup pass - at this point we can set mBackupRunning - // to false to allow another pass to fire synchronized (mBackupManagerService.getQueueLock()) { mBackupManagerService.setBackupRunning(false); if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) { - if (MORE_DEBUG) { - Slog.d(TAG, "Transport requires initialization, rerunning"); - } - mBackupManagerService.addBackupTrace("init required; rerunning"); + mReporter.onTransportNotInitialized(); try { - String name = mBackupManagerService.getTransportManager() - .getTransportName(mTransportClient.getTransportComponent()); - mBackupManagerService.getPendingInits().add(name); + IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString); + mBackupManagerService.getPendingInits().add(transport.name()); + clearPmMetadata(); + mBackupManagerService.backupNow(); } catch (Exception e) { - Slog.w(TAG, "Failed to query transport name for init: " + e); - // swallow it and proceed; we don't rely on this + mReporter.onPendingInitializeTransportError(e); } - clearMetadata(); - mBackupManagerService.backupNow(); } } - mBackupManagerService.clearBackupTrace(); - unregisterTask(); - - if (!mCancelled && mStatus == BackupTransport.TRANSPORT_OK && - mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) { - Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups); - // Acquiring wakelock for PerformFullTransportBackupTask before its start. - mBackupManagerService.getWakelock().acquire(); - // The full-backup task is now responsible for calling onFinish() on mListener, which - // was the listener we passed it. + mReporter.onKeyValueBackupFinished(); + + if (!mCancelled + && mStatus == BackupTransport.TRANSPORT_OK + && mFullBackupTask != null + && !mPendingFullBackups.isEmpty()) { + mReporter.onStartFullBackup(mPendingFullBackups); + // The key-value backup has finished but not the overall backup. Full-backup task will: + // * Call mObserver.backupFinished() (which is called by mReporter below). + // * Call mTaskFinishedListener.onFinished(). + // * Release the wakelock. (new Thread(mFullBackupTask, "full-transport-requested")).start(); - } else if (mCancelled) { - mListener.onFinished(callerLogString); - if (mFullBackupTask != null) { - mFullBackupTask.unregisterTask(); - } - BackupObserverUtils.sendBackupFinished(mObserver, BackupManager.ERROR_BACKUP_CANCELLED); - } else { - mListener.onFinished(callerLogString); - if (mFullBackupTask != null) { - mFullBackupTask.unregisterTask(); - } - switch (mStatus) { - case BackupTransport.TRANSPORT_OK: - case BackupTransport.TRANSPORT_QUOTA_EXCEEDED: - case BackupTransport.TRANSPORT_PACKAGE_REJECTED: - BackupObserverUtils.sendBackupFinished(mObserver, BackupManager.SUCCESS); - break; - case BackupTransport.TRANSPORT_NOT_INITIALIZED: - BackupObserverUtils.sendBackupFinished(mObserver, - BackupManager.ERROR_TRANSPORT_ABORTED); - break; - case BackupTransport.TRANSPORT_ERROR: - default: - BackupObserverUtils.sendBackupFinished(mObserver, - BackupManager.ERROR_TRANSPORT_ABORTED); - break; - } + return; } - Slog.i(TAG, "K/V backup pass finished"); + + if (mFullBackupTask != null) { + mFullBackupTask.unregisterTask(); + } + mTaskFinishedListener.onFinished(callerLogString); + mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, mStatus)); mBackupManagerService.getWakelock().release(); } - // Remove the PM metadata state. This will generate an init on the next pass. - private void clearMetadata() { - final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL); - if (pmState.exists()) pmState.delete(); + private int getBackupFinishedStatus(boolean cancelled, int transportStatus) { + if (cancelled) { + return BackupManager.ERROR_BACKUP_CANCELLED; + } + switch (transportStatus) { + case BackupTransport.TRANSPORT_OK: + case BackupTransport.TRANSPORT_QUOTA_EXCEEDED: + case BackupTransport.TRANSPORT_PACKAGE_REJECTED: + return BackupManager.SUCCESS; + case BackupTransport.TRANSPORT_NOT_INITIALIZED: + case BackupTransport.TRANSPORT_ERROR: + default: + return BackupManager.ERROR_TRANSPORT_ABORTED; + } + } + + /** Removes PM state, triggering initialization in the next key-value task. */ + private void clearPmMetadata() { + File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL); + if (pmState.exists()) { + pmState.delete(); + } } /** @@ -791,22 +686,16 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { * {@link BackupTransport#TRANSPORT_OK}, the second of the pair contains the agent result, * otherwise {@code null}. */ - private Pair<Integer, RemoteResult> invokeAgentForBackup( - String packageName, IBackupAgent agent) { - if (DEBUG) { - Slog.d(TAG, "Invoking agent on " + packageName); - } - mBackupManagerService.addBackupTrace("invoking " + packageName); + private Pair<Integer, RemoteResult> extractAgentData(String packageName, IBackupAgent agent) { + mReporter.onInvokeAgent(packageName); File blankStateFile = new File(mStateDir, BLANK_STATE_FILE_NAME); mSavedStateFile = new File(mStateDir, packageName); + File savedStateFileForAgent = (mNonIncremental) ? blankStateFile : mSavedStateFile; mBackupDataFile = new File(mBackupManagerService.getDataDir(), packageName + STAGING_FILE_SUFFIX); mNewStateFile = new File(mStateDir, packageName + NEW_STATE_FILE_SUFFIX); - if (MORE_DEBUG) { - Slog.d(TAG, "Data file: " + mBackupDataFile); - } - + mReporter.onAgentFilesReady(mBackupDataFile); mSavedState = null; mBackupData = null; @@ -815,46 +704,31 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { boolean callingAgent = false; final RemoteResult agentResult; try { - // Look up the package info & signatures. This is first so that if it - // throws an exception, there's no file setup yet that would need to - // be unraveled. + // TODO: Move this to backupPm() if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) { - // The metadata 'package' is synthetic; construct one and make - // sure our global state is pointed at it mCurrentPackage = new PackageInfo(); mCurrentPackage.packageName = packageName; } + // MODE_CREATE to make an empty file if necessary mSavedState = ParcelFileDescriptor.open( - (mNonIncremental) ? blankStateFile : mSavedStateFile, - ParcelFileDescriptor.MODE_READ_ONLY | - ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary - - mBackupData = ParcelFileDescriptor.open(mBackupDataFile, - ParcelFileDescriptor.MODE_READ_WRITE | - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE); + savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE); + mBackupData = ParcelFileDescriptor.open( + mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE); + mNewState = ParcelFileDescriptor.open( + mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE); if (!SELinux.restorecon(mBackupDataFile)) { - Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataFile); + mReporter.onRestoreconFailed(mBackupDataFile); } - mNewState = ParcelFileDescriptor.open(mNewStateFile, - ParcelFileDescriptor.MODE_READ_WRITE | - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE); - - IBackupTransport transport = - mTransportClient.connectOrThrow("KVBT.invokeAgentForBackup()"); - - final long quota = transport.getBackupQuota(packageName, false /* isFullBackup */); - callingAgent = true; - - // Initiate the target's backup pass + IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.extractAgentData()"); + long quota = transport.getBackupQuota(packageName, /* isFullBackup */ false); + int transportFlags = transport.getTransportFlags(); long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); - mBackupManagerService.addBackupTrace("calling agent doBackup()"); + callingAgent = true; agentResult = remoteCall( callback -> @@ -864,22 +738,19 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { mNewState, quota, callback, - transport.getTransportFlags()), + transportFlags), kvBackupAgentTimeoutMillis); } catch (Exception e) { - Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e); - mBackupManagerService.addBackupTrace("exception: " + e); - EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString()); + mReporter.onCallAgentDoBackupError(packageName, callingAgent, e); errorCleanup(); + // TODO: Remove the check on callingAgent when RemoteCall supports local agent calls. int status = callingAgent ? BackupTransport.AGENT_ERROR : BackupTransport.TRANSPORT_ERROR; return Pair.create(status, null); - } finally { - if (mNonIncremental) { - blankStateFile.delete(); - } } - + if (mNonIncremental) { + blankStateFile.delete(); + } return Pair.create(BackupTransport.TRANSPORT_OK, agentResult); } @@ -887,7 +758,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { try { agent.fail(message); } catch (Exception e) { - Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName); + mReporter.onFailAgentError(mCurrentPackage.packageName); } } @@ -898,36 +769,27 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { MessageDigest md = MessageDigest.getInstance("SHA-1"); checksum = md.digest(input); } catch (NoSuchAlgorithmException e) { - Slog.e(TAG, "Unable to use SHA-1!"); + mReporter.onDigestError(e); return "00"; } - StringBuffer sb = new StringBuffer(checksum.length * 2); + StringBuilder string = new StringBuilder(checksum.length * 2); for (byte item : checksum) { - sb.append(Integer.toHexString(item)); + string.append(Integer.toHexString(item)); } - return sb.toString(); + return string.toString(); } private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName) throws IOException { // TODO: http://b/22388012 byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, UserHandle.USER_SYSTEM); - // has the widget state changed since last time? - final File widgetFile = new File(mStateDir, pkgName + "_widget"); - final boolean priorStateExists = widgetFile.exists(); - - if (MORE_DEBUG) { - if (priorStateExists || widgetState != null) { - Slog.i(TAG, "Checking widget update: state=" + (widgetState != null) - + " prior=" + priorStateExists); - } - } - + File widgetFile = new File(mStateDir, pkgName + "_widget"); + boolean priorStateExists = widgetFile.exists(); if (!priorStateExists && widgetState == null) { - // no prior state, no new state => nothing to do return; } + mReporter.onWriteWidgetData(priorStateExists, widgetState); // if the new state is not null, we might need to compare checksums to // determine whether to update the widget blob in the archive. If the @@ -969,93 +831,67 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { } } - private BackupState handleAgentResult(long unusedResult) { + private BackupState sendDataToTransport(long agentResult) { Preconditions.checkState(mBackupData != null); - final String pkgName = mCurrentPackage.packageName; - final long filepos = mBackupDataFile.length(); + String packageName = mCurrentPackage.packageName; + ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo; + long filePos = mBackupDataFile.length(); FileDescriptor fd = mBackupData.getFileDescriptor(); + boolean writingWidgetData = false; try { - // If it's a 3rd party app, see whether they wrote any protected keys - // and complain mightily if they are attempting shenanigans. - if (mCurrentPackage.applicationInfo != null && - (mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) - == 0) { - ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataFile, - ParcelFileDescriptor.MODE_READ_ONLY); + // If it's a 3rd party app, crash them if they wrote any protected keys. + if (applicationInfo != null && + (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + ParcelFileDescriptor readFd = + ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY); BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor()); try { while (in.readNextHeader()) { - final String key = in.getKey(); + String key = in.getKey(); if (key != null && key.charAt(0) >= 0xff00) { - // Not okay: crash them and bail. + mReporter.onAgentIllegalKey(mCurrentPackage, key); failAgent(mAgentBinder, "Illegal backup key: " + key); - mBackupManagerService - .addBackupTrace("illegal key " + key + " from " + pkgName); - EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName, - "bad key"); - mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY, - mCurrentPackage, - BackupManagerMonitor - .LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, - BackupManagerMonitorUtils.putMonitoringExtra(null, - BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY, - key)); - BackupObserverUtils - .sendBackupOnPackageResult(mObserver, pkgName, - BackupManager.ERROR_AGENT_FAILURE); errorCleanup(); - if (MORE_DEBUG) { - Slog.i(TAG, "Agent failure for " + pkgName - + " with illegal key " + key + ", dropped"); - } - return BackupState.RUNNING_QUEUE; } in.skipEntityData(); } } finally { - if (readFd != null) { - readFd.close(); - } + readFd.close(); } } - // Piggyback the widget state payload, if any - writeWidgetPayloadIfAppropriate(fd, pkgName); + writingWidgetData = true; + writeWidgetPayloadIfAppropriate(fd, packageName); } catch (IOException e) { - // Hard disk error; recovery/failure policy TBD. For now roll back, - // but we may want to consider this a transport-level failure (i.e. - // we're in such a bad state that we can't contemplate doing backup - // operations any more during this pass). - Slog.w(TAG, "Unable read backup data or to save widget state for " + pkgName); + if (writingWidgetData) { + mReporter.onWriteWidgetDataError(packageName, e); + } else { + mReporter.onReadAgentDataError(packageName, e); + } try { - Os.ftruncate(fd, filepos); + Os.ftruncate(fd, filePos); } catch (ErrnoException ee) { - Slog.w(TAG, "Unable to roll back"); + mReporter.onTruncateDataError(); } } clearAgentState(); - mBackupManagerService.addBackupTrace("operation complete"); ParcelFileDescriptor backupData = null; mStatus = BackupTransport.TRANSPORT_OK; long size = 0; try { - IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.handleAgentResult()"); + IBackupTransport transport = + mTransportClient.connectOrThrow("KVBT.sendDataToTransport()"); size = mBackupDataFile.length(); if (size > 0) { - if (MORE_DEBUG) { - Slog.v(TAG, "Sending non-empty data to transport for " + pkgName); - } boolean isNonIncremental = mSavedStateFile.length() == 0; - if (mStatus == BackupTransport.TRANSPORT_OK) { - backupData = ParcelFileDescriptor.open(mBackupDataFile, - ParcelFileDescriptor.MODE_READ_ONLY); - mBackupManagerService.addBackupTrace("sending data to transport"); + if (mStatus == BackupTransport.TRANSPORT_OK) { + mReporter.onSendDataToTransport(packageName); + backupData = ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY); int userInitiatedFlag = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0; int incrementalFlag = @@ -1069,114 +905,58 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { if (isNonIncremental && mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) { - // TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED is only valid if the backup was - // incremental, as if the backup is non-incremental there is no state to - // clear. This avoids us ending up in a retry loop if the transport always - // returns this code. - Slog.e(TAG, "Transport requested non-incremental but already the case"); - mBackupManagerService.addBackupTrace( - "Transport requested non-incremental but already the case, error"); + mReporter.onNonIncrementalAndNonIncrementalRequired(); mStatus = BackupTransport.TRANSPORT_ERROR; } - mBackupManagerService.addBackupTrace("data delivered: " + mStatus); if (mStatus == BackupTransport.TRANSPORT_OK) { - mBackupManagerService.addBackupTrace("finishing op on transport"); mStatus = transport.finishBackup(); - mBackupManagerService.addBackupTrace("finished: " + mStatus); - } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { - mBackupManagerService.addBackupTrace("transport rejected package"); } } else { - if (MORE_DEBUG) { - Slog.i(TAG, "No backup data written, not calling transport"); - } - mBackupManagerService.addBackupTrace("no data to send"); - mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND, - mCurrentPackage, - BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, - null); + mReporter.onEmptyData(mCurrentPackage); } if (mStatus == BackupTransport.TRANSPORT_OK) { - // After successful transport, delete the now-stale data - // and juggle the files so that next time we supply the agent - // with the new state file it just created. mBackupDataFile.delete(); mNewStateFile.renameTo(mSavedStateFile); - BackupObserverUtils.sendBackupOnPackageResult( - mObserver, pkgName, BackupManager.SUCCESS); - EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size); - mBackupManagerService.logBackupComplete(pkgName); + mReporter.onPackageBackupComplete(packageName, size); } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { - // The transport has rejected backup of this specific package. Roll it - // back but proceed with running the rest of the queue. mBackupDataFile.delete(); mNewStateFile.delete(); - BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName, - BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); - EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected"); + mReporter.onPackageBackupRejected(packageName); } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { - BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName, - BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); - EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName); - + // TODO: Should reset files like above? + mReporter.onPackageBackupQuotaExceeded(packageName); } else if (mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) { - Slog.i(TAG, "Transport lost data, retrying package"); - mBackupManagerService.addBackupTrace( - "Transport lost data, retrying package:" + pkgName); - BackupManagerMonitorUtils.monitorEvent( - mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED, - mCurrentPackage, - BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, - /*extras=*/ null); - + mReporter.onPackageBackupNonIncrementalRequired(mCurrentPackage); mBackupDataFile.delete(); mSavedStateFile.delete(); mNewStateFile.delete(); // Immediately retry the package by adding it back to the front of the queue. // We cannot add @pm@ to the queue because we back it up separately at the start - // of the backup pass in state BACKUP_PM. Instead we retry this state (see - // below). - if (!PACKAGE_MANAGER_SENTINEL.equals(pkgName)) { - mQueue.add(0, new BackupRequest(pkgName)); + // of the backup pass in state BACKUP_PM. See below. + if (!PACKAGE_MANAGER_SENTINEL.equals(packageName)) { + mQueue.add(0, new BackupRequest(packageName)); } - } else { - // Actual transport-level failure to communicate the data to the backend - BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName, - BackupManager.ERROR_TRANSPORT_ABORTED); - EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName); + mReporter.onPackageBackupTransportFailure(packageName); } } catch (Exception e) { - BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName, - BackupManager.ERROR_TRANSPORT_ABORTED); - Slog.e(TAG, "Transport error backing up " + pkgName, e); - EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName); + mReporter.onPackageBackupError(packageName, e); mStatus = BackupTransport.TRANSPORT_ERROR; } finally { - try { - if (backupData != null) { - backupData.close(); - } - } catch (IOException e) { - Slog.w(TAG, "Error closing backup data file-descriptor"); - } + tryCloseFileDescriptor(backupData, "backup data"); } final BackupState nextState; if (mStatus == BackupTransport.TRANSPORT_OK || mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { - // Success or single-package rejection. Proceed with the next app if any, - // otherwise we're done. nextState = BackupState.RUNNING_QUEUE; } else if (mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) { // We want to immediately retry the current package. - if (PACKAGE_MANAGER_SENTINEL.equals(pkgName)) { + if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) { nextState = BackupState.BACKUP_PM; } else { // This is an ordinary package so we will have added it back into the queue @@ -1185,25 +965,21 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { } } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { - if (MORE_DEBUG) { - Slog.d(TAG, "Package " + mCurrentPackage.packageName + - " hit quota limit on key-value backup"); - } if (mAgentBinder != null) { try { IBackupTransport transport = - mTransportClient.connectOrThrow("KVBT.handleAgentResult()"); + mTransportClient.connectOrThrow("KVBT.sendDataToTransport()"); long quota = transport.getBackupQuota(mCurrentPackage.packageName, false); mAgentBinder.doQuotaExceeded(size, quota); } catch (Exception e) { - Slog.e(TAG, "Unable to notify about quota exceeded: " + e.getMessage()); + mReporter.onAgentDoQuotaExceededError(e); } } nextState = BackupState.RUNNING_QUEUE; } else { // Any other error here indicates a transport-level failure. That means // we need to halt everything and reschedule everything for next time. - revertAndEndBackup(); + revertBackup(); nextState = BackupState.FINAL; } @@ -1223,10 +999,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { */ @Override public void handleCancel(boolean cancelAll) { + // This is called in a thread different from the one that executes method run(). Preconditions.checkArgument(cancelAll, "Can't partially cancel a key-value backup task"); - if (MORE_DEBUG) { - Slog.v(TAG, "Cancel received"); - } + mReporter.onCancel(); mCancelled = true; RemoteCall pendingCall = mPendingCall; if (pendingCall != null) { @@ -1236,66 +1011,35 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { } private void handleAgentTimeout() { - String packageName = getPackageNameForLog(); - Slog.i(TAG, "Agent " + packageName + " timed out"); - EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); - mBackupManagerService.addBackupTrace("timeout of " + packageName); - mMonitor = - BackupManagerMonitorUtils.monitorEvent( - mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL, - mCurrentPackage, - BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, - BackupManagerMonitorUtils.putMonitoringExtra( - null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, false)); + mReporter.onAgentTimedOut(mCurrentPackage); errorCleanup(); } private void handleAgentCancelled() { - String packageName = getPackageNameForLog(); - Slog.i(TAG, "Cancel backing up " + packageName); - EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); - mBackupManagerService.addBackupTrace("cancel of " + packageName); + mReporter.onAgentCancelled(mCurrentPackage); errorCleanup(); } - private void finalizeCancelledBackup() { - mMonitor = - BackupManagerMonitorUtils.monitorEvent( - mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL, - mCurrentPackage, - BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, - BackupManagerMonitorUtils.putMonitoringExtra( - null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, true)); - finalizeBackup(); + private void finishCancelledBackup() { + finishBackup(); // finalizeBackup() may call the transport, so we only acknowledge the cancellation here. mCancelAcknowledged.open(); } - private String getPackageNameForLog() { - return (mCurrentPackage != null) ? mCurrentPackage.packageName : "no_package_yet"; - } - - private void revertAndEndBackup() { - if (MORE_DEBUG) { - Slog.i(TAG, "Reverting backup queue, re-staging everything"); - } - mBackupManagerService.addBackupTrace("transport error; reverting"); - - // We want to reset the backup schedule based on whatever the transport suggests - // by way of retry/backoff time. + private void revertBackup() { + mReporter.onRevertBackup(); long delay; try { IBackupTransport transport = - mTransportClient.connectOrThrow("KVBT.revertAndEndBackup()"); + mTransportClient.connectOrThrow("KVBT.revertBackup()"); delay = transport.requestBackupTime(); } catch (Exception e) { - Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e); - delay = 0; // use the scheduler's default + mReporter.onTransportRequestBackupTimeError(e); + // Use the scheduler's default. + delay = 0; } - KeyValueBackupJob.schedule(mBackupManagerService.getContext(), delay, - mBackupManagerService.getConstants()); + KeyValueBackupJob.schedule( + mBackupManagerService.getContext(), delay, mBackupManagerService.getConstants()); for (BackupRequest request : mOriginalQueue) { mBackupManagerService.dataChangedImpl(request.packageName); @@ -1308,50 +1052,37 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { clearAgentState(); } - // Cleanup common to both success and failure cases private void clearAgentState() { - try { - if (mSavedState != null) { - mSavedState.close(); - } - } catch (IOException e) { - Slog.w(TAG, "Error closing old state file-descriptor"); - } - try { - if (mBackupData != null) { - mBackupData.close(); - } - } catch (IOException e) { - Slog.w(TAG, "Error closing backup data file-descriptor"); - } - try { - if (mNewState != null) { - mNewState.close(); - } - } catch (IOException e) { - Slog.w(TAG, "Error closing new state file-descriptor"); - } + // Cleanup common to both success and failure cases. + tryCloseFileDescriptor(mSavedState, "old state"); + tryCloseFileDescriptor(mBackupData, "backup data"); + tryCloseFileDescriptor(mNewState, "new state"); synchronized (mBackupManagerService.getCurrentOpLock()) { - // Current-operation callback handling requires the validity of these various - // bits of internal state as an invariant of the operation still being live. - // This means we make sure to clear all of the state in unison inside the lock. + // TODO: Do we still need this? mSavedState = mBackupData = mNewState = null; } - // If this was a pseudo-package there's no associated Activity Manager state + // For PM metadata (for which applicationInfo is null) there is no agent-bound state. if (mCurrentPackage.applicationInfo != null) { - mBackupManagerService.addBackupTrace("unbinding " + mCurrentPackage.packageName); mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo); } } + private void tryCloseFileDescriptor(@Nullable Closeable closeable, String logName) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + mReporter.onCloseFileDescriptorError(logName); + } + } + } + private RemoteResult remoteCall(RemoteCallable<IBackupCallback> remoteCallable, long timeoutMs) throws RemoteException { mPendingCall = new RemoteCall(mCancelled, remoteCallable, timeoutMs); RemoteResult result = mPendingCall.call(); - if (MORE_DEBUG) { - Slog.v(TAG, "Agent call returned " + result); - } + mReporter.onRemoteCallReturned(result); mPendingCall = null; return result; } diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java index 28e9b77c82fc..9af952ddfc1c 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -136,7 +136,14 @@ public class AppBackupUtils { /** * Checks if the app is in a stopped state. This is not part of the general "eligible for * backup?" check because we *do* still need to restore data to apps in this state (e.g. - * newly-installing ones) + * newly-installing ones). + * + * <p>Reasons for such state: + * <ul> + * <li>The app has been force-stopped. + * <li>The app has been cleared. + * <li>The app has just been installed. + * </ul> */ public static boolean appIsStopped(ApplicationInfo app) { return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0); diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java index b23781d37569..6f083760980d 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java +++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java @@ -21,6 +21,7 @@ import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NA import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.TAG; +import android.annotation.Nullable; import android.app.backup.BackupManagerMonitor; import android.app.backup.IBackupManagerMonitor; import android.content.pm.PackageInfo; @@ -44,8 +45,13 @@ public class BackupManagerMonitorUtils { * @param extras - additional event data. * @return <code>monitor</code> if call succeeded and <code>null</code> otherwise. */ - public static IBackupManagerMonitor monitorEvent(IBackupManagerMonitor monitor, int id, - PackageInfo pkg, int category, Bundle extras) { + @Nullable + public static IBackupManagerMonitor monitorEvent( + @Nullable IBackupManagerMonitor monitor, + int id, + PackageInfo pkg, + int category, + Bundle extras) { if (monitor != null) { try { Bundle bundle = new Bundle(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6b3f8f8eb216..914404be887f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2194,8 +2194,7 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: { - Integer score = (Integer) msg.obj; - if (score != null) updateNetworkScore(nai, score.intValue()); + updateNetworkScore(nai, msg.arg1); break; } case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: { diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index d06e78514a5c..f4d20b332e2f 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -1014,12 +1014,7 @@ public class SyncManager { Bundle finalExtras = new Bundle(extras); String packageName = syncAdapterInfo.componentName.getPackageName(); // If the app did not run and has no account access, done - try { - if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) { - continue; - } - } catch (IllegalArgumentException e) { - // Package not found, race with an uninstall + if (!wasPackageEverLaunched(packageName, userId)) { continue; } mAccountManagerInternal.requestAccountAccess(account.account, @@ -3352,7 +3347,7 @@ public class SyncManager { String packageName = op.owningPackage; final int userId = UserHandle.getUserId(op.owningUid); // If the app did not run and has no account access, done - if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) { + if (!wasPackageEverLaunched(packageName, userId)) { return; } mAccountManagerInternal.requestAccountAccess(op.target.account, @@ -4059,4 +4054,12 @@ public class SyncManager { public void resetTodayStats() { mSyncStorageEngine.resetTodayStats(/*force=*/ true); } + + private boolean wasPackageEverLaunched(String packageName, int userId) { + try { + return mPackageManagerInternal.wasPackageEverLaunched(packageName, userId); + } catch (IllegalArgumentException e) { + return false; // Package has been removed. + } + } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 3f57faf58e8c..f487200e40c1 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2144,6 +2144,10 @@ public class NotificationManagerService extends SystemService { enforceSystemOrSystemUI("setNotificationsEnabledForPackage"); mPreferencesHelper.setEnabled(pkg, uid, enabled); + mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) + .setType(MetricsEvent.TYPE_ACTION) + .setPackageName(pkg) + .setSubtype(enabled ? 1 : 0)); // Now, cancel any outstanding notifications that are part of a just-disabled app if (!enabled) { cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true, diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ed1dc58701bd..5769207e8536 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -917,6 +917,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.USER_ACTIVITY); + break; case MSG_RINGER_TOGGLE_CHORD: handleRingerChordGesture(); break; @@ -2452,11 +2453,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; break; case TYPE_STATUS_BAR: + // If the Keyguard is in a hidden state (occluded by another window), we force to - // remove the keyguard flag so that any change in-flight after setting - // the keyguard as occluded wouldn't set the flag again. + // remove the wallpaper and keyguard flag so that any change in-flight after setting + // the keyguard as occluded wouldn't set these flags again. // See {@link #processKeyguardSetHiddenResultLw}. if (mKeyguardOccluded) { + attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; } break; @@ -5517,13 +5520,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate.setOccluded(false, true /* animate */); if (mStatusBar != null) { mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD; + if (!mKeyguardDelegate.hasLockscreenWallpaper()) { + mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER; + } } return true; } else if (isOccluded && changed && showing) { mKeyguardOccluded = true; - mKeyguardDelegate.setOccluded(true, !mShowingDream /* animate */); + mKeyguardDelegate.setOccluded(true, false /* animate */); if (mStatusBar != null) { mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD; + mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; } return true; } else if (changed) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 3ae5cedec773..b55adeb32729 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1711,8 +1711,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } /** - * Requests that the WindowManager sends WindowManagerPolicy#ACTION_USER_ACTIVITY_NOTIFICATION - * on the next user activity. + * Requests that the WindowManager sends + * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity. */ public void requestUserActivityNotification(); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 7ee35e79e2e4..d73606f3003f 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1557,7 +1557,7 @@ public class AppTransition implements Dump { if (isKeyguardGoingAwayTransit(transit) && enter) { a = loadKeyguardExitAnimation(transit); } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) { - a = loadAnimationRes(lp, com.android.internal.R.anim.keyguard_occlude_open_enter); + a = null; } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) { a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit); } else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 44d01871b693..ae2256aa26b2 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2128,6 +2128,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } mService.mAnimator.removeDisplayLocked(mDisplayId); + mWindowingLayer.release(); + mOverlayLayer.release(); } finally { mRemovingDisplay = false; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index b5566a7dca08..dea40769f4fd 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -361,6 +361,11 @@ public class RecentsAnimationController implements DeathRecipient { new RemoteAnimationTarget[appAnimations.size()]); mPendingStart = false; + // Perform layout if it was scheduled before to make sure that we get correct content + // insets for the target app window after a rotation + final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId); + displayContent.performLayout(false /* initial */, false /* updateInputWindows */); + final Rect minimizedHomeBounds = mTargetAppToken != null && mTargetAppToken.inSplitScreenSecondaryWindowingMode() ? mMinimizedHomeBounds @@ -369,8 +374,7 @@ public class RecentsAnimationController implements DeathRecipient { && mTargetAppToken.findMainWindow() != null ? mTargetAppToken.findMainWindow().mContentInsets : null; - mRunner.onAnimationStart(mController, appTargets, contentInsets, - minimizedHomeBounds); + mRunner.onAnimationStart(mController, appTargets, contentInsets, minimizedHomeBounds); if (DEBUG_RECENTS_ANIMATIONS) { Slog.d(TAG, "startAnimation(): Notify animation start:"); for (int i = 0; i < mPendingAnimations.size(); i++) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b6f3d3b337e8..c82c242ea522 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -28,6 +28,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; +import android.database.sqlite.SQLiteGlobal; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -355,6 +356,10 @@ public final class SystemServer { Binder.setWarnOnBlocking(true); // The system server should always load safe labels PackageItemInfo.setForceSafeLabels(true); + + // Default to FULL within the system server. + SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL; + // Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized SQLiteCompatibilityWalFlags.init(null); diff --git a/services/robotests/README b/services/robotests/README new file mode 100644 index 000000000000..3c682922102d --- /dev/null +++ b/services/robotests/README @@ -0,0 +1,23 @@ +This folder is for Robolectric tests inside the platform. + +To add a test class annotate it as follows: + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderClasses({ClassUnderTest.class, DependencyClasses.class}) +@SystemLoaderPackages({"com.android.server.yourmodule"}) + +Robolectric loads some classes that it decides from versioned jars of the framework. Since we are +part of the framework some of our classes get loaded from these jars. This is NOT what we want, we +want to test against what we wrote in the tree. Because of this we use a custom test runner, +FrameworkRobolectricTestRunner, that bypasses these jars and loads certain classes from the system +class loader. + +To specify which classes to load use either @SystemLoaderClasses or @SystemLoaderPackages. In +practice: +* You MUST put the class under test here. +* If you encounter any exceptions that might be caused by a different version of the class being +loaded, such as NoSuchMethodException, put the class involved in the exception in this annotation +and try again. + +Check Android.mk file for more info. diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index de22201e3874..e316d5b48de5 100644 --- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -1382,6 +1382,7 @@ public class KeyValueBackupTaskTest { verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L)); assertEventLogged(EventLogTags.BACKUP_QUOTA_EXCEEDED, PACKAGE_1.packageName); assertBackupNotPendingFor(PACKAGE_1); + // TODO: Assert about state/staging files (possible bug) } @Test diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index 25851e32f6c6..b7ccee5871d0 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -16,16 +16,16 @@ package android.telephony; -import android.os.Parcel; -import android.os.Parcelable; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE; import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS; import static android.telephony.TelephonyManager.NETWORK_TYPE_HSDPA; -import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA; import static android.telephony.TelephonyManager.NETWORK_TYPE_HSPA; +import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; +import android.os.Parcel; +import android.os.Parcelable; /** @@ -100,6 +100,39 @@ public class NeighboringCellInfo implements Parcelable mCid = cid; } + /** @hide */ + public NeighboringCellInfo(final CellInfoGsm info) { + mNetworkType = TelephonyManager.NETWORK_TYPE_GPRS; + + mRssi = info.getCellSignalStrength().getAsuLevel(); + if (mRssi == Integer.MAX_VALUE) mRssi = UNKNOWN_RSSI; + + mLac = info.getCellIdentity().getLac(); + if (mLac == Integer.MAX_VALUE) mLac = UNKNOWN_CID; + + mCid = info.getCellIdentity().getCid(); + if (mCid == Integer.MAX_VALUE) mCid = UNKNOWN_CID; + + mPsc = UNKNOWN_CID; + } + + /** @hide */ + public NeighboringCellInfo(final CellInfoWcdma info) { + mNetworkType = TelephonyManager.NETWORK_TYPE_UMTS; + + mRssi = info.getCellSignalStrength().getAsuLevel(); + if (mRssi == Integer.MAX_VALUE) mRssi = UNKNOWN_RSSI; + + mLac = info.getCellIdentity().getLac(); + if (mLac == Integer.MAX_VALUE) mLac = UNKNOWN_CID; + + mCid = info.getCellIdentity().getCid(); + if (mCid == Integer.MAX_VALUE) mCid = UNKNOWN_CID; + + mPsc = info.getCellIdentity().getPsc(); + if (mPsc == Integer.MAX_VALUE) mPsc = UNKNOWN_CID; + } + /** * Initialize the object from rssi, location string, and radioType * radioType is one of following diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index b2eb5e03db31..8782a41bca94 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1544,7 +1544,7 @@ public class TelephonyManager { * @return List of NeighboringCellInfo or null if info unavailable. * * @deprecated Use {@link #getAllCellInfo} which returns a superset of the information - * from NeighboringCellInfo. + * from NeighboringCellInfo, including LTE cell information. */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java index c6f8622f3fd9..e924a2521617 100644 --- a/telephony/java/android/telephony/ims/ImsSsInfo.java +++ b/telephony/java/android/telephony/ims/ImsSsInfo.java @@ -16,10 +16,14 @@ package android.telephony.ims; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Provides the result to the update operation for the supplementary service configuration. * @@ -34,6 +38,30 @@ public final class ImsSsInfo implements Parcelable { public static final int DISABLED = 0; public static final int ENABLED = 1; + /** + * Provision status of service + */ + /** @hide */ + @IntDef({ + SERVICE_PROVISIONING_UNKNOWN, + SERVICE_NOT_PROVISIONED, + SERVICE_PROVISIONED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ServiceProvisionStatus {} + /** + * Unknown provision status for the service. + */ + public static final int SERVICE_PROVISIONING_UNKNOWN = (-1); + /** + * Service is not provisioned. + */ + public static final int SERVICE_NOT_PROVISIONED = 0; + /** + * Service is provisioned. + */ + public static final int SERVICE_PROVISIONED = 1; + // 0: disabled, 1: enabled /** @hide */ // TODO: Make private, do not modify this field directly, use getter! @@ -41,6 +69,8 @@ public final class ImsSsInfo implements Parcelable { /** @hide */ // TODO: Make private, do not modify this field directly, use getter! public String mIcbNum; + /** @hide */ + public int mProvisionStatus = SERVICE_PROVISIONING_UNKNOWN; /**@hide*/ // TODO: Remove! Do not use this constructor, instead use public version. @@ -74,16 +104,30 @@ public final class ImsSsInfo implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(mStatus); out.writeString(mIcbNum); + out.writeInt(mProvisionStatus); } @Override public String toString() { - return super.toString() + ", Status: " + ((mStatus == 0) ? "disabled" : "enabled"); + return super.toString() + ", Status: " + ((mStatus == 0) ? "disabled" : "enabled") + + ", ProvisionStatus: " + provisionStatusToString(mProvisionStatus); + } + + private static String provisionStatusToString(int pStatus) { + switch (pStatus) { + case SERVICE_NOT_PROVISIONED: + return "Service not provisioned"; + case SERVICE_PROVISIONED: + return "Service provisioned"; + default: + return "Service provisioning unknown"; + } } private void readFromParcel(Parcel in) { mStatus = in.readInt(); mIcbNum = in.readString(); + mProvisionStatus = in.readInt(); } public static final Creator<ImsSsInfo> CREATOR = @@ -112,4 +156,15 @@ public final class ImsSsInfo implements Parcelable { public String getIcbNum() { return mIcbNum; } + + /** + * @return Supplementary Service Provision status. Valid Values are: + * {@link #SERVICE_PROVISIONING_UNKNOWN}, + * {@link #SERVICE_NOT_PROVISIONED}, + * {@link #SERVICE_PROVISIONED} + */ + @ServiceProvisionStatus + public int getProvisionStatus() { + return mProvisionStatus; + } } |