Merge "startop: Add iorap parcelables for AIDL interfaces"
This commit is contained in:
51
startop/iorap/Android.bp
Normal file
51
startop/iorap/Android.bp
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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.
|
||||
|
||||
java_library_static {
|
||||
name: "libiorap-java",
|
||||
|
||||
aidl: {
|
||||
include_dirs: [
|
||||
"system/iorap/binder",
|
||||
],
|
||||
},
|
||||
|
||||
srcs: [
|
||||
":iorap-aidl",
|
||||
"**/*.java",
|
||||
],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "libiorap-java-tests",
|
||||
srcs: ["tests/src/**/*.kt"],
|
||||
|
||||
static_libs: [
|
||||
// non-test dependencies
|
||||
"libiorap-java",
|
||||
// test android dependencies
|
||||
"platform-test-annotations",
|
||||
"android-support-test",
|
||||
// test framework dependencies
|
||||
"mockito-target-inline-minus-junit4",
|
||||
"truth-prebuilt",
|
||||
],
|
||||
|
||||
//sdk_version: "current",
|
||||
//certificate: "platform",
|
||||
|
||||
libs: ["android.test.base"],
|
||||
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
31
startop/iorap/AndroidManifest.xml
Normal file
31
startop/iorap/AndroidManifest.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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.
|
||||
-->
|
||||
<!--suppress AndroidUnknownAttribute -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.startop.iorap.tests"
|
||||
android:sharedUserId="com.google.android.startop.iorap.tests"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<!--suppress AndroidDomInspection -->
|
||||
<instrumentation
|
||||
android:name="android.support.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.google.android.startop.iorap.tests" />
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Provide a hint to iorapd that an activity has transitioned state.<br /><br />
|
||||
*
|
||||
* Knowledge of when an activity starts/stops can be used by iorapd to increase system
|
||||
* performance (e.g. by launching perfetto tracing to record an io profile, or by
|
||||
* playing back an ioprofile via readahead) over the long run.<br /><br />
|
||||
*
|
||||
* /@see com.google.android.startop.iorap.IIorap#onActivityHintEvent<br /><br />
|
||||
*
|
||||
* Once an activity hint is in {@link #TYPE_STARTED} it must transition to another type.
|
||||
* All other states could be terminal, see below: <br /><br />
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* ┌──────────────────────────────────────┐
|
||||
* │ ▼
|
||||
* ┌─────────┐ ╔════════════════╗ ╔═══════════╗
|
||||
* ──▶ │ STARTED │ ──▶ ║ COMPLETED ║ ──▶ ║ CANCELLED ║
|
||||
* └─────────┘ ╚════════════════╝ ╚═══════════╝
|
||||
* │
|
||||
* │
|
||||
* ▼
|
||||
* ╔════════════════╗
|
||||
* ║ POST_COMPLETED ║
|
||||
* ╚════════════════╝
|
||||
*
|
||||
* </pre> <!-- system/iorap/docs/binder/ActivityHint.dot -->
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class ActivityHintEvent implements Parcelable {
|
||||
|
||||
public static final int TYPE_STARTED = 0;
|
||||
public static final int TYPE_CANCELLED = 1;
|
||||
public static final int TYPE_COMPLETED = 2;
|
||||
public static final int TYPE_POST_COMPLETED = 3;
|
||||
private static final int TYPE_MAX = TYPE_POST_COMPLETED;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
|
||||
TYPE_STARTED,
|
||||
TYPE_CANCELLED,
|
||||
TYPE_COMPLETED,
|
||||
TYPE_POST_COMPLETED,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
|
||||
@Type public final int type;
|
||||
public final ActivityInfo activityInfo;
|
||||
|
||||
public ActivityHintEvent(@Type int type, ActivityInfo activityInfo) {
|
||||
this.type = type;
|
||||
this.activityInfo = activityInfo;
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
CheckHelpers.checkTypeInRange(type, TYPE_MAX);
|
||||
Objects.requireNonNull(activityInfo, "activityInfo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{type: %d, activityInfo: %s}", type, activityInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof ActivityHintEvent) {
|
||||
return equals((ActivityHintEvent) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(ActivityHintEvent other) {
|
||||
return type == other.type &&
|
||||
Objects.equals(activityInfo, other.activityInfo);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(type);
|
||||
activityInfo.writeToParcel(out, flags);
|
||||
}
|
||||
|
||||
private ActivityHintEvent(Parcel in) {
|
||||
this.type = in.readInt();
|
||||
this.activityInfo = ActivityInfo.CREATOR.createFromParcel(in);
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ActivityHintEvent> CREATOR
|
||||
= new Parcelable.Creator<ActivityHintEvent>() {
|
||||
public ActivityHintEvent createFromParcel(Parcel in) {
|
||||
return new ActivityHintEvent(in);
|
||||
}
|
||||
|
||||
public ActivityHintEvent[] newArray(int size) {
|
||||
return new ActivityHintEvent[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
/**
|
||||
* Provide minimal information for launched activities to iorap.<br /><br />
|
||||
*
|
||||
* This uniquely identifies a system-wide activity by providing the {@link #packageName} and
|
||||
* {@link #activityName}.
|
||||
*
|
||||
* @see ActivityHintEvent
|
||||
* @see AppIntentEvent
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class ActivityInfo implements Parcelable {
|
||||
|
||||
/** The name of the package, for example {@code com.android.calculator}. */
|
||||
public final String packageName;
|
||||
/** The name of the activity, for example {@code .activities.activity.MainActivity} */
|
||||
public final String activityName;
|
||||
|
||||
public ActivityInfo(String packageName, String activityName) {
|
||||
this.packageName = packageName;
|
||||
this.activityName = activityName;
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
Objects.requireNonNull(packageName, "packageName");
|
||||
Objects.requireNonNull(activityName, "activityName");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{packageName: %s, activityName: %s}", packageName, activityName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof ActivityInfo) {
|
||||
return equals((ActivityInfo) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(ActivityInfo other) {
|
||||
return Objects.equals(packageName, other.packageName) &&
|
||||
Objects.equals(activityName, other.activityName);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(packageName);
|
||||
out.writeString(activityName);
|
||||
}
|
||||
|
||||
private ActivityInfo(Parcel in) {
|
||||
packageName = in.readString();
|
||||
activityName = in.readString();
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ActivityInfo> CREATOR
|
||||
= new Parcelable.Creator<ActivityInfo>() {
|
||||
public ActivityInfo createFromParcel(Parcel in) {
|
||||
return new ActivityInfo(in);
|
||||
}
|
||||
|
||||
public ActivityInfo[] newArray(int size) {
|
||||
return new ActivityInfo[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Notifications for iorapd specifying when a system-wide intent defaults change.<br /><br />
|
||||
*
|
||||
* Intent defaults provide a mechanism for an app to register itself as an automatic handler.
|
||||
* For example the camera app might be registered as the default handler for
|
||||
* {@link android.provider.MediaStore#INTENT_ACTION_STILL_IMAGE_CAMERA} intent. Subsequently,
|
||||
* if an arbitrary other app requests for a still image camera photo to be taken, the system
|
||||
* will launch the respective default camera app to be launched to handle that request.<br /><br />
|
||||
*
|
||||
* In some cases iorapd might need to know default intents, e.g. for boot-time pinning of
|
||||
* applications that resolve from the default intent. If the application would now be resolved
|
||||
* differently, iorapd would unpin the old application and pin the new application.<br /><br />
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class AppIntentEvent implements Parcelable {
|
||||
|
||||
/** @see android.content.Intent#CATEGORY_DEFAULT */
|
||||
public static final int TYPE_DEFAULT_INTENT_CHANGED = 0;
|
||||
private static final int TYPE_MAX = 0;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
|
||||
TYPE_DEFAULT_INTENT_CHANGED,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
|
||||
@Type public final int type;
|
||||
|
||||
public final ActivityInfo oldActivityInfo;
|
||||
public final ActivityInfo newActivityInfo;
|
||||
|
||||
// TODO: Probably need the corresponding action here as well.
|
||||
|
||||
public static AppIntentEvent createDefaultIntentChanged(ActivityInfo oldActivityInfo,
|
||||
ActivityInfo newActivityInfo) {
|
||||
return new AppIntentEvent(TYPE_DEFAULT_INTENT_CHANGED, oldActivityInfo,
|
||||
newActivityInfo);
|
||||
}
|
||||
|
||||
private AppIntentEvent(@Type int type, ActivityInfo oldActivityInfo,
|
||||
ActivityInfo newActivityInfo) {
|
||||
this.type = type;
|
||||
this.oldActivityInfo = oldActivityInfo;
|
||||
this.newActivityInfo = newActivityInfo;
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
CheckHelpers.checkTypeInRange(type, TYPE_MAX);
|
||||
Objects.requireNonNull(oldActivityInfo, "oldActivityInfo");
|
||||
Objects.requireNonNull(oldActivityInfo, "newActivityInfo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{oldActivityInfo: %s, newActivityInfo: %s}", oldActivityInfo,
|
||||
newActivityInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof AppIntentEvent) {
|
||||
return equals((AppIntentEvent) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(AppIntentEvent other) {
|
||||
return type == other.type &&
|
||||
Objects.equals(oldActivityInfo, other.oldActivityInfo) &&
|
||||
Objects.equals(newActivityInfo, other.newActivityInfo);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(type);
|
||||
oldActivityInfo.writeToParcel(out, flags);
|
||||
newActivityInfo.writeToParcel(out, flags);
|
||||
}
|
||||
|
||||
private AppIntentEvent(Parcel in) {
|
||||
this.type = in.readInt();
|
||||
this.oldActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
|
||||
this.newActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<AppIntentEvent> CREATOR
|
||||
= new Parcelable.Creator<AppIntentEvent>() {
|
||||
public AppIntentEvent createFromParcel(Parcel in) {
|
||||
return new AppIntentEvent(in);
|
||||
}
|
||||
|
||||
public AppIntentEvent[] newArray(int size) {
|
||||
return new AppIntentEvent[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
/**
|
||||
* Convenience short-hand to throw {@link IllegalAccessException} when the arguments
|
||||
* are out-of-range.
|
||||
*/
|
||||
public class CheckHelpers {
|
||||
/** @throws IllegalAccessException if {@param type} is not in {@code [0..maxValue]} */
|
||||
public static void checkTypeInRange(int type, int maxValue) {
|
||||
if (type < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("type must be non-negative (value=%d)", type));
|
||||
}
|
||||
if (type > maxValue) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("type out of range (value=%d, max=%d)", type, maxValue));
|
||||
}
|
||||
}
|
||||
|
||||
/** @throws IllegalAccessException if {@param state} is not in {@code [0..maxValue]} */
|
||||
public static void checkStateInRange(int state, int maxValue) {
|
||||
if (state < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("state must be non-negative (value=%d)", state));
|
||||
}
|
||||
if (state > maxValue) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("state out of range (value=%d, max=%d)", state, maxValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.net.Uri;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Forward package manager events to iorapd. <br /><br />
|
||||
*
|
||||
* Knowing when packages are modified by the system are a useful tidbit to help with performance:
|
||||
* for example when a package is replaced, it could be a hint used to invalidate any collected
|
||||
* io profiles used for prefetching or pinning.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class PackageEvent implements Parcelable {
|
||||
|
||||
/** @see android.content.Intent#ACTION_PACKAGE_REPLACED */
|
||||
public static final int TYPE_REPLACED = 0;
|
||||
private static final int TYPE_MAX = 0;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
|
||||
TYPE_REPLACED,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
|
||||
@Type public final int type;
|
||||
|
||||
/** The path that a package is installed in, for example {@code /data/app/.../base.apk}. */
|
||||
public final Uri packageUri;
|
||||
/** The name of the package, for example {@code com.android.calculator}. */
|
||||
public final String packageName;
|
||||
|
||||
@NonNull
|
||||
public static PackageEvent createReplaced(Uri packageUri, String packageName) {
|
||||
return new PackageEvent(TYPE_REPLACED, packageUri, packageName);
|
||||
}
|
||||
|
||||
private PackageEvent(@Type int type, Uri packageUri, String packageName) {
|
||||
this.type = type;
|
||||
this.packageUri = packageUri;
|
||||
this.packageName = packageName;
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
CheckHelpers.checkTypeInRange(type, TYPE_MAX);
|
||||
Objects.requireNonNull(packageUri, "packageUri");
|
||||
Objects.requireNonNull(packageName, "packageName");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof PackageEvent) {
|
||||
return equals((PackageEvent) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(PackageEvent other) {
|
||||
return type == other.type &&
|
||||
Objects.equals(packageUri, other.packageUri) &&
|
||||
Objects.equals(packageName, other.packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{packageUri: %s, packageName: %s}", packageUri, packageName);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(type);
|
||||
packageUri.writeToParcel(out, flags);
|
||||
out.writeString(packageName);
|
||||
}
|
||||
|
||||
private PackageEvent(Parcel in) {
|
||||
this.type = in.readInt();
|
||||
this.packageUri = Uri.CREATOR.createFromParcel(in);
|
||||
this.packageName = in.readString();
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<PackageEvent> CREATOR
|
||||
= new Parcelable.Creator<PackageEvent>() {
|
||||
public PackageEvent createFromParcel(Parcel in) {
|
||||
return new PackageEvent(in);
|
||||
}
|
||||
|
||||
public PackageEvent[] newArray(int size) {
|
||||
return new PackageEvent[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Uniquely identify an {@link com.google.android.startop.iorap.IIorap} method invocation,
|
||||
* used for asynchronous callbacks by the server. <br /><br />
|
||||
*
|
||||
* As all system server binder calls must be {@code oneway}, this means all invocations
|
||||
* into {@link com.google.android.startop.iorap.IIorap} are non-blocking. The request ID
|
||||
* exists to associate all calls with their respective callbacks in
|
||||
* {@link com.google.android.startop.iorap.ITaskListener}.
|
||||
*
|
||||
* @see com.google.android.startop.iorap.IIorap
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class RequestId implements Parcelable {
|
||||
|
||||
public final long requestId;
|
||||
|
||||
private static Object mLock = new Object();
|
||||
private static long mNextRequestId = 0;
|
||||
|
||||
/**
|
||||
* Create a monotonically increasing request ID.<br /><br />
|
||||
*
|
||||
* It is invalid to re-use the same request ID for multiple method calls on
|
||||
* {@link com.google.android.startop.iorap.IIorap}; a new request ID must be created
|
||||
* each time.
|
||||
*/
|
||||
@NonNull public static RequestId nextValueForSequence() {
|
||||
long currentRequestId;
|
||||
synchronized (mLock) {
|
||||
currentRequestId = mNextRequestId;
|
||||
++mNextRequestId;
|
||||
}
|
||||
return new RequestId(currentRequestId);
|
||||
}
|
||||
|
||||
private RequestId(long requestId) {
|
||||
this.requestId = requestId;
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
if (requestId < 0) {
|
||||
throw new IllegalArgumentException("request id must be non-negative");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{requestId: %ld}", requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof RequestId) {
|
||||
return equals((RequestId) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(RequestId other) {
|
||||
return requestId == other.requestId;
|
||||
}
|
||||
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeLong(requestId);
|
||||
}
|
||||
|
||||
private RequestId(Parcel in) {
|
||||
requestId = in.readLong();
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<RequestId> CREATOR
|
||||
= new Parcelable.Creator<RequestId>() {
|
||||
public RequestId createFromParcel(Parcel in) {
|
||||
return new RequestId(in);
|
||||
}
|
||||
|
||||
public RequestId[] newArray(int size) {
|
||||
return new RequestId[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Forward system service events to iorapd.
|
||||
*
|
||||
* @see com.android.server.SystemService
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SystemServiceEvent implements Parcelable {
|
||||
|
||||
/** @see com.android.server.SystemService#onBootPhase */
|
||||
public static final int TYPE_BOOT_PHASE = 0;
|
||||
/** @see com.android.server.SystemService#onStart */
|
||||
public static final int TYPE_START = 1;
|
||||
private static final int TYPE_MAX = TYPE_START;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
|
||||
TYPE_BOOT_PHASE,
|
||||
TYPE_START,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
|
||||
@Type public final int type;
|
||||
|
||||
// TODO: do we want to pass the exact build phase enum?
|
||||
|
||||
public SystemServiceEvent(@Type int type) {
|
||||
this.type = type;
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
CheckHelpers.checkTypeInRange(type, TYPE_MAX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{type: %d}", type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof SystemServiceEvent) {
|
||||
return equals((SystemServiceEvent) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(SystemServiceEvent other) {
|
||||
return type == other.type;
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(type);
|
||||
}
|
||||
|
||||
private SystemServiceEvent(Parcel in) {
|
||||
this.type = in.readInt();
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SystemServiceEvent> CREATOR
|
||||
= new Parcelable.Creator<SystemServiceEvent>() {
|
||||
public SystemServiceEvent createFromParcel(Parcel in) {
|
||||
return new SystemServiceEvent(in);
|
||||
}
|
||||
|
||||
public SystemServiceEvent[] newArray(int size) {
|
||||
return new SystemServiceEvent[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Forward user events to iorapd.<br /><br />
|
||||
*
|
||||
* Knowledge of the logged-in user is reserved to be used to set-up appropriate policies
|
||||
* by iorapd (e.g. to handle user default pinned applications changing).
|
||||
*
|
||||
* @see com.android.server.SystemService
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SystemServiceUserEvent implements Parcelable {
|
||||
|
||||
/** @see com.android.server.SystemService#onStartUser */
|
||||
public static final int TYPE_START_USER = 0;
|
||||
/** @see com.android.server.SystemService#onUnlockUser */
|
||||
public static final int TYPE_UNLOCK_USER = 1;
|
||||
/** @see com.android.server.SystemService#onSwitchUser*/
|
||||
public static final int TYPE_SWITCH_USER = 2;
|
||||
/** @see com.android.server.SystemService#onStopUser */
|
||||
public static final int TYPE_STOP_USER = 3;
|
||||
/** @see com.android.server.SystemService#onCleanupUser */
|
||||
public static final int TYPE_CLEANUP_USER = 4;
|
||||
private static final int TYPE_MAX = TYPE_CLEANUP_USER;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
|
||||
TYPE_START_USER,
|
||||
TYPE_UNLOCK_USER,
|
||||
TYPE_SWITCH_USER,
|
||||
TYPE_STOP_USER,
|
||||
TYPE_CLEANUP_USER,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
|
||||
@Type public final int type;
|
||||
public final int userHandle;
|
||||
|
||||
public SystemServiceUserEvent(@Type int type, int userHandle) {
|
||||
this.type = type;
|
||||
this.userHandle = userHandle;
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
CheckHelpers.checkTypeInRange(type, TYPE_MAX);
|
||||
if (userHandle < 0) {
|
||||
throw new IllegalArgumentException("userHandle must be non-negative");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{type: %d, userHandle: %d}", type, userHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof SystemServiceUserEvent) {
|
||||
return equals((SystemServiceUserEvent) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(SystemServiceUserEvent other) {
|
||||
return type == other.type &&
|
||||
userHandle == other.userHandle;
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(type);
|
||||
out.writeInt(userHandle);
|
||||
}
|
||||
|
||||
private SystemServiceUserEvent(Parcel in) {
|
||||
this.type = in.readInt();
|
||||
this.userHandle = in.readInt();
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SystemServiceUserEvent> CREATOR
|
||||
= new Parcelable.Creator<SystemServiceUserEvent>() {
|
||||
public SystemServiceUserEvent createFromParcel(Parcel in) {
|
||||
return new SystemServiceUserEvent(in);
|
||||
}
|
||||
|
||||
public SystemServiceUserEvent[] newArray(int size) {
|
||||
return new SystemServiceUserEvent[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Result data accompanying a request for {@link com.google.android.startop.iorap.ITaskListener}
|
||||
* callbacks.<br /><br />
|
||||
*
|
||||
* Following {@link com.google.android.startop.iorap.IIorap} method invocation,
|
||||
* iorapd will issue in-order callbacks for that corresponding {@link RequestId}.<br /><br />
|
||||
*
|
||||
* State transitions are as follows: <br /><br />
|
||||
*
|
||||
* <pre>
|
||||
* ┌─────────────────────────────┐
|
||||
* │ ▼
|
||||
* ┌───────┐ ┌─────────┐ ╔═══════════╗
|
||||
* ──▶ │ BEGAN │ ──▶ │ ONGOING │ ──▶ ║ COMPLETED ║
|
||||
* └───────┘ └─────────┘ ╚═══════════╝
|
||||
* │ │
|
||||
* │ │
|
||||
* ▼ │
|
||||
* ╔═══════╗ │
|
||||
* ──▶ ║ ERROR ║ ◀─────┘
|
||||
* ╚═══════╝
|
||||
*
|
||||
* </pre> <!-- system/iorap/docs/binder/TaskResult.dot -->
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TaskResult implements Parcelable {
|
||||
|
||||
public static final int STATE_BEGAN = 0;
|
||||
public static final int STATE_ONGOING = 1;
|
||||
public static final int STATE_COMPLETED = 2;
|
||||
public static final int STATE_ERROR = 3;
|
||||
private static final int STATE_MAX = STATE_ERROR;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "STATE_" }, value = {
|
||||
STATE_BEGAN,
|
||||
STATE_ONGOING,
|
||||
STATE_COMPLETED,
|
||||
STATE_ERROR,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface State {}
|
||||
|
||||
@State public final int state;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{state: %d}", state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (other instanceof TaskResult) {
|
||||
return equals((TaskResult) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(TaskResult other) {
|
||||
return state == other.state;
|
||||
}
|
||||
|
||||
public TaskResult(@State int state) {
|
||||
this.state = state;
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
private void checkConstructorArguments() {
|
||||
CheckHelpers.checkStateInRange(state, STATE_MAX);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Binder boilerplate">
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(state);
|
||||
}
|
||||
|
||||
private TaskResult(Parcel in) {
|
||||
state = in.readInt();
|
||||
|
||||
checkConstructorArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TaskResult> CREATOR
|
||||
= new Parcelable.Creator<TaskResult>() {
|
||||
public TaskResult createFromParcel(Parcel in) {
|
||||
return new TaskResult(in);
|
||||
}
|
||||
|
||||
public TaskResult[] newArray(int size) {
|
||||
return new TaskResult[size];
|
||||
}
|
||||
};
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.google.android.startop.iorap
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.support.test.filters.SmallTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Basic unit tests to ensure that all of the [Parcelable]s in [com.google.android.startop.iorap]
|
||||
* have a valid-conforming interface implementation.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(Parameterized::class)
|
||||
class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) {
|
||||
companion object {
|
||||
private val initialRequestId = RequestId.nextValueForSequence()!!
|
||||
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters
|
||||
fun data() = listOf(
|
||||
InputData(
|
||||
newActivityInfo(),
|
||||
newActivityInfo(),
|
||||
ActivityInfo("some package", "some other activity")),
|
||||
InputData(
|
||||
ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()),
|
||||
ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()),
|
||||
ActivityHintEvent(ActivityHintEvent.TYPE_POST_COMPLETED,
|
||||
newActivityInfo())),
|
||||
InputData(
|
||||
AppIntentEvent.createDefaultIntentChanged(newActivityInfo(),
|
||||
newActivityInfoOther()),
|
||||
AppIntentEvent.createDefaultIntentChanged(newActivityInfo(),
|
||||
newActivityInfoOther()),
|
||||
AppIntentEvent.createDefaultIntentChanged(newActivityInfoOther(),
|
||||
newActivityInfo())),
|
||||
InputData(
|
||||
PackageEvent.createReplaced(newUri(), "some package"),
|
||||
PackageEvent.createReplaced(newUri(), "some package"),
|
||||
PackageEvent.createReplaced(newUri(), "some other package")
|
||||
),
|
||||
InputData(initialRequestId, cloneRequestId(initialRequestId),
|
||||
RequestId.nextValueForSequence()),
|
||||
InputData(
|
||||
SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE),
|
||||
SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE),
|
||||
SystemServiceEvent(SystemServiceEvent.TYPE_START)),
|
||||
InputData(
|
||||
SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345),
|
||||
SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345),
|
||||
SystemServiceUserEvent(SystemServiceUserEvent.TYPE_CLEANUP_USER, 12345)),
|
||||
InputData(
|
||||
TaskResult(TaskResult.STATE_COMPLETED),
|
||||
TaskResult(TaskResult.STATE_COMPLETED),
|
||||
TaskResult(TaskResult.STATE_ONGOING))
|
||||
)
|
||||
|
||||
private fun newActivityInfo() : ActivityInfo {
|
||||
return ActivityInfo("some package", "some activity")
|
||||
}
|
||||
|
||||
private fun newActivityInfoOther() : ActivityInfo {
|
||||
return ActivityInfo("some package 2", "some activity 2")
|
||||
}
|
||||
|
||||
private fun newUri() : Uri {
|
||||
return Uri.parse("https://www.google.com")
|
||||
}
|
||||
|
||||
private fun cloneRequestId(requestId: RequestId) : RequestId {
|
||||
val constructor = requestId::class.java.declaredConstructors[0]
|
||||
constructor.isAccessible = true
|
||||
return constructor.newInstance(requestId.requestId) as RequestId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for [Object.equals] implementation.
|
||||
*/
|
||||
@Test
|
||||
fun testEquality() {
|
||||
assertThat(inputData.valid).isEqualTo(inputData.valid)
|
||||
assertThat(inputData.valid).isEqualTo(inputData.validCopy)
|
||||
assertThat(inputData.valid).isNotEqualTo(inputData.validOther)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for [Parcelable] implementation.
|
||||
*/
|
||||
@Test
|
||||
fun testParcelRoundTrip() {
|
||||
// calling writeToParcel and then T::CREATOR.createFromParcel would return the same data.
|
||||
val assertParcels = { it : T, data : InputData<T> ->
|
||||
val parcel = Parcel.obtain()
|
||||
it.writeToParcel(parcel, 0)
|
||||
parcel.setDataPosition(0) // future reads will see all previous writes.
|
||||
assertThat(it).isEqualTo(data.createFromParcel(parcel))
|
||||
parcel.recycle()
|
||||
}
|
||||
|
||||
assertParcels(inputData.valid, inputData)
|
||||
assertParcels(inputData.validCopy, inputData)
|
||||
assertParcels(inputData.validOther, inputData)
|
||||
}
|
||||
|
||||
data class InputData<T : Parcelable>(val valid : T, val validCopy : T, val validOther : T) {
|
||||
val kls = valid.javaClass
|
||||
init {
|
||||
assertThat(valid).isNotSameAs(validCopy)
|
||||
// Don't use isInstanceOf because of phantom warnings in intellij about Class!
|
||||
assertThat(validCopy.javaClass).isEqualTo(valid.javaClass)
|
||||
assertThat(validOther.javaClass).isEqualTo(valid.javaClass)
|
||||
}
|
||||
|
||||
fun createFromParcel(parcel : Parcel) : T {
|
||||
val field = kls.getDeclaredField("CREATOR")
|
||||
val creator = field.get(null) as Parcelable.Creator<T>
|
||||
|
||||
return creator.createFromParcel(parcel)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user