Merge "idmap2: fix clang-tidy warnings [misc-*]"
diff --git a/api/current.txt b/api/current.txt
index d881857..3d57a42 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23379,12 +23379,13 @@
method public android.media.AudioPresentation.Builder setProgramId(int);
}
- public class AudioRecord implements android.media.AudioRouting {
+ public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting {
ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
method protected void finalize();
method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException;
+ method public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
method public int getAudioFormat();
method public int getAudioSessionId();
method public int getAudioSource();
@@ -23409,6 +23410,7 @@
method public int read(float[], int, int, int);
method public int read(java.nio.ByteBuffer, int);
method public int read(java.nio.ByteBuffer, int, int);
+ method public void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback);
method public void release();
method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
@@ -23420,6 +23422,7 @@
method public void startRecording() throws java.lang.IllegalStateException;
method public void startRecording(android.media.MediaSyncEvent) throws java.lang.IllegalStateException;
method public void stop() throws java.lang.IllegalStateException;
+ method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
field public static final int ERROR = -1; // 0xffffffff
field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
@@ -23474,6 +23477,12 @@
field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
}
+ public abstract interface AudioRecordingMonitor {
+ method public abstract android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
+ method public abstract void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback);
+ method public abstract void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
+ }
+
public abstract interface AudioRouting {
method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
@@ -25475,11 +25484,12 @@
field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
}
- public class MediaRecorder implements android.media.AudioRouting {
+ public class MediaRecorder implements android.media.AudioRecordingMonitor android.media.AudioRouting {
ctor public MediaRecorder();
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method protected void finalize();
method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException;
+ method public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
method public static final int getAudioSourceMax();
method public int getMaxAmplitude() throws java.lang.IllegalStateException;
method public android.os.PersistableBundle getMetrics();
@@ -25488,6 +25498,7 @@
method public android.view.Surface getSurface();
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
+ method public void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback);
method public void release();
method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
@@ -25523,6 +25534,7 @@
method public void setVideoSource(int) throws java.lang.IllegalStateException;
method public void start() throws java.lang.IllegalStateException;
method public void stop() throws java.lang.IllegalStateException;
+ method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
@@ -38682,22 +38694,23 @@
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String CURRENT = "current";
field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
- field public static final java.lang.String MCC = "mcc";
+ field public static final deprecated java.lang.String MCC = "mcc";
field public static final java.lang.String MMSC = "mmsc";
field public static final java.lang.String MMSPORT = "mmsport";
field public static final java.lang.String MMSPROXY = "mmsproxy";
- field public static final java.lang.String MNC = "mnc";
- field public static final java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
- field public static final java.lang.String MVNO_TYPE = "mvno_type";
+ field public static final deprecated java.lang.String MNC = "mnc";
+ field public static final deprecated java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
+ field public static final deprecated java.lang.String MVNO_TYPE = "mvno_type";
field public static final java.lang.String NAME = "name";
field public static final java.lang.String NETWORK_TYPE_BITMASK = "network_type_bitmask";
- field public static final java.lang.String NUMERIC = "numeric";
+ field public static final deprecated java.lang.String NUMERIC = "numeric";
field public static final java.lang.String PASSWORD = "password";
field public static final java.lang.String PORT = "port";
field public static final java.lang.String PROTOCOL = "protocol";
field public static final java.lang.String PROXY = "proxy";
field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
field public static final java.lang.String SERVER = "server";
+ field public static final android.net.Uri SIM_APN_URI;
field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
field public static final java.lang.String TYPE = "type";
field public static final java.lang.String USER = "user";
diff --git a/api/system-current.txt b/api/system-current.txt
index 0a42d25..3aa7cc7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2953,7 +2953,7 @@
field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff
}
- public class AudioRecord implements android.media.AudioRouting {
+ public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting {
ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
}
@@ -6481,12 +6481,17 @@
method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
method public int getOtaStatus();
field public static final java.lang.String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+ field public static final java.lang.String ACTION_PROFILE_SELECTION = "android.telephony.euicc.action.PROFILE_SELECTION";
field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+ field public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; // 0x2
+ field public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; // 0x1
+ field public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; // 0x3
field public static final int EUICC_OTA_FAILED = 2; // 0x2
field public static final int EUICC_OTA_IN_PROGRESS = 1; // 0x1
field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4
field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5
field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3
+ field public static final java.lang.String EXTRA_ACTIVATION_TYPE = "android.telephony.euicc.extra.ACTIVATION_TYPE";
field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
field public static final java.lang.String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
}
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index d7922bc..fe7099b 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -12,14 +12,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library {
- name: "libidmap2",
- host_supported: true,
+cc_defaults {
+ name: "idmap2_defaults",
tidy: true,
+ tidy_checks: [
+ "android-*",
+ "misc-*",
+ "modernize-*",
+ "readability-*",
+ ],
tidy_flags: [
"-system-headers",
-// b/120024673 "-warnings-as-errors=*",
],
+}
+
+cc_library {
+ name: "libidmap2",
+ defaults: [
+ "idmap2_defaults",
+ ],
+ host_supported: true,
srcs: [
"libidmap2/BinaryStreamVisitor.cpp",
"libidmap2/CommandLineOptions.cpp",
@@ -60,12 +72,13 @@
cc_test {
name: "idmap2_tests",
- host_supported: true,
- tidy: true,
- tidy_flags: [
- "-system-headers",
-// b/120024673 "-warnings-as-errors=*",
+ defaults: [
+ "idmap2_defaults",
],
+ tidy_checks: [
+ "-readability-magic-numbers",
+ ],
+ host_supported: true,
srcs: [
"tests/BinaryStreamVisitorTests.cpp",
"tests/CommandLineOptionsTests.cpp",
@@ -114,12 +127,10 @@
cc_binary {
name: "idmap2",
- host_supported: true,
- tidy: true,
- tidy_flags: [
- "-system-headers",
-// b/120024673 "-warnings-as-errors=*",
+ defaults: [
+ "idmap2_defaults",
],
+ host_supported: true,
srcs: [
"idmap2/Create.cpp",
"idmap2/Dump.cpp",
@@ -156,19 +167,11 @@
cc_binary {
name: "idmap2d",
+ defaults: [
+ "idmap2_defaults",
+ ],
host_supported: false,
- tidy: true,
- tidy_checks: [
- // remove google-default-arguments or clang-tidy will complain about
- // the auto-generated file IIdmap2.cpp
- "-google-default-arguments",
- ],
- tidy_flags: [
- "-system-headers",
-// b/120024673 "-warnings-as-errors=*",
- ],
srcs: [
- ":idmap2_aidl",
"idmap2d/Idmap2Service.cpp",
"idmap2d/Main.cpp",
],
@@ -181,9 +184,30 @@
"libutils",
"libziparchive",
],
+ static_libs: [
+ "libidmap2daidl",
+ ],
init_rc: ["idmap2d/idmap2d.rc"],
}
+cc_library_static {
+ name: "libidmap2daidl",
+ defaults: [
+ "idmap2_defaults",
+ ],
+ tidy: false,
+ host_supported: false,
+ srcs: [
+ ":idmap2_aidl",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ aidl: {
+ export_aidl_headers: true,
+ },
+}
+
filegroup {
name: "idmap2_aidl",
srcs: [
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index 5d9ea77..5e71251 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -32,7 +32,9 @@
typedef std::map<std::string, std::function<int(const std::vector<std::string>&, std::ostream&)>>
NameToFunctionMap;
-static void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
+namespace {
+
+void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
out << "usage: idmap2 [";
for (auto iter = commands.cbegin(); iter != commands.cend(); iter++) {
if (iter != commands.cbegin()) {
@@ -43,6 +45,8 @@
out << "]" << std::endl;
}
+} // namespace
+
int main(int argc, char** argv) {
const NameToFunctionMap commands = {
{"create", Create}, {"dump", Dump}, {"lookup", Lookup}, {"scan", Scan}, {"verify", Verify},
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 49bb7d8..89aa6d8 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -39,6 +39,8 @@
namespace android {
namespace idmap2 {
+namespace {
+
#define EXTRACT_TYPE(resid) ((0x00ff0000 & (resid)) >> 16)
#define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
@@ -62,7 +64,7 @@
std::map<TypeId, std::set<std::pair<ResourceId, ResourceId>>> map_;
};
-static bool WARN_UNUSED Read16(std::istream& stream, uint16_t* out) {
+bool WARN_UNUSED Read16(std::istream& stream, uint16_t* out) {
uint16_t value;
if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint16_t))) {
*out = dtohl(value);
@@ -71,7 +73,7 @@
return false;
}
-static bool WARN_UNUSED Read32(std::istream& stream, uint32_t* out) {
+bool WARN_UNUSED Read32(std::istream& stream, uint32_t* out) {
uint32_t value;
if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
*out = dtohl(value);
@@ -81,7 +83,7 @@
}
// a string is encoded as a kIdmapStringLength char array; the array is always null-terminated
-static bool WARN_UNUSED ReadString(std::istream& stream, char out[kIdmapStringLength]) {
+bool WARN_UNUSED ReadString(std::istream& stream, char out[kIdmapStringLength]) {
char buf[kIdmapStringLength];
memset(buf, 0, sizeof(buf));
if (!stream.read(buf, sizeof(buf))) {
@@ -94,7 +96,7 @@
return true;
}
-static ResourceId NameToResid(const AssetManager2& am, const std::string& name) {
+ResourceId NameToResid(const AssetManager2& am, const std::string& name) {
return am.GetResourceId(name);
}
@@ -107,7 +109,7 @@
// relying on a hard-coded index. This however requires storing the package name in the idmap
// header, which in turn requires incrementing the idmap version. Because the initial version of
// idmap2 is compatible with idmap, this will have to wait for now.
-static const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
+const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc.GetPackages();
if (packages.empty()) {
return nullptr;
@@ -116,6 +118,8 @@
return loaded_arsc.GetPackageById(id);
}
+} // namespace
+
std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 5c4e857..cfe5361 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -51,8 +51,10 @@
class Idmap2BinaryTests : public Idmap2Tests {};
-static void AssertIdmap(const Idmap& idmap, const std::string& target_apk_path,
- const std::string& overlay_apk_path) {
+namespace {
+
+void AssertIdmap(const Idmap& idmap, const std::string& target_apk_path,
+ const std::string& overlay_apk_path) {
// check that the idmap file looks reasonable (IdmapTests is responsible for
// more in-depth verification)
ASSERT_EQ(idmap.GetHeader()->GetMagic(), kIdmapMagic);
@@ -67,6 +69,8 @@
ASSERT_NO_FATAL_FAILURE(AssertIdmap(idmap_ref, target_apk_path, overlay_apk_path)); \
} while (0)
+} // namespace
+
TEST_F(Idmap2BinaryTests, Create) {
// clang-format off
auto result = ExecuteBinary({"idmap2",
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index c850a4e..dd0242a 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -19,7 +19,7 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
-import android.annotation.Nullable;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -179,13 +179,13 @@
* @param isExpanded whether the notification is expanded.
*/
public void onNotificationExpansionChanged(
- String key, boolean isUserAction, boolean isExpanded) {}
+ @NonNull String key, boolean isUserAction, boolean isExpanded) {}
/**
* Implement this to know when a direct reply is sent from a notification.
* @param key the notification key
*/
- public void onNotificationDirectReply(String key) {}
+ public void onNotificationDirectReply(@NonNull String key) {}
/**
* Implement this to know when a suggested reply is sent.
@@ -193,7 +193,9 @@
* @param reply the reply that is just sent
* @param source the source that provided the reply, e.g. SOURCE_FROM_APP
*/
- public void onSuggestedReplySent(String key, CharSequence reply, @Source int source) {}
+ public void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply,
+ @Source int source) {
+ }
/**
* Implement this to know when an action is clicked.
@@ -201,7 +203,8 @@
* @param action the action that is just clicked
* @param source the source that provided the action, e.g. SOURCE_FROM_APP
*/
- public void onActionClicked(String key, @Nullable Notification.Action action, int source) {
+ public void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+ @Source int source) {
}
/**
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index b41096c..77cb4cd 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -17,6 +17,7 @@
package android.view.textclassifier;
import android.app.Person;
+import android.content.Context;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -28,7 +29,10 @@
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -84,6 +88,29 @@
new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]);
}
+ /**
+ * Returns the result id for logging.
+ */
+ public static String createResultId(
+ Context context,
+ List<ConversationActions.Message> messages,
+ int modelVersion,
+ List<Locale> modelLocales) {
+ final StringJoiner localesJoiner = new StringJoiner(",");
+ for (Locale locale : modelLocales) {
+ localesJoiner.add(locale.toLanguageTag());
+ }
+ final String modelName = String.format(
+ Locale.US, "%s_v%d", localesJoiner.toString(), modelVersion);
+ final int hash = Objects.hash(
+ messages.stream()
+ .map(ConversationActions.Message::getText)
+ .collect(Collectors.toList()),
+ context.getPackageName());
+ return SelectionSessionLogger.SignatureParser.createSignature(
+ SelectionSessionLogger.CLASSIFIER_ID, modelName, hash);
+ }
+
private static final class PersonEncoder {
private final Map<Person, Integer> mMapping = new ArrayMap<>();
private int mNextUserId = FIRST_NON_LOCAL_USER;
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index 3bb9ee8..f2fea02 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -27,6 +27,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
/**
* A text classifier event.
@@ -498,4 +499,25 @@
}
// TODO: Add build(boolean validate).
}
+
+ @Override
+ public String toString() {
+ StringBuilder out = new StringBuilder(128);
+ out.append("TextClassifierEvent{");
+ out.append("mEventCategory=").append(mEventCategory);
+ out.append(", mEventType=").append(mEventType);
+ out.append(", mEventContext=").append(mEventContext);
+ out.append(", mResultId=").append(mResultId);
+ out.append(", mEventIndex=").append(mEventIndex);
+ out.append(", mEventTime=").append(mEventTime);
+ out.append(", mExtras=").append(mExtras);
+ out.append(", mRelativeWordStartIndex=").append(mRelativeWordStartIndex);
+ out.append(", mRelativeWordEndIndex=").append(mRelativeWordEndIndex);
+ out.append(", mRelativeSuggestedWordStartIndex=").append(mRelativeSuggestedWordStartIndex);
+ out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex);
+ out.append(", mActionIndices=").append(Arrays.toString(mActionIndices));
+ out.append(", mLanguage=").append(mLanguage);
+ out.append("}");
+ return out.toString();
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 9b0f9c6..fcd06c3 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -80,6 +80,8 @@
private static final String LOG_TAG = DEFAULT_LOG_TAG;
+ private static final boolean DEBUG = false;
+
private static final File FACTORY_MODEL_DIR = new File("/etc/textclassifier/");
// Annotator
private static final String ANNOTATOR_FACTORY_MODEL_FILENAME_REGEX =
@@ -109,6 +111,8 @@
@GuardedBy("mLock") // Do not access outside this lock.
private LangIdModel mLangIdImpl;
@GuardedBy("mLock") // Do not access outside this lock.
+ private ModelFileManager.ModelFile mActionModelInUse;
+ @GuardedBy("mLock") // Do not access outside this lock.
private ActionsSuggestionsModel mActionsImpl;
private final Object mLoggerLock = new Object();
@@ -342,8 +346,10 @@
}
@Override
- public void onTextClassifierEvent(@NonNull TextClassifierEvent event) {
- // TODO: Implement.
+ public void onTextClassifierEvent(TextClassifierEvent event) {
+ if (DEBUG) {
+ Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]");
+ }
}
/** @inheritDoc */
@@ -408,7 +414,12 @@
.setConfidenceScore(nativeSuggestion.getScore())
.build());
}
- return new ConversationActions(conversationActions, /*id*/ null);
+ String resultId = ActionsSuggestionsHelper.createResultId(
+ mContext,
+ request.getConversation(),
+ mActionModelInUse.getVersion(),
+ mActionModelInUse.getSupportedLocales());
+ return new ConversationActions(conversationActions, resultId);
} catch (Throwable t) {
// Avoid throwing from this method. Log the error.
Log.e(LOG_TAG, "Error suggesting conversation actions.", t);
@@ -517,6 +528,7 @@
try {
if (pfd != null) {
mActionsImpl = new ActionsSuggestionsModel(pfd.getFd());
+ mActionModelInUse = bestModel;
}
} finally {
maybeCloseAndLogError(pfd);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 12ca78a..eb7338a 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -45,7 +45,7 @@
class BitmapWrapper {
public:
- BitmapWrapper(Bitmap* bitmap)
+ explicit BitmapWrapper(Bitmap* bitmap)
: mBitmap(bitmap) { }
void freePixels() {
diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h
index 9f6462e..b36b4e6 100644
--- a/core/jni/android/graphics/FontUtils.h
+++ b/core/jni/android/graphics/FontUtils.h
@@ -29,7 +29,7 @@
namespace android {
struct FontFamilyWrapper {
- FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {}
+ explicit FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {}
std::shared_ptr<minikin::FontFamily> family;
};
diff --git a/core/jni/android/graphics/GIFMovie.cpp b/core/jni/android/graphics/GIFMovie.cpp
index dd99b37..f84a4bd 100644
--- a/core/jni/android/graphics/GIFMovie.cpp
+++ b/core/jni/android/graphics/GIFMovie.cpp
@@ -21,7 +21,7 @@
class GIFMovie : public Movie {
public:
- GIFMovie(SkStream* stream);
+ explicit GIFMovie(SkStream* stream);
virtual ~GIFMovie();
protected:
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 33b2689..bd87dcc 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -152,7 +152,7 @@
const bool is_sock;
private:
- FileDescriptorInfo(int fd);
+ explicit FileDescriptorInfo(int fd);
FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
int fd_flags, int fs_flags, off_t offset);
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index a3570d7..09022a2 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -86,7 +86,7 @@
bool ReopenOrDetach(std::string* error_msg);
private:
- FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
+ explicit FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
bool RestatInternal(std::set<int>& open_fds, std::string* error_msg);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8b6f33f..299798b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4336,7 +4336,7 @@
<permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
android:protectionLevel="signature|appop" />
- <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#P} that want to use
+ <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#Q} that want to use
{@link android.app.Notification.Builder#setFullScreenIntent notification full screen
intents}. -->
<permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c216425..58b57e5 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -33,6 +33,10 @@
<permission name="android.permission.CRYPT_KEEPER"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.carrierconfig">
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ </privapp-permissions>
+
<privapp-permissions package="com.android.cellbroadcastreceiver">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 6e6ed30..9361c7c 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -55,6 +55,7 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -315,13 +316,14 @@
}
/**
- * List uids of all keys that are auth bound to the current user.
+ * List uids of all keys that are auth bound to the current user.
* Only system is allowed to call this method.
*/
@UnsupportedAppUsage
public int[] listUidsOfAuthBoundKeys() {
- final int MAX_RESULT_SIZE = 100;
- int[] uidsOut = new int[MAX_RESULT_SIZE];
+ // uids are returned as a list of strings because list of integers
+ // as an output parameter is not supported by aidl-cpp.
+ List<String> uidsOut = new ArrayList<>();
try {
int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
if (rc != NO_ERROR) {
@@ -335,8 +337,8 @@
Log.w(TAG, "KeyStore exception", e);
return null;
}
- // Remove any 0 entries
- return Arrays.stream(uidsOut).filter(x -> x > 0).toArray();
+ // Turn list of strings into an array of uid integers.
+ return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
}
public String[] list(String prefix) {
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4b2353c..33f81f1 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -16,8 +16,10 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
@@ -43,6 +45,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* The AudioRecord class manages the audio resources for Java applications
@@ -58,7 +61,7 @@
* been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
* the total recording buffer size.
*/
-public class AudioRecord implements AudioRouting
+public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient
{
//---------------------------------------------------------
// Constants
@@ -1654,6 +1657,56 @@
return activeMicrophones;
}
+
+ //--------------------------------------------------------------------------
+ // Implementation of AudioRecordingMonitor interface
+ //--------------------
+
+ AudioRecordingMonitorImpl mRecordingInfoImpl =
+ new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this);
+
+ /**
+ * Register a callback to be notified of audio capture changes via a
+ * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path
+ * configuration changes (pre-processing, format, sampling rate...) or capture is
+ * silenced/unsilenced by the system.
+ * @param executor {@link Executor} to handle the callbacks.
+ * @param cb non-null callback to register
+ */
+ public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull AudioManager.AudioRecordingCallback cb) {
+ mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb);
+ }
+
+ /**
+ * Unregister an audio recording callback previously registered with
+ * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}.
+ * @param cb non-null callback to unregister
+ */
+ public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) {
+ mRecordingInfoImpl.unregisterAudioRecordingCallback(cb);
+ }
+
+ /**
+ * Returns the current active audio recording for this audio recorder.
+ * @return a valid {@link AudioRecordingConfiguration} if this recorder is active
+ * or null otherwise.
+ * @see AudioRecordingConfiguration
+ */
+ public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() {
+ return mRecordingInfoImpl.getActiveRecordingConfiguration();
+ }
+
+ //---------------------------------------------------------
+ // Implementation of AudioRecordingMonitorClient interface
+ //--------------------
+ /**
+ * @hide
+ */
+ public int getPortId() {
+ return native_getPortId();
+ }
+
//---------------------------------------------------------
// Interface definitions
//--------------------
diff --git a/media/java/android/media/AudioRecordingMonitor.java b/media/java/android/media/AudioRecordingMonitor.java
new file mode 100644
index 0000000..e2605d0
--- /dev/null
+++ b/media/java/android/media/AudioRecordingMonitor.java
@@ -0,0 +1,56 @@
+/*
+ * 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.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.concurrent.Executor;
+
+/**
+ * AudioRecordingMonitor defines an interface implemented by {@link AudioRecord} and
+ * {@link MediaRecorder} allowing applications to install a callback and be notified of changes
+ * in the capture path while recoding is active.
+ */
+public interface AudioRecordingMonitor {
+ /**
+ * Register a callback to be notified of audio capture changes via a
+ * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path
+ * configuration changes (pre-processing, format, sampling rate...) or capture is
+ * silenced/unsilenced by the system.
+ * @param executor {@link Executor} to handle the callbacks.
+ * @param cb non-null callback to register
+ */
+ void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull AudioManager.AudioRecordingCallback cb);
+
+ /**
+ * Unregister an audio recording callback previously registered with
+ * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}.
+ * @param cb non-null callback to unregister
+ */
+ void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb);
+
+ /**
+ * Returns the current active audio recording for this audio recorder.
+ * @return a valid {@link AudioRecordingConfiguration} if this recorder is active
+ * or null otherwise.
+ * @see AudioRecordingConfiguration
+ */
+ @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration();
+}
diff --git a/media/java/android/media/AudioRecordingMonitorClient.java b/media/java/android/media/AudioRecordingMonitorClient.java
new file mode 100644
index 0000000..7578d9b
--- /dev/null
+++ b/media/java/android/media/AudioRecordingMonitorClient.java
@@ -0,0 +1,28 @@
+/*
+ * 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.media;
+
+/**
+ * Interface implemented by classes using { @link AudioRecordingMonitor} interface.
+ * @hide
+ */
+public interface AudioRecordingMonitorClient {
+ /**
+ * @return the unique port ID allocated by audio framework to this recorder
+ */
+ int getPortId();
+}
diff --git a/media/java/android/media/AudioRecordingMonitorImpl.java b/media/java/android/media/AudioRecordingMonitorImpl.java
new file mode 100644
index 0000000..c2cd4bc
--- /dev/null
+++ b/media/java/android/media/AudioRecordingMonitorImpl.java
@@ -0,0 +1,250 @@
+/*
+ * 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.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Implementation of AudioRecordingMonitor interface.
+ * @hide
+ */
+public class AudioRecordingMonitorImpl implements AudioRecordingMonitor {
+
+ private static final String TAG = "android.media.AudioRecordingMonitor";
+
+ private static IAudioService sService; //lazy initialization, use getService()
+
+ private final AudioRecordingMonitorClient mClient;
+
+ AudioRecordingMonitorImpl(@NonNull AudioRecordingMonitorClient client) {
+ mClient = client;
+ }
+
+ /**
+ * Register a callback to be notified of audio capture changes via a
+ * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path
+ * configuration changes (pre-processing, format, sampling rate...) or capture is
+ * silenced/unsilenced by the system.
+ * @param executor {@link Executor} to handle the callbacks.
+ * @param cb non-null callback to register
+ */
+ public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull AudioManager.AudioRecordingCallback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null AudioRecordingCallback");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Illegal null Executor");
+ }
+ synchronized (mRecordCallbackLock) {
+ // check if eventCallback already in list
+ for (AudioRecordingCallbackInfo arci : mRecordCallbackList) {
+ if (arci.mCb == cb) {
+ throw new IllegalArgumentException(
+ "AudioRecordingCallback already registered");
+ }
+ }
+ beginRecordingCallbackHandling();
+ mRecordCallbackList.add(new AudioRecordingCallbackInfo(executor, cb));
+ }
+ }
+
+ /**
+ * Unregister an audio recording callback previously registered with
+ * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}.
+ * @param cb non-null callback to unregister
+ */
+ public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
+ }
+
+ synchronized (mRecordCallbackLock) {
+ for (AudioRecordingCallbackInfo arci : mRecordCallbackList) {
+ if (arci.mCb == cb) {
+ // ok to remove while iterating over list as we exit iteration
+ mRecordCallbackList.remove(arci);
+ if (mRecordCallbackList.size() == 0) {
+ endRecordingCallbackHandling();
+ }
+ return;
+ }
+ }
+ throw new IllegalArgumentException("AudioRecordingCallback was not registered");
+ }
+ }
+
+ /**
+ * Returns the current active audio recording for this audio recorder.
+ * @return a valid {@link AudioRecordingConfiguration} if this recorder is active
+ * or null otherwise.
+ * @see AudioRecordingConfiguration
+ */
+ public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() {
+ final IAudioService service = getService();
+ try {
+ List<AudioRecordingConfiguration> configs = service.getActiveRecordingConfigurations();
+ return getMyConfig(configs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static class AudioRecordingCallbackInfo {
+ final AudioManager.AudioRecordingCallback mCb;
+ final Executor mExecutor;
+ AudioRecordingCallbackInfo(Executor e, AudioManager.AudioRecordingCallback cb) {
+ mExecutor = e;
+ mCb = cb;
+ }
+ }
+
+ private static final int MSG_RECORDING_CONFIG_CHANGE = 1;
+
+ private final Object mRecordCallbackLock = new Object();
+ @GuardedBy("mRecordCallbackLock")
+ @NonNull private LinkedList<AudioRecordingCallbackInfo> mRecordCallbackList =
+ new LinkedList<AudioRecordingCallbackInfo>();
+ @GuardedBy("mRecordCallbackLock")
+ private @Nullable HandlerThread mRecordingCallbackHandlerThread;
+ @GuardedBy("mRecordCallbackLock")
+ private @Nullable volatile Handler mRecordingCallbackHandler;
+
+ @GuardedBy("mRecordCallbackLock")
+ private final IRecordingConfigDispatcher mRecordingCallback =
+ new IRecordingConfigDispatcher.Stub() {
+ @Override
+ public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
+ AudioRecordingConfiguration config = getMyConfig(configs);
+ if (config != null) {
+ synchronized (mRecordCallbackLock) {
+ if (mRecordingCallbackHandler != null) {
+ final Message m = mRecordingCallbackHandler.obtainMessage(
+ MSG_RECORDING_CONFIG_CHANGE/*what*/, config /*obj*/);
+ mRecordingCallbackHandler.sendMessage(m);
+ }
+ }
+ }
+ }
+ };
+
+ @GuardedBy("mRecordCallbackLock")
+ private void beginRecordingCallbackHandling() {
+ if (mRecordingCallbackHandlerThread == null) {
+ mRecordingCallbackHandlerThread = new HandlerThread(TAG + ".RecordingCallback");
+ mRecordingCallbackHandlerThread.start();
+ final Looper looper = mRecordingCallbackHandlerThread.getLooper();
+ if (looper != null) {
+ mRecordingCallbackHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_RECORDING_CONFIG_CHANGE: {
+ if (msg.obj == null) {
+ return;
+ }
+ ArrayList<AudioRecordingConfiguration> configs =
+ new ArrayList<AudioRecordingConfiguration>();
+ configs.add((AudioRecordingConfiguration) msg.obj);
+
+ final LinkedList<AudioRecordingCallbackInfo> cbInfoList;
+ synchronized (mRecordCallbackLock) {
+ if (mRecordCallbackList.size() == 0) {
+ return;
+ }
+ cbInfoList = new LinkedList<AudioRecordingCallbackInfo>(
+ mRecordCallbackList);
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ for (AudioRecordingCallbackInfo cbi : cbInfoList) {
+ cbi.mExecutor.execute(() ->
+ cbi.mCb.onRecordingConfigChanged(configs));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } break;
+ default:
+ Log.e(TAG, "Unknown event " + msg.what);
+ break;
+ }
+ }
+ };
+ final IAudioService service = getService();
+ try {
+ service.registerRecordingCallback(mRecordingCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mRecordCallbackLock")
+ private void endRecordingCallbackHandling() {
+ if (mRecordingCallbackHandlerThread != null) {
+ final IAudioService service = getService();
+ try {
+ service.unregisterRecordingCallback(mRecordingCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mRecordingCallbackHandlerThread.quit();
+ mRecordingCallbackHandlerThread = null;
+ }
+ }
+
+ AudioRecordingConfiguration getMyConfig(List<AudioRecordingConfiguration> configs) {
+ int portId = mClient.getPortId();
+ for (AudioRecordingConfiguration config : configs) {
+ if (config.getClientPortId() == portId) {
+ return config;
+ }
+ }
+ return null;
+ }
+
+ private static IAudioService getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ sService = IAudioService.Stub.asInterface(b);
+ return sService;
+ }
+}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index a3702d6..34345b3 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -793,7 +793,7 @@
// throws IllegalArgumentException if dsd is null or underline PFD of dsd has been closed.
private void checkDataSourceDesc(DataSourceDesc dsd) {
- if (dsd != null) {
+ if (dsd == null) {
throw new IllegalArgumentException("dsd is expected to be non null");
}
if (dsd instanceof FileDataSourceDesc) {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 8ced021..1cdc291 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,7 +16,9 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -40,6 +42,8 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
+
/**
* Used to record audio and video. The recording control is based on a
@@ -83,7 +87,9 @@
* <a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a> developer guide.</p>
* </div>
*/
-public class MediaRecorder implements AudioRouting
+public class MediaRecorder implements AudioRouting,
+ AudioRecordingMonitor,
+ AudioRecordingMonitorClient
{
static {
System.loadLibrary("media_jni");
@@ -304,7 +310,7 @@
/**
* Audio source for preemptible, low-priority software hotword detection
- * It presents the same gain and pre processing tuning as {@link #VOICE_RECOGNITION}.
+ * It presents the same gain and pre-processing tuning as {@link #VOICE_RECOGNITION}.
* <p>
* An application should use this audio source when it wishes to do
* always-on software hotword detection, while gracefully giving in to any other application
@@ -1471,6 +1477,57 @@
private native final int native_getActiveMicrophones(
ArrayList<MicrophoneInfo> activeMicrophones);
+ //--------------------------------------------------------------------------
+ // Implementation of AudioRecordingMonitor interface
+ //--------------------
+
+ AudioRecordingMonitorImpl mRecordingInfoImpl =
+ new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this);
+
+ /**
+ * Register a callback to be notified of audio capture changes via a
+ * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path
+ * configuration changes (pre-processing, format, sampling rate...) or capture is
+ * silenced/unsilenced by the system.
+ * @param executor {@link Executor} to handle the callbacks.
+ * @param cb non-null callback to register
+ */
+ public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull AudioManager.AudioRecordingCallback cb) {
+ mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb);
+ }
+
+ /**
+ * Unregister an audio recording callback previously registered with
+ * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}.
+ * @param cb non-null callback to unregister
+ */
+ public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) {
+ mRecordingInfoImpl.unregisterAudioRecordingCallback(cb);
+ }
+
+ /**
+ * Returns the current active audio recording for this audio recorder.
+ * @return a valid {@link AudioRecordingConfiguration} if this recorder is active
+ * or null otherwise.
+ * @see AudioRecordingConfiguration
+ */
+ public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() {
+ return mRecordingInfoImpl.getActiveRecordingConfiguration();
+ }
+
+ //---------------------------------------------------------
+ // Implementation of AudioRecordingMonitorClient interface
+ //--------------------
+ /**
+ * @hide
+ */
+ public int getPortId() {
+ return native_getPortId();
+ }
+
+ private native int native_getPortId();
+
/**
* Called from native code when an interesting event happens. This method
* just uses the EventHandler system to post the event back to the main app thread.
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index b3a8b21..ca30f32 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -763,6 +763,20 @@
}
return jStatus;
}
+
+static jint android_media_MediaRecord_getPortId(JNIEnv *env, jobject thiz) {
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ if (mr == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return (jint)AUDIO_PORT_HANDLE_NONE;
+ }
+
+ audio_port_handle_t portId;
+ process_media_recorder_call(env, mr->getPortId(&portId),
+ "java/lang/RuntimeException", "getPortId failed.");
+ return (jint)portId;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -801,6 +815,7 @@
{"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaRecorder_enableDeviceCallback},
{"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones},
+ {"native_getPortId", "()I", (void *)android_media_MediaRecord_getPortId},
};
// This function only registers the native methods, and is called from
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 0be71e6..42885e8 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -25,7 +25,7 @@
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 54087d1..af52c00 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -117,7 +117,7 @@
mPackageManager = ActivityThread.getPackageManager();
mSettings = mSettingsFactory.createAndRegister(mHandler,
getApplicationContext().getContentResolver(), getUserId(), this::updateThresholds);
- mSmartActionsHelper = new SmartActionsHelper();
+ mSmartActionsHelper = new SmartActionsHelper(getContext(), mSettings);
mNotificationCategorizer = new NotificationCategorizer();
mAgingHelper = new AgingHelper(getContext(),
mNotificationCategorizer,
@@ -215,10 +215,8 @@
return null;
}
NotificationEntry entry = new NotificationEntry(mPackageManager, sbn, channel);
- ArrayList<Notification.Action> actions =
- mSmartActionsHelper.suggestActions(this, entry, mSettings);
- ArrayList<CharSequence> replies =
- mSmartActionsHelper.suggestReplies(this, entry, mSettings);
+ ArrayList<Notification.Action> actions = mSmartActionsHelper.suggestActions(entry);
+ ArrayList<CharSequence> replies = mSmartActionsHelper.suggestReplies(entry);
return createEnqueuedNotificationAdjustment(entry, actions, replies);
}
@@ -343,6 +341,7 @@
if (entry != null) {
entry.setSeen();
mAgingHelper.onNotificationSeen(entry);
+ mSmartActionsHelper.onNotificationSeen(entry);
}
}
} catch (Throwable e) {
@@ -351,34 +350,46 @@
}
@Override
- public void onNotificationExpansionChanged(String key, boolean isUserAction,
+ public void onNotificationExpansionChanged(@NonNull String key, boolean isUserAction,
boolean isExpanded) {
if (DEBUG) {
- Log.i(TAG,
- "onNotificationExpansionChanged " + key + ", isUserAction =" + isUserAction
- + ", isExpanded = isExpanded");
+ Log.d(TAG, "onNotificationExpansionChanged() called with: key = [" + key
+ + "], isUserAction = [" + isUserAction + "], isExpanded = [" + isExpanded
+ + "]");
+ }
+ NotificationEntry entry = mLiveNotifications.get(key);
+
+ if (entry != null) {
+ entry.setExpanded(isExpanded);
+ mSmartActionsHelper.onNotificationExpansionChanged(entry, isUserAction, isExpanded);
}
}
@Override
- public void onNotificationDirectReply(String key) {
+ public void onNotificationDirectReply(@NonNull String key) {
if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key);
+ mSmartActionsHelper.onNotificationDirectReply(key);
}
@Override
- public void onSuggestedReplySent(String key, CharSequence reply, int source) {
+ public void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply,
+ @Source int source) {
if (DEBUG) {
Log.d(TAG, "onSuggestedReplySent() called with: key = [" + key + "], reply = [" + reply
+ "], source = [" + source + "]");
}
+ mSmartActionsHelper.onSuggestedReplySent(key, reply, source);
}
@Override
- public void onActionClicked(String key, Notification.Action action, int source) {
+ public void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+ @Source int source) {
if (DEBUG) {
- Log.d(TAG, "onActionClicked() called with: key = [" + key + "], action = [" + action.title
- + "], source = [" + source + "]");
+ Log.d(TAG,
+ "onActionClicked() called with: key = [" + key + "], action = [" + action.title
+ + "], source = [" + source + "]");
}
+ mSmartActionsHelper.onActionClicked(key, action, source);
}
@Override
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
index 6f437bd5..71fd9ce 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
@@ -52,6 +52,8 @@
private NotificationChannel mChannel;
private int mImportance;
private boolean mSeen;
+ private boolean mExpanded;
+ private boolean mIsShowActionEventLogged;
public NotificationEntry(IPackageManager packageManager, StatusBarNotification sbn,
NotificationChannel channel) {
@@ -216,10 +218,26 @@
mSeen = true;
}
+ public void setExpanded(boolean expanded) {
+ mExpanded = expanded;
+ }
+
+ public void setShowActionEventLogged() {
+ mIsShowActionEventLogged = true;
+ }
+
public boolean hasSeen() {
return mSeen;
}
+ public boolean isExpanded() {
+ return mExpanded;
+ }
+
+ public boolean isShowActionEventLogged() {
+ return mIsShowActionEventLogged;
+ }
+
public StatusBarNotification getSbn() {
return mSbn;
}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 38df9b0..b041842 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -24,12 +24,16 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
+import android.service.notification.NotificationAssistantService;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.LruCache;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextClassifierEvent;
import android.view.textclassifier.TextLinks;
import java.time.Instant;
@@ -47,6 +51,7 @@
private static final ArrayList<Notification.Action> EMPTY_ACTION_LIST = new ArrayList<>();
private static final ArrayList<CharSequence> EMPTY_REPLY_LIST = new ArrayList<>();
+ private static final String KEY_ACTION_TYPE = "action_type";
// If a notification has any of these flags set, it's inelgibile for actions being added.
private static final int FLAG_MASK_INELGIBILE_FOR_ACTIONS =
Notification.FLAG_ONGOING_EVENT
@@ -59,6 +64,7 @@
private static final int MAX_SUGGESTED_REPLIES = 3;
// TODO: Make this configurable.
private static final int MAX_MESSAGES_TO_EXTRACT = 5;
+ private static final int MAX_RESULT_ID_TO_CACHE = 20;
private static final ConversationActions.TypeConfig TYPE_CONFIG =
new ConversationActions.TypeConfig.Builder().setIncludedTypes(
@@ -68,26 +74,36 @@
private static final List<String> HINTS =
Collections.singletonList(ConversationActions.HINT_FOR_NOTIFICATION);
- SmartActionsHelper() {
+ private Context mContext;
+ @Nullable
+ private TextClassifier mTextClassifier;
+ @NonNull
+ private AssistantSettings mSettings;
+ private LruCache<String, String> mNotificationKeyToResultIdCache =
+ new LruCache<>(MAX_RESULT_ID_TO_CACHE);
+
+ SmartActionsHelper(Context context, AssistantSettings settings) {
+ mContext = context;
+ TextClassificationManager textClassificationManager =
+ mContext.getSystemService(TextClassificationManager.class);
+ if (textClassificationManager != null) {
+ mTextClassifier = textClassificationManager.getTextClassifier();
+ }
+ mSettings = settings;
}
/**
* Adds action adjustments based on the notification contents.
*/
@NonNull
- ArrayList<Notification.Action> suggestActions(@Nullable Context context,
- @NonNull NotificationEntry entry, @NonNull AssistantSettings settings) {
- if (!settings.mGenerateActions) {
+ ArrayList<Notification.Action> suggestActions(@NonNull NotificationEntry entry) {
+ if (!mSettings.mGenerateActions) {
return EMPTY_ACTION_LIST;
}
if (!isEligibleForActionAdjustment(entry)) {
return EMPTY_ACTION_LIST;
}
- if (context == null) {
- return EMPTY_ACTION_LIST;
- }
- TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class);
- if (tcm == null) {
+ if (mTextClassifier == null) {
return EMPTY_ACTION_LIST;
}
List<ConversationActions.Message> messages = extractMessages(entry.getNotification());
@@ -96,22 +112,17 @@
}
// TODO: Move to TextClassifier.suggestConversationActions once it is ready.
return suggestActionsFromText(
- tcm, messages.get(messages.size() - 1).getText(), MAX_SMART_ACTIONS);
+ messages.get(messages.size() - 1).getText(), MAX_SMART_ACTIONS);
}
- ArrayList<CharSequence> suggestReplies(@Nullable Context context,
- @NonNull NotificationEntry entry, @NonNull AssistantSettings settings) {
- if (!settings.mGenerateReplies) {
+ ArrayList<CharSequence> suggestReplies(@NonNull NotificationEntry entry) {
+ if (!mSettings.mGenerateReplies) {
return EMPTY_REPLY_LIST;
}
if (!isEligibleForReplyAdjustment(entry)) {
return EMPTY_REPLY_LIST;
}
- if (context == null) {
- return EMPTY_REPLY_LIST;
- }
- TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class);
- if (tcm == null) {
+ if (mTextClassifier == null) {
return EMPTY_REPLY_LIST;
}
List<ConversationActions.Message> messages = extractMessages(entry.getNotification());
@@ -125,14 +136,122 @@
.setTypeConfig(TYPE_CONFIG)
.build();
- TextClassifier textClassifier = tcm.getTextClassifier();
+ ConversationActions conversationActionsResult =
+ mTextClassifier.suggestConversationActions(request);
List<ConversationActions.ConversationAction> conversationActions =
- textClassifier.suggestConversationActions(request).getConversationActions();
-
- return conversationActions.stream()
+ conversationActionsResult.getConversationActions();
+ ArrayList<CharSequence> replies = conversationActions.stream()
.map(conversationAction -> conversationAction.getTextReply())
.filter(textReply -> !TextUtils.isEmpty(textReply))
.collect(Collectors.toCollection(ArrayList::new));
+
+ String resultId = conversationActionsResult.getId();
+ if (resultId != null && !replies.isEmpty()) {
+ mNotificationKeyToResultIdCache.put(entry.getSbn().getKey(), resultId);
+ }
+ return replies;
+ }
+
+ void onNotificationSeen(@NonNull NotificationEntry entry) {
+ if (entry.isExpanded()) {
+ maybeSendActionShownEvent(entry);
+ }
+ }
+
+ void onNotificationExpansionChanged(@NonNull NotificationEntry entry, boolean isUserAction,
+ boolean isExpanded) {
+ // Notification can be expanded in the background, and thus the isUserAction check.
+ if (isUserAction && isExpanded) {
+ maybeSendActionShownEvent(entry);
+ }
+ }
+
+ void onNotificationDirectReply(@NonNull String key) {
+ if (mTextClassifier == null) {
+ return;
+ }
+ String resultId = mNotificationKeyToResultIdCache.get(key);
+ if (resultId == null) {
+ return;
+ }
+ TextClassifierEvent textClassifierEvent =
+ createTextClassifierEventBuilder(TextClassifierEvent.TYPE_MANUAL_REPLY, resultId)
+ .build();
+ mTextClassifier.onTextClassifierEvent(textClassifierEvent);
+ }
+
+ void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply,
+ @NotificationAssistantService.Source int source) {
+ if (mTextClassifier == null) {
+ return;
+ }
+ if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
+ return;
+ }
+ String resultId = mNotificationKeyToResultIdCache.get(key);
+ if (resultId == null) {
+ return;
+ }
+ TextClassifierEvent textClassifierEvent =
+ createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
+ .setEntityType(ConversationActions.TYPE_TEXT_REPLY)
+ .build();
+ mTextClassifier.onTextClassifierEvent(textClassifierEvent);
+ }
+
+ void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+ @NotificationAssistantService.Source int source) {
+ if (mTextClassifier == null) {
+ return;
+ }
+ if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
+ return;
+ }
+ String resultId = mNotificationKeyToResultIdCache.get(key);
+ if (resultId == null) {
+ return;
+ }
+ String actionType = action.getExtras().getString(KEY_ACTION_TYPE);
+ if (actionType == null) {
+ return;
+ }
+ TextClassifierEvent textClassifierEvent =
+ createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
+ .setEntityType(actionType)
+ .build();
+ mTextClassifier.onTextClassifierEvent(textClassifierEvent);
+ }
+
+ private TextClassifierEvent.Builder createTextClassifierEventBuilder(
+ int eventType, @NonNull String resultId) {
+ return new TextClassifierEvent.Builder(
+ TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType)
+ .setEventTime(System.currentTimeMillis())
+ .setEventContext(
+ new TextClassificationContext.Builder(
+ mContext.getPackageName(), TextClassifier.WIDGET_TYPE_NOTIFICATION)
+ .build())
+ .setResultId(resultId);
+ }
+
+ private void maybeSendActionShownEvent(@NonNull NotificationEntry entry) {
+ if (mTextClassifier == null) {
+ return;
+ }
+ String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
+ if (resultId == null) {
+ return;
+ }
+ // Only report if this is the first time the user sees these suggestions.
+ if (entry.isShowActionEventLogged()) {
+ return;
+ }
+ entry.setShowActionEventLogged();
+ TextClassifierEvent textClassifierEvent =
+ createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN, resultId)
+ .build();
+ // TODO: If possible, report which replies / actions are actually seen by user.
+ mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
/**
@@ -220,13 +339,10 @@
/** Returns a list of actions to act on entities in a given piece of text. */
@NonNull
private ArrayList<Notification.Action> suggestActionsFromText(
- @NonNull TextClassificationManager tcm, @Nullable CharSequence text,
- int maxSmartActions) {
+ @Nullable CharSequence text, int maxSmartActions) {
if (TextUtils.isEmpty(text)) {
return EMPTY_ACTION_LIST;
}
- TextClassifier textClassifier = tcm.getTextClassifier();
-
// We want to process only text visible to the user to avoid confusing suggestions, so we
// truncate the text to a reasonable length. This is particularly important for e.g.
// email apps that sometimes include the text for the entire thread.
@@ -239,7 +355,7 @@
Collections.singletonList(
TextClassifier.HINT_TEXT_IS_NOT_EDITABLE)))
.build();
- TextLinks links = textClassifier.generateLinks(textLinksRequest);
+ TextLinks links = mTextClassifier.generateLinks(textLinksRequest);
ArrayMap<String, Integer> entityTypeFrequency = getEntityTypeFrequency(links);
ArrayList<Notification.Action> actions = new ArrayList<>();
@@ -254,19 +370,26 @@
// Generate the actions, and add the most prominent ones to the action bar.
TextClassification classification =
- textClassifier.classifyText(
+ mTextClassifier.classifyText(
new TextClassification.Request.Builder(
text, link.getStart(), link.getEnd()).build());
+ if (classification.getEntityCount() == 0) {
+ continue;
+ }
int numOfActions = Math.min(
MAX_ACTIONS_PER_LINK, classification.getActions().size());
for (int i = 0; i < numOfActions; ++i) {
- RemoteAction action = classification.getActions().get(i);
- actions.add(
- new Notification.Action.Builder(
- action.getIcon(),
- action.getTitle(),
- action.getActionIntent())
- .build());
+ RemoteAction remoteAction = classification.getActions().get(i);
+ Notification.Action action = new Notification.Action.Builder(
+ remoteAction.getIcon(),
+ remoteAction.getTitle(),
+ remoteAction.getActionIntent())
+ .setSemanticAction(
+ Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION)
+ .addExtras(Bundle.forPair(KEY_ACTION_TYPE, classification.getEntity(0)))
+ .build();
+ actions.add(action);
+
// We have enough smart actions.
if (actions.size() >= maxSmartActions) {
return actions;
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
index 0352ebc..da382a0 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
@@ -28,12 +28,14 @@
import android.app.Person;
import android.content.Context;
import android.os.Process;
+import android.service.notification.NotificationAssistantService;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextClassifierEvent;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
@@ -44,12 +46,14 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -58,8 +62,14 @@
@RunWith(AndroidJUnit4.class)
public class SmartActionHelperTest {
+ private static final String NOTIFICATION_KEY = "key";
+ private static final String RESULT_ID = "id";
- private SmartActionsHelper mSmartActionsHelper = new SmartActionsHelper();
+ private static final ConversationActions.ConversationAction REPLY_ACTION =
+ new ConversationActions.ConversationAction.Builder(
+ ConversationActions.TYPE_TEXT_REPLY).setTextReply("Home").build();
+
+ private SmartActionsHelper mSmartActionsHelper;
private Context mContext;
@Mock private TextClassifier mTextClassifier;
@Mock private NotificationEntry mNotificationEntry;
@@ -75,7 +85,7 @@
mContext.getSystemService(TextClassificationManager.class)
.setTextClassifier(mTextClassifier);
when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
- .thenReturn(new ConversationActions(Collections.emptyList(), null));
+ .thenReturn(new ConversationActions(Arrays.asList(REPLY_ACTION), RESULT_ID));
when(mNotificationEntry.getSbn()).thenReturn(mStatusBarNotification);
// The notification is eligible to have smart suggestions.
@@ -83,18 +93,20 @@
when(mNotificationEntry.isMessaging()).thenReturn(true);
when(mStatusBarNotification.getPackageName()).thenReturn("random.app");
when(mStatusBarNotification.getUser()).thenReturn(Process.myUserHandle());
+ when(mStatusBarNotification.getKey()).thenReturn(NOTIFICATION_KEY);
mNotificationBuilder = new Notification.Builder(mContext, "channel");
mSettings = AssistantSettings.createForTesting(
null, null, Process.myUserHandle().getIdentifier(), null);
mSettings.mGenerateActions = true;
mSettings.mGenerateReplies = true;
+ mSmartActionsHelper = new SmartActionsHelper(mContext, mSettings);
}
@Test
public void testSuggestReplies_notMessagingApp() {
when(mNotificationEntry.isMessaging()).thenReturn(false);
ArrayList<CharSequence> textReplies =
- mSmartActionsHelper.suggestReplies(mContext, mNotificationEntry, mSettings);
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
assertThat(textReplies).isEmpty();
}
@@ -102,7 +114,7 @@
public void testSuggestReplies_noInlineReply() {
when(mNotificationEntry.hasInlineReply()).thenReturn(false);
ArrayList<CharSequence> textReplies =
- mSmartActionsHelper.suggestReplies(mContext, mNotificationEntry, mSettings);
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
assertThat(textReplies).isEmpty();
}
@@ -169,18 +181,128 @@
.build();
when(mNotificationEntry.getNotification()).thenReturn(notification);
- mSmartActionsHelper.suggestReplies(mContext, mNotificationEntry, mSettings);
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
verify(mTextClassifier, never())
.suggestConversationActions(any(ConversationActions.Request.class));
}
+ @Test
+ public void testOnSuggestedReplySent() {
+ final String message = "Where are you?";
+ Notification notification = mNotificationBuilder.setContentText(message).build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onSuggestedReplySent(
+ NOTIFICATION_KEY, message, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+
+ ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+ ArgumentCaptor.forClass(TextClassifierEvent.class);
+ verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+ TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+ assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_SMART_ACTION);
+ }
+
+ @Test
+ public void testOnSuggestedReplySent_anotherNotification() {
+ final String message = "Where are you?";
+ Notification notification = mNotificationBuilder.setContentText(message).build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onSuggestedReplySent(
+ "something_else", message, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+
+ verify(mTextClassifier, never())
+ .onTextClassifierEvent(Mockito.any(TextClassifierEvent.class));
+ }
+
+ @Test
+ public void testOnSuggestedReplySent_missingResultId() {
+ when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
+ .thenReturn(new ConversationActions(Collections.emptyList(), null));
+
+ final String message = "Where are you?";
+ Notification notification = mNotificationBuilder.setContentText(message).build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onSuggestedReplySent(
+ "something_else", message, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+
+ verify(mTextClassifier, never())
+ .onTextClassifierEvent(Mockito.any(TextClassifierEvent.class));
+ }
+
+ @Test
+ public void testOnNotificationDirectReply() {
+ Notification notification = mNotificationBuilder.setContentText("Where are you?").build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onNotificationDirectReply(NOTIFICATION_KEY);
+
+ ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+ ArgumentCaptor.forClass(TextClassifierEvent.class);
+ verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+ TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+ assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_MANUAL_REPLY);
+ }
+
+ @Test
+ public void testOnNotificationExpansionChanged() {
+ final String message = "Where are you?";
+ Notification notification = mNotificationBuilder.setContentText(message).build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onNotificationExpansionChanged(mNotificationEntry, true, true);
+
+ ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+ ArgumentCaptor.forClass(TextClassifierEvent.class);
+ verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+ TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+ assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_SHOWN);
+ }
+
+ @Test
+ public void testOnNotificationsSeen_notExpanded() {
+ final String message = "Where are you?";
+ Notification notification = mNotificationBuilder.setContentText(message).build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+ when(mNotificationEntry.isExpanded()).thenReturn(false);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onNotificationSeen(mNotificationEntry);
+
+ verify(mTextClassifier, never()).onTextClassifierEvent(
+ Mockito.any(TextClassifierEvent.class));
+ }
+
+ @Test
+ public void testOnNotificationsSeen_expanded() {
+ final String message = "Where are you?";
+ Notification notification = mNotificationBuilder.setContentText(message).build();
+ when(mNotificationEntry.getNotification()).thenReturn(notification);
+ when(mNotificationEntry.isExpanded()).thenReturn(true);
+
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
+ mSmartActionsHelper.onNotificationSeen(mNotificationEntry);
+
+ ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+ ArgumentCaptor.forClass(TextClassifierEvent.class);
+ verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+ TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+ assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_SHOWN);
+ }
+
private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneOffset.systemDefault());
}
private List<ConversationActions.Message> getMessagesInRequest() {
- mSmartActionsHelper.suggestReplies(mContext, mNotificationEntry, mSettings);
+ mSmartActionsHelper.suggestReplies(mNotificationEntry);
ArgumentCaptor<ConversationActions.Request> argumentCaptor =
ArgumentCaptor.forClass(ConversationActions.Request.class);
@@ -189,6 +311,17 @@
return request.getConversation();
}
+ private void assertTextClassifierEvent(
+ TextClassifierEvent textClassifierEvent, int expectedEventType) {
+ assertThat(textClassifierEvent.getEventCategory())
+ .isEqualTo(TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS);
+ assertThat(textClassifierEvent.getEventContext().getPackageName())
+ .isEqualTo(InstrumentationRegistry.getTargetContext().getPackageName());
+ assertThat(textClassifierEvent.getEventContext().getWidgetType())
+ .isEqualTo(TextClassifier.WIDGET_TYPE_NOTIFICATION);
+ assertThat(textClassifierEvent.getEventType()).isEqualTo(expectedEventType);
+ }
+
private static final class MessageSubject
extends Subject<MessageSubject, ConversationActions.Message> {
diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp
index 83427d4..04cf01a 100644
--- a/packages/ExternalStorageProvider/tests/Android.bp
+++ b/packages/ExternalStorageProvider/tests/Android.bp
@@ -14,7 +14,7 @@
],
static_libs: [
- "android-support-test",
+ "androidx.test.rules",
"mockito-target",
"truth-prebuilt",
],
diff --git a/packages/ExternalStorageProvider/tests/AndroidManifest.xml b/packages/ExternalStorageProvider/tests/AndroidManifest.xml
index 58b6e86..f1a6af0 100644
--- a/packages/ExternalStorageProvider/tests/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/tests/AndroidManifest.xml
@@ -6,7 +6,7 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.externalstorage"
android:label="ExternalStorageProvider Tests" />
</manifest>
diff --git a/packages/ExternalStorageProvider/tests/AndroidTest.xml b/packages/ExternalStorageProvider/tests/AndroidTest.xml
index e5fa73f..f8438b2 100644
--- a/packages/ExternalStorageProvider/tests/AndroidTest.xml
+++ b/packages/ExternalStorageProvider/tests/AndroidTest.xml
@@ -23,7 +23,7 @@
<option name="test-tag" value="ExternalStorageProviderTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.externalstorage.tests" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
index a88b3e1..fbf2e4b 100644
--- a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
+++ b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
@@ -23,8 +23,9 @@
import static org.mockito.Mockito.verify;
import android.content.pm.ProviderInfo;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index c893b6d..4a814df 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -31,8 +31,8 @@
LOCAL_USE_AAPT2 := true
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
- espresso-core \
+ androidx.test.rules \
+ androidx.test.espresso.core \
mockito-target-minus-junit4 \
truth-prebuilt
diff --git a/packages/SettingsLib/tests/integ/AndroidManifest.xml b/packages/SettingsLib/tests/integ/AndroidManifest.xml
index e8e0b41..da808dd 100644
--- a/packages/SettingsLib/tests/integ/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/integ/AndroidManifest.xml
@@ -31,7 +31,7 @@
<activity android:name=".drawer.SettingsDrawerActivityTest$TestActivity"/>
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.settingslib"
android:label="Tests for SettingsLib">
</instrumentation>
diff --git a/packages/SettingsLib/tests/integ/AndroidTest.xml b/packages/SettingsLib/tests/integ/AndroidTest.xml
index d7ee618..b5d0947 100644
--- a/packages/SettingsLib/tests/integ/AndroidTest.xml
+++ b/packages/SettingsLib/tests/integ/AndroidTest.xml
@@ -22,7 +22,7 @@
<option name="test-tag" value="SettingsLibTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.settingslib" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java
index d0ab46a..50f5b9d 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java
@@ -16,15 +16,10 @@
package com.android.settingslib.bluetooth;
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
-import static java.util.concurrent.TimeUnit.SECONDS;
-
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -32,15 +27,18 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
import java.util.concurrent.CountDownLatch;
/**
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
index 3fa2ce5..a436cb5 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
@@ -27,8 +27,9 @@
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import com.android.settingslib.R;
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 dddfa7a..08484bc 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
@@ -1,19 +1,7 @@
package com.android.settingslib.graph;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import com.android.settingslib.R;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import static com.google.common.truth.Truth.assertThat;
-import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyString;
@@ -21,6 +9,21 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.settingslib.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BatteryMeterDrawableBaseTest {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java
index 93b038e..9962e1c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java
@@ -20,12 +20,13 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java
index e591d8c..f1c0bea 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java
@@ -16,11 +16,12 @@
package com.android.settingslib.inputmethod;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
index 54510b2..46557d3 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,8 +32,9 @@
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
index ee03d50..37f2600 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
@@ -16,19 +16,22 @@
package com.android.settingslib.utils;
+import static junit.framework.Assert.assertEquals;
+
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.settingslib.NetworkPolicyEditor;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static junit.framework.Assert.assertEquals;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkPolicyEditorTest {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
index 0ec75ec..ff8dbda 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
@@ -15,21 +15,23 @@
*/
package com.android.settingslib.utils;
+import static junit.framework.Assert.assertTrue;
+
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.filters.SmallTest;
import android.text.Spanned;
import android.text.style.TtsSpan;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.settingslib.datetime.ZoneGetter;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.*;
-import com.android.settingslib.datetime.ZoneGetter;
-
-import static junit.framework.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@SmallTest
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 03247999..fc3034e 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -22,7 +22,6 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -44,12 +43,12 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.SpannableString;
import android.text.format.DateUtils;
-import android.text.style.TtsSpan;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.settingslib.R;
import com.android.settingslib.utils.ThreadUtils;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 1860b31..42eb0b9 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -53,9 +53,10 @@
import android.os.HandlerThread;
import android.os.SystemClock;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.settingslib.utils.ThreadUtils;
@@ -79,7 +80,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
// TODO(sghuman): Change these to robolectric tests b/35766684.
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WifiTrackerTest {
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
index 8e8d9f7..abe82a8 100644
--- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -18,7 +18,7 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.os.SystemProperties;
+import android.sysprop.SetupWizardProperties;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
@@ -51,7 +51,7 @@
// Setup theme for aosp/pixel
setTheme(
WizardManagerHelper.getThemeRes(
- SystemProperties.get("setupwizard.theme"),
+ SetupWizardProperties.theme().orElse(""),
R.style.SuwThemeGlif_Light
)
);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 201c7e6..9a8a6d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -41,6 +41,8 @@
import androidx.slice.builders.SliceAction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
@@ -49,6 +51,7 @@
import java.util.Date;
import java.util.Locale;
+import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
/**
@@ -100,21 +103,28 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (Intent.ACTION_TIME_TICK.equals(action)
- || Intent.ACTION_DATE_CHANGED.equals(action)
- || Intent.ACTION_TIME_CHANGED.equals(action)
- || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
- || Intent.ACTION_LOCALE_CHANGED.equals(action)) {
- if (Intent.ACTION_LOCALE_CHANGED.equals(action)
- || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
- // need to get a fresh date format
- mHandler.post(KeyguardSliceProvider.this::cleanDateFormat);
- }
+ if (Intent.ACTION_DATE_CHANGED.equals(action)) {
mHandler.post(KeyguardSliceProvider.this::updateClock);
+ } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ mHandler.post(KeyguardSliceProvider.this::cleanDateFormat);
}
}
};
+ @VisibleForTesting
+ final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onTimeChanged() {
+ mHandler.post(KeyguardSliceProvider.this::updateClock);
+ }
+
+ @Override
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mHandler.post(KeyguardSliceProvider.this::cleanDateFormat);
+ }
+ };
+
public KeyguardSliceProvider() {
this(new Handler());
}
@@ -250,11 +260,10 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_DATE_CHANGED);
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
null /* scheduler */);
+ getKeyguardUpdateMonitor().registerCallback(mKeyguardUpdateMonitorCallback);
mRegistered = true;
}
@@ -300,4 +309,9 @@
}
updateNextAlarm();
}
+
+ @VisibleForTesting
+ protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
+ return KeyguardUpdateMonitor.getInstance(getContext());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 7d1b640..158430f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,10 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
@@ -35,7 +32,6 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.text.format.Formatter;
@@ -152,10 +148,7 @@
private void registerCallbacks(KeyguardUpdateMonitor monitor) {
monitor.registerCallback(getKeyguardCallback());
- mContext.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
- new IntentFilter(Intent.ACTION_TIME_TICK), null,
- Dependency.get(Dependency.TIME_TICK_HANDLER));
-
+ KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mTickReceiver);
Dependency.get(StatusBarStateController.class).addCallback(this);
}
@@ -166,7 +159,7 @@
* //TODO: This can probably be converted to a fragment and not have to be manually recreated
*/
public void destroy() {
- mContext.unregisterReceiver(mTickReceiver);
+ KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mTickReceiver);
Dependency.get(StatusBarStateController.class).removeCallback(this);
}
@@ -477,16 +470,15 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
}
- private final BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.post(() -> {
- if (mVisible) {
- updateIndication(false);
+ private final KeyguardUpdateMonitorCallback mTickReceiver =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onTimeChanged() {
+ if (mVisible) {
+ updateIndication(false /* animate */);
+ }
}
- });
- }
- };
+ };
private final Handler mHandler = new Handler() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 7876aa5..dd07ec4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.NavBarTintController.DEFAULT_COLOR_ADAPT_TRANSITION_TIME;
import static com.android.systemui.statusbar.phone.NavBarTintController.MIN_COLOR_ADAPT_TRANSITION_TIME;
import static com.android.systemui.statusbar.phone.NavBarTintController.NAV_COLOR_TRANSITION_TIME_SETTING;
@@ -161,7 +162,7 @@
public long getTintAnimationDuration() {
if (NavBarTintController.isEnabled(mContext)) {
return Math.max(Settings.Global.getInt(mContext.getContentResolver(),
- NAV_COLOR_TRANSITION_TIME_SETTING, DEFAULT_TINT_ANIMATION_DURATION),
+ NAV_COLOR_TRANSITION_TIME_SETTING, DEFAULT_COLOR_ADAPT_TRANSITION_TIME),
MIN_COLOR_ADAPT_TRANSITION_TIME);
}
return DEFAULT_TINT_ANIMATION_DURATION;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
index 9ecee18..b4f850b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -31,6 +31,7 @@
public class NavBarTintController {
public static final String NAV_COLOR_TRANSITION_TIME_SETTING = "navbar_color_adapt_transition";
public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400;
+ public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1500;
private final HandlerThread mColorAdaptHandlerThread = new HandlerThread("ColorExtractThread");
private Handler mColorAdaptionHandler;
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 c1c80ce..7d94635 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -19,13 +19,13 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.AlarmManager;
import android.content.ContentResolver;
-import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
@@ -40,6 +40,7 @@
import androidx.slice.builders.ListBuilder;
import androidx.slice.core.SliceQuery;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import org.junit.Assert;
@@ -91,7 +92,7 @@
@Test
public void cleansDateFormat() {
- mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIMEZONE_CHANGED));
+ mProvider.mKeyguardUpdateMonitorCallback.onTimeZoneChanged(null);
TestableLooper.get(this).processAllMessages();
Assert.assertEquals("Date format should have been cleaned.", 1 /* expected */,
mProvider.mCleanDateFormatInvokations);
@@ -99,7 +100,7 @@
@Test
public void updatesClock() {
- mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK));
+ mProvider.mKeyguardUpdateMonitorCallback.onTimeChanged();
TestableLooper.get(this).processAllMessages();
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
}
@@ -171,6 +172,11 @@
}
@Override
+ public KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
+ return mock(KeyguardUpdateMonitor.class);
+ }
+
+ @Override
protected String getFormattedDate() {
return super.getFormattedDate() + mCounter++;
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 8ec97c5..d0937e9 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1519,6 +1519,13 @@
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ // Stacks and activities could be removed while putting activities to sleep if
+ // the app process was gone. This prevents us getting exception by accessing an
+ // invalid stack index.
+ if (stackNdx >= display.getChildCount()) {
+ continue;
+ }
+
final ActivityStack stack = display.getChildAt(stackNdx);
if (allowDelay) {
allSleep &= stack.goToSleepIfPossible(shuttingDown);
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index c006a7b..b219419 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -66,8 +66,11 @@
// method target window will lose the focus.
return;
}
- mDisplayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP,
- mDisplayContent, true /* includingParents */);
+ WindowContainer parent = mDisplayContent.getParent();
+ if (parent != null) {
+ parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
+ true /* includingParents */);
+ }
}
};
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index 83e7ee7..dfdbf32 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -49,12 +49,9 @@
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
import java.util.concurrent.CountDownLatch;
@@ -72,7 +69,6 @@
@Mock Transaction mMockTransaction;
@Mock AnimationSpec mMockAnimationSpec;
@Mock PowerManagerInternal mMockPowerManager;
- @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
private SurfaceAnimationRunner mSurfaceAnimationRunner;
private CountDownLatch mFinishCallbackLatch;
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 1cbe5a2..c115a4b 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2732,10 +2732,26 @@
/**
* The {@code content://} style URL for this table.
+ * For MSIM, this will return APNs for the default subscription
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
+ * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
*/
public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
/**
+ * The {@code content://} style URL for this table. Used for APN query based on current
+ * subscription. Instead of specifying carrier matching information in the selection,
+ * this API will return all matching APNs from current subscription carrier and queries
+ * will be applied on top of that. If there is no match for MVNO (Mobile Virtual Network
+ * Operator) APNs, return APNs from its MNO (based on mccmnc) instead. For MSIM, this will
+ * return APNs for the default subscription
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
+ * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
+ */
+ public static final Uri SIM_APN_URI = Uri.parse(
+ "content://telephony/carriers/sim_apn_list");
+
+ /**
* The {@code content://} style URL to be called from DevicePolicyManagerService,
* can manage DPC-owned APNs.
* @hide
@@ -2745,7 +2761,9 @@
/**
* The {@code content://} style URL to be called from Telephony to query APNs.
* When DPC-owned APNs are enforced, only DPC-owned APNs are returned, otherwise only
- * non-DPC-owned APNs are returned.
+ * non-DPC-owned APNs are returned. For MSIM, this will return APNs for the default
+ * subscription {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId
+ * for MSIM, use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
* @hide
*/
public static final Uri FILTERED_URI = Uri.parse("content://telephony/carriers/filtered");
@@ -2759,13 +2777,6 @@
"content://telephony/carriers/enforce_managed");
/**
- * The {@code content://} style URL to be called from Telephony to query current APNs.
- * @hide
- */
- public static final Uri SIM_APN_LIST = Uri.parse(
- "content://telephony/carriers/sim_apn_list");
-
- /**
* The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
* @hide
*/
@@ -2839,18 +2850,30 @@
/**
* Mobile Country Code (MCC).
* <P>Type: TEXT</P>
+ * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+ * matching APNs based on current subscription carrier, thus no need to specify MCC and
+ * other carrier matching information. In the future, Android will not support MCC for
+ * APN query.
*/
public static final String MCC = "mcc";
/**
* Mobile Network Code (MNC).
* <P>Type: TEXT</P>
+ * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+ * matching APNs based on current subscription carrier, thus no need to specify MNC and
+ * other carrier matching information. In the future, Android will not support MNC for
+ * APN query.
*/
public static final String MNC = "mnc";
/**
* Numeric operator ID (as String). Usually {@code MCC + MNC}.
* <P>Type: TEXT</P>
+ * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+ * matching APNs based on current subscription carrier, thus no need to specify Numeric
+ * and other carrier matching information. In the future, Android will not support Numeric
+ * for APN query.
*/
public static final String NUMERIC = "numeric";
@@ -2931,6 +2954,10 @@
* MVNO type:
* {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
* <P>Type: TEXT</P>
+ * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+ * matching APNs based on current subscription carrier, thus no need to specify MVNO_TYPE
+ * and other carrier matching information. In the future, Android will not support MVNO_TYPE
+ * for APN query.
*/
public static final String MVNO_TYPE = "mvno_type";
@@ -2943,6 +2970,10 @@
* <li>GID: 4E, 33, ...</li>
* </ul>
* <P>Type: TEXT</P>
+ * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+ * matching APNs based on current subscription carrier, thus no need to specify
+ * MVNO_MATCH_DATA and other carrier matching information. In the future, Android will not
+ * support MVNO_MATCH_DATA for APN query.
*/
public static final String MVNO_MATCH_DATA = "mvno_match_data";
@@ -3151,7 +3182,6 @@
})
@Retention(RetentionPolicy.SOURCE)
public @interface EditStatus {}
-
}
/**
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 355a576..6326cc6 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -61,7 +61,6 @@
public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
"android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
-
/**
* Broadcast Action: The eUICC OTA status is changed.
* <p class="note">
@@ -87,6 +86,20 @@
"android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
/**
+ * Intent action to select a profile to enable before download a new eSIM profile.
+ *
+ * May be called during device provisioning when there are multiple slots having profiles on
+ * them. This Intent launches a screen for all the current existing profiles and let users to
+ * choose which one they want to enable. In this case, the slot contains the profile will be
+ * activated.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_PROFILE_SELECTION =
+ "android.telephony.euicc.action.PROFILE_SELECTION";
+
+ /**
* Intent action to provision an embedded subscription.
*
* <p>May be called during device provisioning to launch a screen to perform embedded SIM
@@ -132,6 +145,16 @@
public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2;
/**
+ * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for which
+ * kind of activation flow will be evolved. (see {@code EUICC_ACTIVATION_})
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ACTIVATION_TYPE =
+ "android.telephony.euicc.extra.ACTIVATION_TYPE";
+
+ /**
* Key for an extra set on {@link PendingIntent} result callbacks providing a detailed result
* code.
*
@@ -197,6 +220,52 @@
public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
/**
+ * Euicc activation type which will be included in {@link #EXTRA_ACTIVATION_TYPE} and used to
+ * decide which kind of activation flow should be lauched.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EUICC_ACTIVATION_"}, value = {
+ EUICC_ACTIVATION_TYPE_DEFAULT,
+ EUICC_ACTIVATION_TYPE_BACKUP,
+ EUICC_ACTIVATION_TYPE_TRANSFER
+
+ })
+ public @interface EuiccActivationType{}
+
+
+ /**
+ * The default euicc activation type which includes checking server side and downloading the
+ * profile based on carrier's download configuration.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1;
+
+ /**
+ * The euicc activation type used when the default download process failed. LPA will start the
+ * backup flow and try to download the profile for the carrier.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2;
+
+ /**
+ * The activation flow of eSIM seamless transfer will be used. LPA will start normal eSIM
+ * activation flow and if it's failed, the name of the carrier selected will be recorded. After
+ * the future device pairing, LPA will contact this carrier to transfer it from the other device
+ * to this device.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3;
+
+
+ /**
* Euicc OTA update status which can be got by {@link #getOtaStatus}
* @hide
*/