Merge "Add more UserMananger related tests."
diff --git a/Android.mk b/Android.mk
index 584e4d1..1d236f4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -900,7 +900,7 @@
framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-hdf sdk.codename N \
- -hdf sdk.preview.version 2 \
+ -hdf sdk.preview.version 5 \
-hdf sdk.version $(framework_docs_SDK_VERSION) \
-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-hdf sdk.preview 1
diff --git a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
index db15e9b..d444c92 100644
--- a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
@@ -17,6 +17,7 @@
package android.widget;
import android.app.Activity;
+import android.os.Looper;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
@@ -42,6 +43,7 @@
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
+import static org.junit.Assert.assertTrue;
@LargeTest
@RunWith(Parameterized.class)
@@ -77,6 +79,11 @@
@Test
@UiThreadTest
public void testLayoutPerf() {
+ assertTrue("We should be running on the main thread",
+ Looper.getMainLooper().getThread() == Thread.currentThread());
+ assertTrue("We should be running on the main thread",
+ Looper.myLooper() == Looper.getMainLooper());
+
Activity activity = mActivityRule.getActivity();
activity.setContentView(mLayoutId);
diff --git a/api/current.txt b/api/current.txt
index 5065f5c..956559e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10326,7 +10326,7 @@
}
public class Resources {
- ctor public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+ ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
method public final void finishPreloading();
method public final void flushLayoutCache();
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
@@ -10377,7 +10377,7 @@
method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -19657,6 +19657,7 @@
field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
+ field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
@@ -20109,7 +20110,6 @@
method public java.lang.String getAttribute(java.lang.String);
method public double getAttributeDouble(java.lang.String, double);
method public int getAttributeInt(java.lang.String, int);
- method public long[] getAttributeLongArray(java.lang.String);
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
method public long[] getThumbnailRange();
@@ -40668,6 +40668,7 @@
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
+ method public int indexOfValueByValue(E);
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 666b604..292f533 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10765,7 +10765,7 @@
}
public class Resources {
- ctor public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+ ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
method public final void finishPreloading();
method public final void flushLayoutCache();
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
@@ -10816,7 +10816,7 @@
method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -21165,6 +21165,7 @@
field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
+ field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
@@ -21629,7 +21630,6 @@
method public java.lang.String getAttribute(java.lang.String);
method public double getAttributeDouble(java.lang.String, double);
method public int getAttributeInt(java.lang.String, int);
- method public long[] getAttributeLongArray(java.lang.String);
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
method public long[] getThumbnailRange();
@@ -43834,6 +43834,7 @@
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
+ method public int indexOfValueByValue(E);
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 92745c3..592ec67 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10340,7 +10340,7 @@
}
public class Resources {
- ctor public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+ ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
method public final void finishPreloading();
method public final void flushLayoutCache();
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
@@ -10391,7 +10391,7 @@
method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -19727,6 +19727,7 @@
field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
+ field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
@@ -20179,7 +20180,6 @@
method public java.lang.String getAttribute(java.lang.String);
method public double getAttributeDouble(java.lang.String, double);
method public int getAttributeInt(java.lang.String, int);
- method public long[] getAttributeLongArray(java.lang.String);
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
method public long[] getThumbnailRange();
@@ -40748,6 +40748,7 @@
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
+ method public int indexOfValueByValue(E);
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 2e02382..2093579 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -299,8 +299,9 @@
}
if (!niceName.isEmpty()) {
- runtime.setArgv0(niceName.string());
- set_process_name(niceName.string());
+ const char* procName = niceName.string();
+ pthread_setname_np(pthread_self(), procName);
+ runtime.setArgv0(procName);
}
if (zygote) {
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 3cf13d9..3a92b9e 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -36,8 +36,4 @@
LOCAL_32_BIT_ONLY := true
endif
-# get asserts to work
-APP_OPTIM := debug
-LOCAL_CFLAGS += -UNDEBUG
-
include $(BUILD_EXECUTABLE)
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index d82629d..e634717 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -49,8 +49,8 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <SkBitmap.h>
+#include <SkImage.h>
#include <SkStream.h>
-#include <SkImageDecoder.h>
#pragma GCC diagnostic pop
#include <GLES/gl.h>
@@ -72,6 +72,8 @@
static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
+// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
+static const long long ACCURATE_TIME_EPOCH = 946684800000;
static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
static const int ANIM_ENTRY_NAME_MAX = 256;
@@ -115,8 +117,10 @@
if (asset == NULL)
return NO_INIT;
SkBitmap bitmap;
- SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
- &bitmap, kUnknown_SkColorType, SkImageDecoder::kDecodePixels_Mode);
+ sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false),
+ asset->getLength());
+ sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
+ image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
asset->close();
delete asset;
@@ -169,15 +173,10 @@
//StopWatch watch("blah");
SkBitmap bitmap;
- SkMemoryStream stream(frame.map->getDataPtr(), frame.map->getDataLength());
- SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
- if (codec != NULL) {
- codec->setDitherImage(false);
- codec->decode(&stream, &bitmap,
- kN32_SkColorType,
- SkImageDecoder::kDecodePixels_Mode);
- delete codec;
- }
+ sk_sp<SkData> data = SkData::MakeWithoutCopy(frame.map->getDataPtr(),
+ frame.map->getDataLength());
+ sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
+ image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
// FileMap memory is never released until application exit.
// Release it now as the texture is already loaded and the memory used for
@@ -586,7 +585,7 @@
return false;
}
- bool hasAudio = false;
+ Animation::Part* partWithAudio = NULL;
ZipEntryRO entry;
char name[ANIM_ENTRY_NAME_MAX];
while ((entry = zip->nextEntry(cookie)) != NULL) {
@@ -610,10 +609,10 @@
if (map) {
Animation::Part& part(animation.parts.editItemAt(j));
if (leaf == "audio.wav") {
- hasAudio = true;
// a part may have at most one audio file
part.audioData = (uint8_t *)map->getDataPtr();
part.audioLength = map->getDataLength();
+ partWithAudio = ∂
} else if (leaf == "trim.txt") {
part.trimData.setTo((char const*)map->getDataPtr(),
map->getDataLength());
@@ -664,9 +663,11 @@
}
// Create and initialize audioplay if there is a wav file in any of the animations.
- if (hasAudio) {
+ if (partWithAudio != NULL) {
ALOGD("found audio.wav, creating playback engine");
- audioplay::create();
+ if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) {
+ return false;
+ }
}
zip->endIteration(cookie);
@@ -902,7 +903,10 @@
mLoadedFiles.add(animation->fileName);
parseAnimationDesc(*animation);
- preloadZip(*animation);
+ if (!preloadZip(*animation)) {
+ return NULL;
+ }
+
mLoadedFiles.remove(fn);
return animation;
@@ -932,8 +936,9 @@
clock_gettime(CLOCK_REALTIME, &now);
// Match the Java timestamp format
long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
- if (lastChangedTime > rtcNow - MAX_TIME_IN_PAST
- && lastChangedTime < rtcNow + MAX_TIME_IN_FUTURE) {
+ if (ACCURATE_TIME_EPOCH < rtcNow
+ && lastChangedTime > (rtcNow - MAX_TIME_IN_PAST)
+ && lastChangedTime < (rtcNow + MAX_TIME_IN_FUTURE)) {
mTimeIsAccurate = true;
}
}
diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
index e20ef0c..8a5c2c6 100644
--- a/cmds/bootanimation/audioplay.cpp
+++ b/cmds/bootanimation/audioplay.cpp
@@ -21,7 +21,6 @@
#define CHATTY ALOGD
-#include <assert.h>
#include <string.h>
#include <utils/Log.h>
@@ -80,8 +79,6 @@
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
(void)bq;
(void)context;
- assert(bq == bqPlayerBufferQueue);
- assert(NULL == context);
audioplay::setPlaying(false);
}
@@ -90,39 +87,56 @@
}
// create the engine and output mix objects
-void createEngine() {
+bool createEngine() {
SLresult result;
// create engine
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("slCreateEngine failed with result %d", result);
+ return false;
+ }
(void)result;
// realize the engine
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl engine Realize failed with result %d", result);
+ return false;
+ }
(void)result;
// get the engine interface, which is needed in order to create other objects
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl engine GetInterface failed with result %d", result);
+ return false;
+ }
(void)result;
// create output mix, with environmental reverb specified as a non-required interface
const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean req[1] = {SL_BOOLEAN_FALSE};
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl engine CreateOutputMix failed with result %d", result);
+ return false;
+ }
(void)result;
// realize the output mix
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl outputMix Realize failed with result %d", result);
+ return false;
+ }
(void)result;
+
+ return true;
}
// create buffer queue audio player
-void createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
+bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
SLresult result;
// configure audio source
@@ -148,83 +162,89 @@
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
2, ids, req);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl CreateAudioPlayer failed with result %d", result);
+ return false;
+ }
(void)result;
// realize the player
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl player Realize failed with result %d", result);
+ return false;
+ }
(void)result;
// get the play interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl player GetInterface failed with result %d", result);
+ return false;
+ }
(void)result;
// get the buffer queue interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
+ return false;
+ }
(void)result;
// register callback on the buffer queue
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
+ return false;
+ }
(void)result;
-#if 0 // mute/solo is not supported for sources that are known to be mono, as this is
- // get the mute/solo interface
- result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
- assert(SL_RESULT_SUCCESS == result);
- (void)result;
-#endif
-
// get the volume interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
- assert(SL_RESULT_SUCCESS == result);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl volume GetInterface failed with result %d", result);
+ return false;
+ }
(void)result;
// set the player's state to playing
audioplay::setPlaying(true);
CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
+ return true;
}
-} // namespace
-
-void create() {
- createEngine();
-}
-
-bool playClip(const uint8_t* buf, int size) {
- // Parse the WAV header
- nextBuffer = buf;
- nextSize = size;
- const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)buf;
- if (nextSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
+bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,
+ const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
+ *oSoundBuf = clipBuf;
+ *oSoundBufSize = clipBufSize;
+ *oChunkFormat = NULL;
+ const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
+ if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
(wavHeader->wave_id != ID_WAVE)) {
ALOGE("Error: audio file is not a riff/wave file\n");
return false;
}
- nextBuffer += sizeof(*wavHeader);
- nextSize -= sizeof(*wavHeader);
+ *oSoundBuf += sizeof(*wavHeader);
+ *oSoundBufSize -= sizeof(*wavHeader);
- const ChunkFormat* chunkFormat = nullptr;
while (true) {
- const ChunkHeader* chunkHeader = (const ChunkHeader*)nextBuffer;
- if (nextSize < sizeof(*chunkHeader)) {
+ const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
+ if (*oSoundBufSize < sizeof(*chunkHeader)) {
ALOGE("EOF reading chunk headers");
return false;
}
- nextBuffer += sizeof(*chunkHeader);
- nextSize -= sizeof(*chunkHeader);
+ *oSoundBuf += sizeof(*chunkHeader);
+ *oSoundBufSize -= sizeof(*chunkHeader);
bool endLoop = false;
switch (chunkHeader->id) {
case ID_FMT:
- chunkFormat = (const ChunkFormat*)nextBuffer;
- nextBuffer += chunkHeader->sz;
- nextSize -= chunkHeader->sz;
+ *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
+ *oSoundBuf += chunkHeader->sz;
+ *oSoundBufSize -= chunkHeader->sz;
break;
case ID_DATA:
/* Stop looking for chunks */
@@ -232,27 +252,49 @@
break;
default:
/* Unknown chunk, skip bytes */
- nextBuffer += chunkHeader->sz;
- nextSize -= chunkHeader->sz;
+ *oSoundBuf += chunkHeader->sz;
+ *oSoundBufSize -= chunkHeader->sz;
}
if (endLoop) {
break;
}
}
- if (!chunkFormat) {
+ if (*oChunkFormat == NULL) {
ALOGE("format not found in WAV file");
return false;
}
+ return true;
+}
- // If this is the first clip, create the buffer based on this WAV's header.
- // We assume all future clips with be in the same format.
- if (bqPlayerBufferQueue == nullptr) {
- createBufferQueueAudioPlayer(chunkFormat);
+} // namespace
+
+bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
+ if (!createEngine()) {
+ return false;
}
- assert(bqPlayerBufferQueue != nullptr);
- assert(buf != nullptr);
+ // Parse the example clip.
+ const ChunkFormat* chunkFormat;
+ const uint8_t* soundBuf;
+ unsigned soundBufSize;
+ if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) {
+ return false;
+ }
+
+ // Initialize the BufferQueue based on this clip's format.
+ if (!createBufferQueueAudioPlayer(chunkFormat)) {
+ return false;
+ }
+ return true;
+}
+
+bool playClip(const uint8_t* buf, int size) {
+ // Parse the WAV header
+ const ChunkFormat* chunkFormat;
+ if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
+ return false;
+ }
if (!hasPlayer()) {
ALOGD("cannot play clip %p without a player", buf);
@@ -285,8 +327,6 @@
// set the player's state
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
- assert(SL_RESULT_SUCCESS == result);
- (void)result;
}
}
diff --git a/cmds/bootanimation/audioplay.h b/cmds/bootanimation/audioplay.h
index bdc0a1c..0e5705af 100644
--- a/cmds/bootanimation/audioplay.h
+++ b/cmds/bootanimation/audioplay.h
@@ -22,10 +22,12 @@
namespace audioplay {
-void create();
+// Initializes the engine with an example of the type of WAV clip to play.
+// All buffers passed to playClip are assumed to be in the same format.
+bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize);
-// Play a WAV pointed to by buf. All clips are assumed to be in the same format.
-// playClip should not be called while a clip is still playing.
+// Plays a WAV contained in buf.
+// Should not be called while a clip is still playing.
bool playClip(const uint8_t* buf, int size);
void setPlaying(bool isPlaying);
void destroy();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0c0af87..edeb838 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -724,8 +724,6 @@
private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:";
private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui";
- private static final String KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME =
- "com.android.systemui.statusbar.KeyboardShortcutsReceiver";
private static class ManagedDialog {
Dialog mDialog;
@@ -1694,9 +1692,8 @@
*/
public final void requestShowKeyboardShortcuts() {
Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
- intent.setComponent(new ComponentName(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME,
- KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME));
- sendBroadcast(intent);
+ intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
+ sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
/**
@@ -1704,9 +1701,8 @@
*/
public final void dismissKeyboardShortcutsHelper() {
Intent intent = new Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS);
- intent.setComponent(new ComponentName(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME,
- KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME));
- sendBroadcast(intent);
+ intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
+ sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
@Override
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 22a1fce..419f723 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -93,7 +93,8 @@
@IntDef({
BUGREPORT_OPTION_FULL,
BUGREPORT_OPTION_INTERACTIVE,
- BUGREPORT_OPTION_REMOTE
+ BUGREPORT_OPTION_REMOTE,
+ BUGREPORT_OPTION_WEAR
})
public @interface BugreportMode {}
/**
@@ -114,6 +115,11 @@
* @hide
*/
public static final int BUGREPORT_OPTION_REMOTE = 2;
+ /**
+ * Takes a bugreport on a wearable device.
+ * @hide
+ */
+ public static final int BUGREPORT_OPTION_WEAR = 3;
/**
* <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 8692336..9fa8a5d 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -345,7 +345,7 @@
PrintWriter pw = new FastPrintWriter(sw, false, 256);
tr.printStackTrace(pw);
pw.flush();
- stackTrace = sw.toString();
+ stackTrace = sanitizeString(sw.toString());
exceptionMessage = tr.getMessage();
// Populate fields with the "root cause" exception
@@ -374,6 +374,29 @@
throwMethodName = "unknown";
throwLineNumber = 0;
}
+
+ exceptionMessage = sanitizeString(exceptionMessage);
+ }
+
+ /**
+ * Ensure that the string is of reasonable size, truncating from the middle if needed.
+ */
+ private String sanitizeString(String s) {
+ int prefixLength = 10 * 1024;
+ int suffixLength = 10 * 1024;
+ int acceptableLength = prefixLength + suffixLength;
+
+ if (s != null && s.length() > acceptableLength) {
+ String replacement =
+ "\n[TRUNCATED " + (s.length() - acceptableLength) + " CHARS]\n";
+
+ StringBuilder sb = new StringBuilder(acceptableLength + replacement.length());
+ sb.append(s.substring(0, prefixLength));
+ sb.append(replacement);
+ sb.append(s.substring(s.length() - suffixLength));
+ return sb.toString();
+ }
+ return s;
}
/**
diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
index 35b53a4..d5b3ed0 100644
--- a/core/java/android/app/ITransientNotification.aidl
+++ b/core/java/android/app/ITransientNotification.aidl
@@ -19,7 +19,7 @@
/** @hide */
oneway interface ITransientNotification {
- void show();
+ void show(IBinder windowToken);
void hide();
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 9cd70e6..db7d54b 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -49,7 +49,7 @@
/**
* Set the live wallpaper. This only affects the system wallpaper.
*/
- void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
+ void setWallpaperComponentChecked(in ComponentName name, in String callingPackage, int userId);
/**
* Set the live wallpaper. This only affects the system wallpaper.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0d2fd2e..e78b2e7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3478,6 +3478,8 @@
mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon);
}
contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
+ contentView.setDrawableParameters(R.id.icon, false /* targetBackground */,
+ -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel);
processSmallIconColor(mN.mSmallIcon, contentView);
}
@@ -3523,6 +3525,8 @@
boolean validRemoteInput = false;
int N = mActions.size();
+ boolean emphazisedMode = mN.fullScreenIntent != null;
+ big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
if (N > 0) {
big.setViewVisibility(R.id.actions_container, View.VISIBLE);
big.setViewVisibility(R.id.actions, View.VISIBLE);
@@ -3533,7 +3537,8 @@
Action action = mActions.get(i);
validRemoteInput |= hasValidRemoteInput(action);
- final RemoteViews button = generateActionButton(action);
+ final RemoteViews button = generateActionButton(action, emphazisedMode,
+ i % 2 != 0);
big.addView(R.id.actions, button);
}
} else {
@@ -3698,11 +3703,13 @@
- private RemoteViews generateActionButton(Action action) {
+ private RemoteViews generateActionButton(Action action, boolean emphazisedMode,
+ boolean oddAction) {
final boolean tombstone = (action.actionIntent == null);
RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(),
- tombstone ? getActionTombstoneLayoutResource()
- : getActionLayoutResource());
+ emphazisedMode ? getEmphasizedActionLayoutResource()
+ : tombstone ? getActionTombstoneLayoutResource()
+ : getActionLayoutResource());
final Icon ai = action.getIcon();
button.setTextViewText(R.id.action0, processLegacyText(action.title));
if (!tombstone) {
@@ -3712,8 +3719,18 @@
if (action.mRemoteInputs != null) {
button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
}
- if (mN.color != COLOR_DEFAULT) {
- button.setTextColor(R.id.action0, resolveContrastColor());
+ if (emphazisedMode) {
+ // change the background color
+ int color = resolveContrastColor();
+ if (oddAction) {
+ color = NotificationColorUtil.lightenColor(color, 10);
+ }
+ button.setDrawableParameters(R.id.button_holder, true, -1, color,
+ PorterDuff.Mode.SRC_ATOP, -1);
+ } else {
+ if (mN.color != COLOR_DEFAULT) {
+ button.setTextColor(R.id.action0, resolveContrastColor());
+ }
}
return button;
}
@@ -3983,6 +4000,10 @@
return R.layout.notification_material_action;
}
+ private int getEmphasizedActionLayoutResource() {
+ return R.layout.notification_material_action_emphasized;
+ }
+
private int getActionTombstoneLayoutResource() {
return R.layout.notification_material_action_tombstone;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 53da4e3..20cbde1 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -417,8 +417,14 @@
* This is returned as an
* abstract Drawable that you can install in a View to display whatever
* wallpaper the user has currently set.
+ * <p>
+ * This method can return null if there is no system wallpaper available, if
+ * wallpapers are not supported in the current user, or if the calling app is not
+ * permitted to access the system wallpaper.
*
- * @return Returns a Drawable object that will draw the wallpaper.
+ * @return Returns a Drawable object that will draw the system wallpaper,
+ * or {@code null} if no system wallpaper exists or if the calling application
+ * is not able to access the wallpaper.
*/
public Drawable getDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM);
@@ -1404,12 +1410,26 @@
*/
@SystemApi
public boolean setWallpaperComponent(ComponentName name) {
+ return setWallpaperComponent(name, UserHandle.myUserId());
+ }
+
+ /**
+ * Set the live wallpaper.
+ *
+ * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
+ * permission. The caller must hold the INTERACT_ACROSS_USERS_FULL permission to change
+ * another user's wallpaper.
+ *
+ * @hide
+ */
+ public boolean setWallpaperComponent(ComponentName name, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
}
try {
- sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
+ sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName(),
+ userId);
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 416cf3b..6e58f09 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1315,7 +1315,7 @@
/**
* Retrieve the current minimum password quality for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
*
* <p>This method can be called on the {@link DevicePolicyManager} instance
@@ -1379,7 +1379,7 @@
/**
* Retrieve the current minimum password length for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
*
* <p>This method can be called on the {@link DevicePolicyManager} instance
@@ -1442,7 +1442,7 @@
/**
* Retrieve the current number of upper case letters required in the password
- * for a particular admin or all admins that set retrictions on this user and
+ * for a particular admin or all admins that set restrictions on this user and
* its participating profiles. Restrictions on profiles that have a separate challenge
* are not taken into account.
* This is the same value as set by
@@ -1511,7 +1511,7 @@
/**
* Retrieve the current number of lower case letters required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1580,7 +1580,7 @@
/**
* Retrieve the current number of letters required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1648,7 +1648,7 @@
/**
* Retrieve the current number of numerical digits required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1716,7 +1716,7 @@
/**
* Retrieve the current number of symbols required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account. This is the same value as
* set by {@link #setPasswordMinimumSymbols(ComponentName, int)}
@@ -1783,7 +1783,7 @@
/**
* Retrieve the current number of non-letter characters required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1915,7 +1915,7 @@
/**
* Get the current password expiration time for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account. If admin is {@code null}, then a composite
* of all expiration times is returned - which will be the minimum of all of them.
*
@@ -1939,7 +1939,7 @@
/**
* Retrieve the current password history length for a particular admin or all admins that
- * set retrictions on this user and its participating profiles. Restrictions on profiles that
+ * set restrictions on this user and its participating profiles. Restrictions on profiles that
* have a separate challenge are not taken into account.
*
* <p>This method can be called on the {@link DevicePolicyManager} instance
@@ -2121,7 +2121,7 @@
/**
* Retrieve the current maximum number of login attempts that are allowed before the device
- * or profile is wiped, for a particular admin or all admins that set retrictions on this user
+ * or profile is wiped, for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have a separate challenge are
* not taken into account.
*
@@ -2262,7 +2262,7 @@
/**
* Retrieve the current maximum time to unlock for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
*
* <p>This method can be called on the {@link DevicePolicyManager} instance
@@ -3349,7 +3349,7 @@
/**
* Determine whether or not features have been disabled in keyguard either by the calling
- * admin, if specified, or all admins that set retrictions on this user and its participating
+ * admin, if specified, or all admins that set restrictions on this user and its participating
* profiles. Restrictions on profiles that have a separate challenge are not taken into account.
*
* <p>This method can be called on the {@link DevicePolicyManager} instance
@@ -6438,6 +6438,30 @@
}
}
+ /**
+ * @hide
+ * Writes that the provisioning configuration has been applied.
+ */
+ public void setDeviceProvisioningConfigApplied() {
+ try {
+ mService.setDeviceProvisioningConfigApplied();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * @return whether the provisioning configuration has been applied.
+ */
+ public boolean isDeviceProvisioningConfigApplied() {
+ try {
+ return mService.isDeviceProvisioningConfigApplied();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
private void throwIfParentInstance(String functionName) {
if (mParentInstance) {
throw new SecurityException(functionName + " cannot be called on the parent instance");
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 4b793d1..1036f04 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -303,4 +303,6 @@
void uninstallPackageWithActiveAdmins(String packageName);
boolean isDeviceProvisioned();
+ boolean isDeviceProvisioningConfigApplied();
+ void setDeviceProvisioningConfigApplied();
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 49f32ab..2d6b45d 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -166,6 +166,9 @@
* network restrictions for the requesting app. Note that this flag alone
* doesn't actually place your {@link JobService} in the foreground; you
* still need to post the notification yourself.
+ * <p>
+ * To use this flag, the caller must hold the
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission.
*
* @hide
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9f5b838..43a8a82 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2219,6 +2219,22 @@
"android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
/**
+ * Broadcast Action: preferred activities have changed *explicitly*.
+ *
+ * <p>Note there are cases where a preferred activity is invalidated *implicitly*, e.g.
+ * when an app is installed or uninstalled, but in such cases this broadcast will *not*
+ * be sent.
+ *
+ * {@link #EXTRA_USER_HANDLE} contains the user ID in question.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PREFERRED_ACTIVITY_CHANGED =
+ "android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED";
+
+
+ /**
* Broadcast Action: The current system wallpaper has changed. See
* {@link android.app.WallpaperManager} for retrieving the new wallpaper.
* This should <em>only</em> be used to determine when the wallpaper
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 8ea77d6..f66e1f4 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -652,7 +652,7 @@
/** @hide */
public static IllegalArgumentException getInvalidIconException() {
return new IllegalArgumentException("Unsupported icon type:"
- +" only bitmap, resource and content URI are supported");
+ +" only the bitmap and resource types are supported");
}
/**
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index de52f73..f994d7e 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -67,17 +67,4 @@
public abstract boolean hasShortcutHostPermission(int launcherUserId,
@NonNull String callingPackage);
-
- /**
- * Called by AM when the system locale changes *within the AM lock*. ABSOLUTELY do not take
- * any locks in this method.
- */
- public abstract void onSystemLocaleChangedNoLock();
-
- /**
- * Called by PM before sending package broadcasts to other components. PM doesn't hold the PM
- * lock, but do not take any locks in here anyway, and don't do any heavy tasks, as doing so
- * would slow down all the package broadcasts.
- */
- public abstract void onPackageBroadcast(Intent intent);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 8d3940c..ad11307 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -201,12 +201,16 @@
* Create a new Resources object on top of an existing set of assets in an
* AssetManager.
*
+ * @deprecated Resources should not be constructed by apps.
+ * See {@link android.content.Context#createConfigurationContext(Configuration)}.
+ *
* @param assets Previously created AssetManager.
* @param metrics Current display metrics to consider when
* selecting/computing resource values.
* @param config Desired device configuration to consider when
* selecting/computing resource values (optional).
*/
+ @Deprecated
public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
this(null);
mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
@@ -1762,7 +1766,10 @@
/**
* Store the newly updated configuration.
+ *
+ * @deprecated See {@link android.content.Context#createConfigurationContext(Configuration)}.
*/
+ @Deprecated
public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
updateConfiguration(config, metrics, null);
}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 92134ee..1e44a5c 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -49,6 +49,10 @@
attrs.mLength = len;
attrs.mRecycled = false;
+ // Reset the assets, which may have changed due to configuration changes
+ // or further resource loading.
+ attrs.mAssets = res.getAssets();
+
final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
if (attrs.mData.length >= fullLen) {
return attrs;
@@ -66,7 +70,7 @@
private final Resources mResources;
private final DisplayMetrics mMetrics;
- private final AssetManager mAssets;
+ private AssetManager mAssets;
private boolean mRecycled;
@@ -1086,6 +1090,7 @@
// These may have been set by the client.
mXml = null;
mTheme = null;
+ mAssets = null;
mResources.mTypedArrayPool.release(this);
}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 43e596f..062c958 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -16,6 +16,11 @@
package android.hardware.location;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -53,10 +58,14 @@
private static final int PRE_LOADED_APP_MEM_REQ = 0;
private static final int MSG_HEADER_SIZE = 4;
- private static final int MSG_FIELD_TYPE = 0;
- private static final int MSG_FIELD_VERSION = 1;
- private static final int MSG_FIELD_HUB_HANDLE = 2;
- private static final int MSG_FIELD_APP_INSTANCE = 3;
+ private static final int HEADER_FIELD_MSG_TYPE = 0;
+ private static final int HEADER_FIELD_MSG_VERSION = 1;
+ private static final int HEADER_FIELD_HUB_HANDLE = 2;
+ private static final int HEADER_FIELD_APP_INSTANCE = 3;
+
+ private static final int HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
+ private static final int HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
+ private static final int MSG_LOAD_APP_HEADER_SIZE = MSG_HEADER_SIZE + 2;
private static final int OS_APP_INSTANCE = -1;
@@ -146,15 +155,23 @@
return -1;
}
- int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
- msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
- msgHeader[MSG_FIELD_VERSION] = 0;
- msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
+ int[] msgHeader = new int[MSG_LOAD_APP_HEADER_SIZE];
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = contextHubHandle;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
+ msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
- if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
+ long appId = app.getAppId();
+
+ msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
+ msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
+
+ int errVal = nativeSendMessage(msgHeader, app.getAppBinary());
+ if (errVal != 0) {
+ Log.e(TAG, "Send Message returns error" + contextHubHandle);
return -1;
}
+
// Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
return 0;
}
@@ -169,12 +186,14 @@
// Call Native interface here
int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
- msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
- msgHeader[MSG_FIELD_VERSION] = 0;
- msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppInstanceHandle;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
+ msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_UNLOAD_NANO_APP;
- if (nativeSendMessage(msgHeader, null) != 0) {
+ byte msg[] = new byte[0];
+
+ if (nativeSendMessage(msgHeader, msg) != 0) {
return -1;
}
@@ -222,10 +241,10 @@
checkPermissions();
int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
- msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
- msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
- msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppHandle;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = msg.getVersion();
+ msgHeader[HEADER_FIELD_MSG_TYPE] = msg.getMsgType();
return nativeSendMessage(msgHeader, msg.getData());
}
@@ -269,15 +288,17 @@
Log.v(TAG, "No message callbacks registered.");
return 0;
}
- ContextHubMessage message =
- new ContextHubMessage(header[MSG_FIELD_TYPE], header[MSG_FIELD_VERSION], data);
+
+ ContextHubMessage msg = new ContextHubMessage(header[HEADER_FIELD_MSG_TYPE],
+ header[HEADER_FIELD_MSG_VERSION],
+ data);
for (int i = 0; i < callbacksCount; ++i) {
IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
try {
callback.onMessageReceipt(
- header[MSG_FIELD_HUB_HANDLE],
- header[MSG_FIELD_APP_INSTANCE],
- message);
+ header[HEADER_FIELD_HUB_HANDLE],
+ header[HEADER_FIELD_APP_INSTANCE],
+ msg);
} catch (RemoteException e) {
Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
continue;
@@ -308,12 +329,20 @@
return 0;
}
+ private int deleteAppInstance(int appInstanceHandle) {
+ if (mNanoAppHash.remove(appInstanceHandle) == null) {
+ return -1;
+ }
+
+ return 0;
+ }
+
private void sendVrStateChangeMessageToApp(NanoAppInstanceInfo app, boolean vrModeEnabled) {
int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_TYPE] = 0;
- msgHeader[MSG_FIELD_VERSION] = 0;
- msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
- msgHeader[MSG_FIELD_APP_INSTANCE] = app.getHandle();
+ msgHeader[HEADER_FIELD_MSG_TYPE] = 0;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = app.getHandle();
byte[] data = new byte[1];
data[0] = (byte) ((vrModeEnabled) ? 1 : 0);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 384ab1c..6e74f14 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -103,7 +103,7 @@
private boolean isIPv6ULA() {
if (address != null && address instanceof Inet6Address) {
byte[] bytes = address.getAddress();
- return ((bytes[0] & (byte)0xfc) == (byte)0xfc);
+ return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
}
return false;
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 847d82b..4501f7b 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -284,6 +284,15 @@
};
/**
+ * Returns true iff. the contained NetworkRequest is of type LISTEN.
+ *
+ * @hide
+ */
+ public boolean isListen() {
+ return type == Type.LISTEN;
+ }
+
+ /**
* Returns true iff. the contained NetworkRequest is one that:
*
* - should be associated with at most one satisfying network
diff --git a/core/java/android/net/network-policy-restrictions.md b/core/java/android/net/network-policy-restrictions.md
index fe13f7a..63ce1a2 100644
--- a/core/java/android/net/network-policy-restrictions.md
+++ b/core/java/android/net/network-policy-restrictions.md
@@ -29,8 +29,8 @@
| **DS** | *WL* | ok | blk | ok | ok |
| **ON** | *!WL* | blk | blk | blk | blk |
| | *BL* | blk | blk | blk | blk |
-| **DS** | *WL* | blk | ok | ok | ok |
-| **OFF** | *!WL* | blk | ok | ok | ok |
+| **DS** | *WL* | blk | blk | ok | ok |
+| **OFF** | *!WL* | blk | blk | ok | ok |
| | *BL* | blk | blk | blk | blk |
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 80927f3..8d6d9ed 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -286,6 +286,11 @@
}
/** {@hide} */
+ public static File getReferenceProfile(String packageName) {
+ return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
+ }
+
+ /** {@hide} */
public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
return buildPath(getDataProfilesDeDirectory(userId), packageName);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index bb7e5ad..edd8a39 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -912,6 +912,7 @@
* @hide
*/
public static final boolean isThreadInProcess(int tid, int pid) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
if (Os.access("/proc/" + tid + "/task/" + pid, OsConstants.F_OK)) {
return true;
@@ -920,6 +921,9 @@
}
} catch (Exception e) {
return false;
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
}
+
}
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5dea3d6..b9193b2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -603,6 +603,17 @@
public static final String DISALLOW_SET_USER_ICON = "no_set_user_icon";
/**
+ * Specifies if a user is not allowed to enable the oem unlock setting. The default value is
+ * <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ * @hide
+ */
+ public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
+
+ /**
* Allows apps in the parent profile to handle web links from the managed profile.
*
* This user restriction has an effect only in a managed profile.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index b0ea99c..c51a613 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -235,7 +235,6 @@
* @see #FLAG_DIR_PREFERS_GRID
* @see #FLAG_DIR_PREFERS_LAST_MODIFIED
* @see #FLAG_VIRTUAL_DOCUMENT
- * @see #FLAG_ARCHIVE
* @see #FLAG_SUPPORTS_COPY
* @see #FLAG_SUPPORTS_MOVE
* @see #FLAG_SUPPORTS_REMOVE
@@ -326,7 +325,7 @@
* Flag indicating that a document can be renamed.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#renameDocument(ContentProviderClient, Uri,
+ * @see DocumentsContract#renameDocument(ContentResolver, Uri,
* String)
* @see DocumentsProvider#renameDocument(String, String)
*/
@@ -337,7 +336,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#copyDocument(ContentProviderClient, Uri, Uri)
+ * @see DocumentsContract#copyDocument(ContentResolver, Uri, Uri)
* @see DocumentsProvider#copyDocument(String, String)
*/
public static final int FLAG_SUPPORTS_COPY = 1 << 7;
@@ -347,7 +346,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#moveDocument(ContentProviderClient, Uri, Uri, Uri)
+ * @see DocumentsContract#moveDocument(ContentResolver, Uri, Uri, Uri)
* @see DocumentsProvider#moveDocument(String, String, String)
*/
public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
@@ -368,7 +367,7 @@
* Flag indicating that a document can be removed from a parent.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#removeDocument(ContentProviderClient, Uri, Uri)
+ * @see DocumentsContract#removeDocument(ContentResolver, Uri, Uri)
* @see DocumentsProvider#removeDocument(String, String)
*/
public static final int FLAG_SUPPORTS_REMOVE = 1 << 10;
@@ -875,7 +874,7 @@
* Test if the given URI represents a {@link Document} tree.
*
* @see #buildTreeDocumentUri(String, String)
- * @see #getTreeDocumentId(Uri, String)
+ * @see #getTreeDocumentId(Uri)
*/
public static boolean isTreeUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a3fc71e..9b3b03f 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5298,15 +5298,6 @@
"accessibility_display_daltonizer";
/**
- * Float list that specifies the color matrix to apply to
- * the display. Valid values are defined in AccessibilityManager.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_COLOR_MATRIX =
- "accessibility_display_color_matrix";
-
- /**
* Setting that specifies whether automatic click when the mouse pointer stops moving is
* enabled.
*
@@ -6343,7 +6334,6 @@
USB_MASS_STORAGE_ENABLED, // moved to global
ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
ACCESSIBILITY_DISPLAY_DALTONIZER,
- ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
@@ -6399,7 +6389,11 @@
PREFERRED_TTY_MODE,
ENHANCED_VOICE_PRIVACY_ENABLED,
TTY_MODE_ENABLED,
- INCALL_POWER_BUTTON_BEHAVIOR
+ INCALL_POWER_BUTTON_BEHAVIOR,
+ NIGHT_DISPLAY_CUSTOM_START_TIME,
+ NIGHT_DISPLAY_CUSTOM_END_TIME,
+ NIGHT_DISPLAY_AUTO_MODE,
+ NIGHT_DISPLAY_ACTIVATED
};
/**
@@ -9123,15 +9117,6 @@
public static final String ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot";
/**
- * Whether toggling OEM unlock is disallowed. If disallowed, it is not possible to enable or
- * disable OEM unlock.
- * <p>
- * Type: int (0: allow OEM unlock setting. 1: disallow OEM unlock)
- * @hide
- */
- public static final String OEM_UNLOCK_DISALLOWED = "oem_unlock_disallowed";
-
- /**
* The maximum allowed notification enqueue rate in Hertz.
*
* Should be a float, and includes both posts and updates.
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1d9784b..038f2ac 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -20,6 +20,8 @@
import android.app.NotificationManager.Policy;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Parcel;
@@ -118,6 +120,7 @@
private static final String RULE_ATT_ZEN = "zen";
private static final String RULE_ATT_CONDITION_ID = "conditionId";
private static final String RULE_ATT_CREATION_TIME = "creationTime";
+ private static final String RULE_ATT_ENABLER = "enabler";
public boolean allowCalls = DEFAULT_ALLOW_CALLS;
public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS;
@@ -502,6 +505,7 @@
rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0);
+ rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
rt.condition = readConditionXml(parser);
return rt;
}
@@ -520,6 +524,9 @@
out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
}
out.attribute(null, RULE_ATT_CREATION_TIME, Long.toString(rule.creationTime));
+ if (rule.enabler != null) {
+ out.attribute(null, RULE_ATT_ENABLER, rule.enabler);
+ }
if (rule.condition != null) {
writeConditionXml(rule.condition, out);
}
@@ -989,6 +996,25 @@
return UUID.randomUUID().toString().replace("-", "");
}
+ private static String getOwnerCaption(Context context, String owner) {
+ final PackageManager pm = context.getPackageManager();
+ try {
+ final ApplicationInfo info = pm.getApplicationInfo(owner, 0);
+ if (info != null) {
+ final CharSequence seq = info.loadLabel(pm);
+ if (seq != null) {
+ final String str = seq.toString().trim();
+ if (str.length() > 0) {
+ return str;
+ }
+ }
+ }
+ } catch (Throwable e) {
+ Slog.w(TAG, "Error loading owner caption", e);
+ }
+ return "";
+ }
+
public static String getConditionSummary(Context context, ZenModeConfig config,
int userHandle, boolean shortVersion) {
return getConditionLine(context, config, userHandle, false /*useLine1*/, shortVersion);
@@ -997,23 +1023,28 @@
private static String getConditionLine(Context context, ZenModeConfig config,
int userHandle, boolean useLine1, boolean shortVersion) {
if (config == null) return "";
+ String summary = "";
if (config.manualRule != null) {
final Uri id = config.manualRule.conditionId;
- if (id == null) {
- return context.getString(com.android.internal.R.string.zen_mode_forever);
+ if (config.manualRule.enabler != null) {
+ summary = getOwnerCaption(context, config.manualRule.enabler);
+ } else {
+ if (id == null) {
+ summary = context.getString(com.android.internal.R.string.zen_mode_forever);
+ } else {
+ final long time = tryParseCountdownConditionId(id);
+ Condition c = config.manualRule.condition;
+ if (time > 0) {
+ final long now = System.currentTimeMillis();
+ final long span = time - now;
+ c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS),
+ userHandle, shortVersion);
+ }
+ final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
+ summary = TextUtils.isEmpty(rt) ? "" : rt;
+ }
}
- final long time = tryParseCountdownConditionId(id);
- Condition c = config.manualRule.condition;
- if (time > 0) {
- final long now = System.currentTimeMillis();
- final long span = time - now;
- c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS),
- userHandle, shortVersion);
- }
- final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
- return TextUtils.isEmpty(rt) ? "" : rt;
}
- String summary = "";
for (ZenRule automaticRule : config.automaticRules.values()) {
if (automaticRule.isAutomaticActive()) {
if (summary.isEmpty()) {
@@ -1023,6 +1054,7 @@
.getString(R.string.zen_mode_rule_name_combination, summary,
automaticRule.name);
}
+
}
}
return summary;
@@ -1038,6 +1070,7 @@
public ComponentName component; // optional
public String id; // required for automatic (unique)
public long creationTime; // required for automatic
+ public String enabler; // package name, only used for manual rules.
public ZenRule() { }
@@ -1055,6 +1088,9 @@
id = source.readString();
}
creationTime = source.readLong();
+ if (source.readInt() == 1) {
+ enabler = source.readString();
+ }
}
@Override
@@ -1083,6 +1119,12 @@
dest.writeInt(0);
}
dest.writeLong(creationTime);
+ if (enabler != null) {
+ dest.writeInt(1);
+ dest.writeString(enabler);
+ } else {
+ dest.writeInt(0);
+ }
}
@Override
@@ -1097,6 +1139,7 @@
.append(",component=").append(component)
.append(",id=").append(id)
.append(",creationTime=").append(creationTime)
+ .append(",enabler=").append(enabler)
.append(']').toString();
}
@@ -1143,6 +1186,9 @@
if (creationTime != to.creationTime) {
d.addLine(item, "creationTime", creationTime, to.creationTime);
}
+ if (enabler != to.enabler) {
+ d.addLine(item, "enabler", enabler, to.enabler);
+ }
}
@Override
@@ -1158,13 +1204,14 @@
&& Objects.equals(other.condition, condition)
&& Objects.equals(other.component, component)
&& Objects.equals(other.id, id)
- && other.creationTime == creationTime;
+ && other.creationTime == creationTime
+ && Objects.equals(other.enabler, enabler);
}
@Override
public int hashCode() {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
- component, id, creationTime);
+ component, id, creationTime, enabler);
}
public boolean isAutomaticActive() {
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index bf96357..d03ff93 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -23,16 +23,16 @@
* @hide
*/
interface IQSService {
- Tile getTile(in ComponentName component);
- void updateQsTile(in Tile tile);
- void updateStatusIcon(in Tile tile, in Icon icon,
+ Tile getTile(in IBinder tile);
+ void updateQsTile(in Tile tile, in IBinder service);
+ void updateStatusIcon(in IBinder tile, in Icon icon,
String contentDescription);
- void onShowDialog(in Tile tile);
- void onStartActivity(in Tile tile);
+ void onShowDialog(in IBinder tile);
+ void onStartActivity(in IBinder tile);
boolean isLocked();
boolean isSecure();
- void startUnlockAndRun(in Tile tile);
+ void startUnlockAndRun(in IBinder tile);
- void onDialogHidden(in Tile tile);
- void onStartSuccessful(in Tile tile);
+ void onDialogHidden(in IBinder tile);
+ void onStartSuccessful(in IBinder tile);
}
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 3d7d53e..4b81a72 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -15,8 +15,8 @@
*/
package android.service.quicksettings;
-import android.content.ComponentName;
import android.graphics.drawable.Icon;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -59,7 +59,7 @@
*/
public static final int STATE_ACTIVE = 2;
- private ComponentName mComponentName;
+ private IBinder mToken;
private Icon mIcon;
private CharSequence mLabel;
private CharSequence mContentDescription;
@@ -78,29 +78,15 @@
/**
* @hide
*/
- public Tile(ComponentName componentName) {
- mComponentName = componentName;
+ public Tile() {
}
/**
* @hide
*/
- public void setService(IQSService service) {
+ public void setService(IQSService service, IBinder stub) {
mService = service;
- }
-
- /**
- * @hide
- */
- public ComponentName getComponentName() {
- return mComponentName;
- }
-
- /**
- * @hide
- */
- public IQSService getQsService() {
- return mService;
+ mToken = stub;
}
/**
@@ -193,7 +179,7 @@
*/
public void updateTile() {
try {
- mService.updateQsTile(this);
+ mService.updateQsTile(this, mToken);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't update tile");
}
@@ -201,12 +187,6 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- if (mComponentName != null) {
- dest.writeByte((byte) 1);
- mComponentName.writeToParcel(dest, flags);
- } else {
- dest.writeByte((byte) 0);
- }
if (mIcon != null) {
dest.writeByte((byte) 1);
mIcon.writeToParcel(dest, flags);
@@ -220,11 +200,6 @@
private void readFromParcel(Parcel source) {
if (source.readByte() != 0) {
- mComponentName = ComponentName.CREATOR.createFromParcel(source);
- } else {
- mComponentName = null;
- }
- if (source.readByte() != 0) {
mIcon = Icon.CREATOR.createFromParcel(source);
} else {
mIcon = null;
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 50411ab..887f4b6 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -123,6 +123,11 @@
/**
* @hide
*/
+ public static final String EXTRA_TOKEN = "token";
+
+ /**
+ * @hide
+ */
public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
private final H mHandler = new H(Looper.getMainLooper());
@@ -132,6 +137,7 @@
private IBinder mToken;
private IQSService mService;
private Runnable mUnlockRunnable;
+ private IBinder mTileToken;
@Override
public void onDestroy() {
@@ -197,7 +203,7 @@
public final void setStatusIcon(Icon icon, String contentDescription) {
if (mService != null) {
try {
- mService.updateStatusIcon(mTile, icon, contentDescription);
+ mService.updateStatusIcon(mTileToken, icon, contentDescription);
} catch (RemoteException e) {
}
}
@@ -224,14 +230,14 @@
@Override
public void onViewDetachedFromWindow(View v) {
try {
- mService.onDialogHidden(getQsTile());
+ mService.onDialogHidden(mTileToken);
} catch (RemoteException e) {
}
}
});
dialog.show();
try {
- mService.onShowDialog(mTile);
+ mService.onShowDialog(mTileToken);
} catch (RemoteException e) {
}
}
@@ -246,7 +252,7 @@
public final void unlockAndRun(Runnable runnable) {
mUnlockRunnable = runnable;
try {
- mService.startUnlockAndRun(mTile);
+ mService.startUnlockAndRun(mTileToken);
} catch (RemoteException e) {
}
}
@@ -292,7 +298,7 @@
public final void startActivityAndCollapse(Intent intent) {
startActivity(intent);
try {
- mService.onStartActivity(mTile);
+ mService.onStartActivity(mTileToken);
} catch (RemoteException e) {
}
}
@@ -311,14 +317,14 @@
@Override
public IBinder onBind(Intent intent) {
mService = IQSService.Stub.asInterface(intent.getIBinderExtra(EXTRA_SERVICE));
+ mTileToken = intent.getIBinderExtra(EXTRA_TOKEN);
try {
- ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
- mTile = mService.getTile(component);
+ mTile = mService.getTile(mTileToken);
} catch (RemoteException e) {
throw new RuntimeException("Unable to reach IQSService", e);
}
if (mTile != null) {
- mTile.setService(mService);
+ mTile.setService(mService, mTileToken);
mHandler.sendEmptyMessage(H.MSG_START_SUCCESS);
}
return new IQSTileService.Stub() {
@@ -403,7 +409,7 @@
break;
case MSG_START_SUCCESS:
try {
- mService.onStartSuccessful(mTile);
+ mService.onStartSuccessful(mTileToken);
} catch (RemoteException e) {
}
break;
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 34e6f04..c766660 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -346,14 +346,44 @@
gc();
}
- for (int i = 0; i < mSize; i++)
- if (mValues[i] == value)
+ for (int i = 0; i < mSize; i++) {
+ if (mValues[i] == value) {
return i;
+ }
+ }
return -1;
}
/**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * <p>Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ * <p>Note also that this method uses {@code equals} unlike {@code indexOfValue}.
+ */
+ public int indexOfValueByValue(E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ for (int i = 0; i < mSize; i++) {
+ if (value == null) {
+ if (mValues[i] == null) {
+ return i;
+ }
+ } else {
+ if (value.equals(mValues[i])) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
* Removes all key-value mappings from this SparseArray.
*/
public void clear() {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e3ff54d..9bc0bb4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -306,6 +306,11 @@
boolean isRotationFrozen();
/**
+ * Screenshot the current wallpaper layer, including the whole screen.
+ */
+ Bitmap screenshotWallpaper();
+
+ /**
* Used only for assist -- request a screenshot of the current application.
*/
boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4818910..292e3f5 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -137,7 +137,7 @@
handleGetNewSurface();
} break;
case UPDATE_WINDOW_MSG: {
- updateWindow(false, false);
+ updateWindow();
} break;
}
}
@@ -147,7 +147,7 @@
= new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
- updateWindow(false, false);
+ updateWindow();
}
};
@@ -157,7 +157,7 @@
public boolean onPreDraw() {
// reposition ourselves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
- updateWindow(false, false);
+ updateWindow();
return true;
}
};
@@ -248,7 +248,7 @@
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow(false, false);
+ updateWindow();
}
@Override
@@ -266,7 +266,7 @@
requestLayout();
}
mRequestedVisible = newRequestedVisible;
- updateWindow(false, false);
+ updateWindow();
}
@Override
@@ -279,7 +279,7 @@
}
mRequestedVisible = false;
- updateWindow(false, false);
+ updateWindow();
mHaveFrame = false;
if (mWindow != null) {
try {
@@ -310,7 +310,7 @@
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean result = super.setFrame(left, top, right, bottom);
- updateWindow(false, false);
+ updateWindow();
return result;
}
@@ -436,7 +436,7 @@
}
/** @hide */
- protected void updateWindow(boolean force, boolean redrawNeeded) {
+ protected void updateWindow() {
if (!mHaveFrame) {
return;
}
@@ -461,8 +461,10 @@
final boolean layoutSizeChanged = getWidth() != mLayout.width
|| getHeight() != mLayout.height;
- if (force || creating || formatChanged || sizeChanged || visibleChanged
- || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
+ boolean redrawNeeded = false;
+
+ if (creating || formatChanged || sizeChanged || visibleChanged
+ || mUpdateWindowNeeded || mReportDrawNeeded) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -499,7 +501,7 @@
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
- if (!creating && !force && !sizeChanged) {
+ if (!creating && !sizeChanged) {
mLayout.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
} else {
@@ -783,7 +785,7 @@
}
void handleGetNewSurface() {
- updateWindow(false, false);
+ updateWindow();
}
/**
@@ -912,7 +914,7 @@
mRequestedFormat = format;
if (mWindow != null) {
- updateWindow(false, false);
+ updateWindow();
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 606cf24..397bd07 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3746,7 +3746,8 @@
/**
* Flag indicating that a drag can cross window boundaries. When
* {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called
- * with this flag set, all visible applications will be able to participate
+ * with this flag set, all visible applications with targetSdkVersion >=
+ * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate
* in the drag operation and receive the dragged content.
*
* If this is the only flag set, then the drag recipient will only have access to text data
@@ -4216,25 +4217,25 @@
setAlpha(a.getFloat(attr, 1f));
break;
case com.android.internal.R.styleable.View_transformPivotX:
- setPivotX(a.getDimensionPixelOffset(attr, 0));
+ setPivotX(a.getDimension(attr, 0));
break;
case com.android.internal.R.styleable.View_transformPivotY:
- setPivotY(a.getDimensionPixelOffset(attr, 0));
+ setPivotY(a.getDimension(attr, 0));
break;
case com.android.internal.R.styleable.View_translationX:
- tx = a.getDimensionPixelOffset(attr, 0);
+ tx = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_translationY:
- ty = a.getDimensionPixelOffset(attr, 0);
+ ty = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_translationZ:
- tz = a.getDimensionPixelOffset(attr, 0);
+ tz = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_elevation:
- elevation = a.getDimensionPixelOffset(attr, 0);
+ elevation = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_rotation:
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e8663e4..495b032 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1731,7 +1731,7 @@
}
boolean hwInitialized = false;
- boolean framesChanged = false;
+ boolean contentInsetsChanged = false;
boolean hadSurface = mSurface.isValid();
try {
@@ -1771,7 +1771,7 @@
final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
mAttachInfo.mOverscanInsets);
- boolean contentInsetsChanged = !mPendingContentInsets.equals(
+ contentInsetsChanged = !mPendingContentInsets.equals(
mAttachInfo.mContentInsets);
final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
mAttachInfo.mVisibleInsets);
@@ -1821,19 +1821,6 @@
+ mAttachInfo.mVisibleInsets);
}
- // If any of the insets changed, do a forceLayout on the view so that the
- // measure cache is cleared. We might have a pending MSG_RESIZED_REPORT
- // that is supposed to take care of it, but since pending insets are
- // already modified here, it won't detect the frame change after this.
- framesChanged = overscanInsetsChanged
- || contentInsetsChanged
- || stableInsetsChanged
- || visibleInsetsChanged
- || outsetsChanged;
- if (mAdded && mView != null && framesChanged) {
- forceLayout(mView);
- }
-
if (!hadSurface) {
if (mSurface.isValid()) {
// If we are creating a new surface, then we need to
@@ -2017,7 +2004,7 @@
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || framesChanged ||
+ || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
@@ -2026,7 +2013,7 @@
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
- + " framesChanged=" + framesChanged);
+ + " coveredInsetsChanged=" + contentInsetsChanged);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -5515,6 +5502,15 @@
if (mView != null && mAdded) {
final int what = event.mAction;
+ // Cache the drag description when the operation starts, then fill it in
+ // on subsequent calls as a convenience
+ if (what == DragEvent.ACTION_DRAG_STARTED) {
+ mCurrentDragView = null; // Start the current-recipient tracking
+ mDragDescription = event.mClipDescription;
+ } else {
+ event.mClipDescription = mDragDescription;
+ }
+
if (what == DragEvent.ACTION_DRAG_EXITED) {
// A direct EXITED event means that the window manager knows we've just crossed
// a window boundary, so the current drag target within this one must have
@@ -5522,15 +5518,6 @@
// for now.
mView.dispatchDragEvent(event);
} else {
- // Cache the drag description when the operation starts, then fill it in
- // on subsequent calls as a convenience
- if (what == DragEvent.ACTION_DRAG_STARTED) {
- mCurrentDragView = null; // Start the current-recipient tracking
- mDragDescription = event.mClipDescription;
- } else {
- event.mClipDescription = mDragDescription;
- }
-
// For events with a [screen] location, translate into window coordinates
if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
mDragPoint.set(event.mX, event.mY);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index b7f57cb..167d526 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1547,7 +1547,7 @@
}
// Let the window manager know to align the top to y.
- outParams.gravity = Gravity.LEFT | Gravity.TOP;
+ outParams.gravity = computeGravity();
outParams.width = width;
outParams.height = height;
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 7762675..4074166 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -24,7 +24,10 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
+import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -326,13 +329,6 @@
}
private static class TN extends ITransientNotification.Stub {
- final Runnable mShow = new Runnable() {
- @Override
- public void run() {
- handleShow();
- }
- };
-
final Runnable mHide = new Runnable() {
@Override
public void run() {
@@ -343,7 +339,13 @@
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
- final Handler mHandler = new Handler();
+ final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ IBinder token = (IBinder) msg.obj;
+ handleShow(token);
+ }
+ };
int mGravity;
int mX, mY;
@@ -379,9 +381,9 @@
* schedule handleShow into the right thread
*/
@Override
- public void show() {
+ public void show(IBinder windowToken) {
if (localLOGV) Log.v(TAG, "SHOW: " + this);
- mHandler.post(mShow);
+ mHandler.obtainMessage(0, windowToken).sendToTarget();
}
/**
@@ -393,7 +395,7 @@
mHandler.post(mHide);
}
- public void handleShow() {
+ public void handleShow(IBinder windowToken) {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
if (mView != mNextView) {
@@ -424,6 +426,7 @@
mParams.packageName = packageName;
mParams.removeTimeoutMilliseconds = mDuration ==
Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
+ mParams.token = windowToken;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java
index dc3832a..cc2c4cf 100644
--- a/core/java/com/android/internal/util/FastPrintWriter.java
+++ b/core/java/com/android/internal/util/FastPrintWriter.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.internal.util;
import android.util.Log;
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 48bcc09..77452ca 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -341,6 +341,20 @@
}
/**
+ * Lighten a color by a specified value
+ * @param baseColor the base color to lighten
+ * @param amount the amount to lighten the color from 0 to 100. This corresponds to the L
+ * increase in the LAB color space.
+ * @return the lightened color
+ */
+ public static int lightenColor(int baseColor, int amount) {
+ final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
+ ColorUtilsFromCompat.colorToLAB(baseColor, result);
+ result[0] = Math.min(100, result[0] + amount);
+ return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
+ }
+
+ /**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
private static class ColorUtilsFromCompat {
@@ -434,7 +448,7 @@
* Convert RGB components to its CIE Lab representative components.
*
* <ul>
- * <li>outLab[0] is L [0 ...1)</li>
+ * <li>outLab[0] is L [0 ...100)</li>
* <li>outLab[1] is a [-128...127)</li>
* <li>outLab[2] is b [-128...127)</li>
* </ul>
@@ -516,7 +530,7 @@
* 2° Standard Observer (1931).</p>
*
* <ul>
- * <li>outLab[0] is L [0 ...1)</li>
+ * <li>outLab[0] is L [0 ...100)</li>
* <li>outLab[1] is a [-128...127)</li>
* <li>outLab[2] is b [-128...127)</li>
* </ul>
@@ -634,7 +648,7 @@
: (XYZ_KAPPA * component + 16) / 116;
}
- private static double[] getTempDouble3Array() {
+ public static double[] getTempDouble3Array() {
double[] result = TEMP_ARRAY.get();
if (result == null) {
result = new double[3];
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 31ab26f..831c646 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -26,6 +26,7 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.util.DisplayMetrics;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
@@ -209,11 +210,9 @@
}
private boolean isContentRectWithinBounds() {
- mScreenRect.set(
- 0,
- 0,
- mContext.getResources().getDisplayMetrics().widthPixels,
- mContext.getResources().getDisplayMetrics().heightPixels);
+ DisplayMetrics metrics = mContext.getApplicationContext()
+ .getResources().getDisplayMetrics();
+ mScreenRect.set(0, 0, metrics.widthPixels, metrics.heightPixels);
return intersectsClosed(mContentRectOnScreen, mScreenRect)
&& intersectsClosed(mContentRectOnScreen, mViewRectOnScreen);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 04654f3..a989b52 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -149,7 +149,7 @@
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
private UserManager mUserManager;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler;
/**
* Use {@link TrustManager#isTrustUsuallyManaged(int)}.
@@ -231,6 +231,9 @@
public LockPatternUtils(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
+
+ Looper looper = Looper.myLooper();
+ mHandler = looper != null ? new Handler(looper) : null;
}
private ILockSettings getLockSettings() {
@@ -1512,6 +1515,10 @@
if (callback == null) {
return null;
} else {
+ if (mHandler == null) {
+ throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
+ + " to use progress callbacks.");
+ }
return new ICheckCredentialProgressCallback.Stub() {
@Override
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 9dd118c..073aac5 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -17,11 +17,13 @@
package com.android.internal.widget;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
+import android.view.RemotableViewMethod;
import android.view.View;
-import android.view.ViewGroup;
+import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
@@ -33,11 +35,14 @@
* the remaining available width, and the last action consumes the remaining space.
*/
@RemoteViews.RemoteView
-public class NotificationActionListLayout extends ViewGroup {
+public class NotificationActionListLayout extends LinearLayout {
private int mTotalWidth = 0;
private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
+ private boolean mMeasureLinearly;
+ private int mDefaultPaddingEnd;
+ private Drawable mDefaultBackground;
public NotificationActionListLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -45,6 +50,10 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mMeasureLinearly) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
final int N = getChildCount();
int textViews = 0;
int otherViews = 0;
@@ -186,6 +195,10 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mMeasureLinearly) {
+ super.onLayout(changed, left, top, right, bottom);
+ return;
+ }
final boolean isLayoutRtl = isLayoutRtl();
final int paddingTop = mPaddingTop;
@@ -241,26 +254,24 @@
}
@Override
- public LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new MarginLayoutParams(getContext(), attrs);
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDefaultPaddingEnd = getPaddingEnd();
+ mDefaultBackground = getBackground();
}
- @Override
- protected LayoutParams generateDefaultLayoutParams() {
- return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
- }
-
- @Override
- protected LayoutParams generateLayoutParams(LayoutParams p) {
- if (p instanceof MarginLayoutParams) {
- return new MarginLayoutParams((MarginLayoutParams)p);
- }
- return new MarginLayoutParams(p);
- }
-
- @Override
- protected boolean checkLayoutParams(LayoutParams p) {
- return p instanceof MarginLayoutParams;
+ /**
+ * Set whether the list is in a mode where some actions are emphasized. This will trigger an
+ * equal measuring where all actions are full height and change a few parameters like
+ * the padding.
+ */
+ @RemotableViewMethod
+ public void setEmphasizedMode(boolean emphasizedMode) {
+ mMeasureLinearly = emphasizedMode;
+ setPaddingRelative(getPaddingStart(), getPaddingTop(),
+ emphasizedMode ? 0 : mDefaultPaddingEnd, getPaddingBottom());
+ setBackground(emphasizedMode ? null : mDefaultBackground);
+ requestLayout();
}
public static final Comparator<Pair<Integer, TextView>> MEASURE_ORDER_COMPARATOR
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 06188d2..695aed5 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -72,7 +72,7 @@
case SkEncodedFormat::kWBMP_SkEncodedFormat:
mimeType = "image/vnd.wap.wbmp";
break;
- case SkEncodedFormat::kRAW_SkEncodedFormat:
+ case SkEncodedFormat::kDNG_SkEncodedFormat:
mimeType = "image/x-adobe-dng";
break;
default:
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 5baa8f8..a5e94a10 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -10,7 +10,6 @@
#include "SkMallocPixelRef.h"
#include "SkPoint.h"
#include "SkRect.h"
-#include "SkImageDecoder.h"
#include <jni.h>
#include <hwui/Canvas.h>
diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp
index 8a84a35..1ea5650 100644
--- a/core/jni/android/graphics/NinePatchPeeker.cpp
+++ b/core/jni/android/graphics/NinePatchPeeker.cpp
@@ -17,7 +17,6 @@
#include "NinePatchPeeker.h"
#include "SkBitmap.h"
-#include "SkImageDecoder.h"
using namespace android;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index b586c43..67c94fb 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -769,6 +769,21 @@
return false;
}
+ // Don't count glyphs that are the recommended "space" glyph and are zero width.
+ // This logic makes assumptions about HarfBuzz layout, but does correctly handle
+ // cases where ligatures form and zero width space glyphs are left in as
+ // placeholders.
+ static size_t countNonSpaceGlyphs(const minikin::Layout& layout) {
+ size_t count = 0;
+ static unsigned int kSpaceGlyphId = 3;
+ for (size_t i = 0; i < layout.nGlyphs(); i++) {
+ if (layout.getGlyphId(i) != kSpaceGlyphId || layout.getCharAdvance(i) != 0.0) {
+ count++;
+ }
+ }
+ return count;
+ }
+
// Returns true if the given string is exact one pair of regional indicators.
static bool isFlag(const jchar* str, size_t length) {
const jchar RI_LEAD_SURROGATE = 0xD83C;
@@ -832,7 +847,7 @@
minikin::Layout layout;
MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
str.size());
- size_t nGlyphs = layout.nGlyphs();
+ size_t nGlyphs = countNonSpaceGlyphs(layout);
if (nGlyphs != 1 && nChars > 1) {
// multiple-character input, and was not a ligature
// TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 7d0c39c..31567f7 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -1,5 +1,5 @@
#include "CreateJavaOutputStreamAdaptor.h"
-#include "SkJpegUtility.h"
+#include "SkJPEGWriteUtility.h"
#include "YuvToJpegEncoder.h"
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index d535193..acf9996 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -88,7 +88,7 @@
}
void write(SkWStream* stream) {
- SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(stream));
+ sk_sp<SkDocument> document = SkDocument::MakePDF(stream);
for (unsigned i = 0; i < mPages.size(); i++) {
PageRecord* page = mPages[i];
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index a56eba6..9515a0e 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -21,28 +21,34 @@
#include <inttypes.h>
#include <jni.h>
-#include <queue>
-#include <unordered_map>
+#include <mutex>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unordered_map>
+#include <queue>
#include <cutils/log.h>
#include "JNIHelp.h"
#include "core_jni_helpers.h"
-static constexpr int OS_APP_ID=-1;
+static constexpr int OS_APP_ID = -1;
+static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
-static constexpr int MIN_APP_ID=1;
-static constexpr int MAX_APP_ID=128;
+static constexpr int MIN_APP_ID = 1;
+static constexpr int MAX_APP_ID = 128;
-static constexpr size_t MSG_HEADER_SIZE=4;
-static constexpr int HEADER_FIELD_MSG_TYPE=0;
-//static constexpr int HEADER_FIELD_MSG_VERSION=1;
-static constexpr int HEADER_FIELD_HUB_HANDLE=2;
-static constexpr int HEADER_FIELD_APP_INSTANCE=3;
+static constexpr size_t MSG_HEADER_SIZE = 4;
+static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
+static constexpr size_t HEADER_FIELD_MSG_VERSION = 1;
+static constexpr size_t HEADER_FIELD_HUB_HANDLE = 2;
+static constexpr size_t HEADER_FIELD_APP_INSTANCE = 3;
+
+static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
+static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
+static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
namespace android {
@@ -83,6 +89,7 @@
jmethodID contextHubServiceMsgReceiptCallback;
jmethodID contextHubServiceAddAppInstance;
+ jmethodID contextHubServiceDeleteAppInstance;
};
struct context_hub_info_s {
@@ -93,10 +100,53 @@
};
struct app_instance_info_s {
- uint32_t hubHandle; // Id of the hub this app is on
- int instanceId; // systemwide unique instance id - assigned
+ uint64_t truncName; // Possibly truncated name for logging
+ uint32_t hubHandle; // Id of the hub this app is on
+ int instanceId; // system wide unique instance id - assigned
struct hub_app_info appInfo; // returned from the HAL
- uint64_t truncName; // Possibly truncated name - logging
+};
+
+/*
+ * TODO(ashutoshj): From original code review:
+ *
+ * So, I feel like we could possible do a better job of organizing this code,
+ * and being more C++-y. Consider something like this:
+ * class TxnManager {
+ * public:
+ * TxnManager();
+ * ~TxnManager();
+ * int add(hub_message_e identifier, void *data);
+ * int close();
+ * bool isPending() const;
+ * int fetchData(hub_message_e *identifier, void **data) const;
+ *
+ * private:
+ * bool mPending;
+ * mutable std::mutex mLock;
+ * hub_message_e mIdentifier;
+ * void *mData;
+ * };
+ *
+ * And then, for example, we'd have things like:
+ * TxnManager::TxnManager() : mPending(false), mLock(), mIdentifier(), mData(nullptr) {}
+ * int TxnManager::add(hub_message_e identifier, void *data) {
+ * std::lock_guard<std::mutex> lock(mLock);
+ * mPending = true;
+ * mData = txnData;
+ * mIdentifier = txnIdentifier;
+ * return 0;
+ * }
+ * And then calling code would look like:
+ * if (!db.txnManager.add(CONTEXT_HUB_LOAD_APP, txnInfo)) {
+ *
+ * This would make it clearer the nothing is manipulating any state within TxnManager
+ * unsafely and outside of these couple of calls.
+ */
+struct txnManager_s {
+ bool txnPending; // Is a transaction pending
+ std::mutex m; // mutex for manager
+ hub_messages_e txnIdentifier; // What are we doing
+ void *txnData; // Details
};
struct contextHubServiceDb_s {
@@ -105,12 +155,69 @@
jniInfo_s jniInfo;
std::queue<int> freeIds;
std::unordered_map<int, app_instance_info_s> appInstances;
+ txnManager_s txnManager;
};
} // unnamed namespace
static contextHubServiceDb_s db;
+static bool initTxnManager() {
+ txnManager_s *mgr = &db.txnManager;
+
+ mgr->txnData = nullptr;
+ mgr->txnPending = false;
+ return true;
+}
+
+static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
+ txnManager_s *mgr = &db.txnManager;
+
+ std::lock_guard<std::mutex>lock(mgr->m);
+
+ mgr->txnPending = true;
+ mgr->txnData = txnData;
+ mgr->txnIdentifier = txnIdentifier;
+
+ return 0;
+}
+
+static int closeTxn() {
+ txnManager_s *mgr = &db.txnManager;
+ std::lock_guard<std::mutex>lock(mgr->m);
+ mgr->txnPending = false;
+ free(mgr->txnData);
+ mgr->txnData = nullptr;
+
+ return 0;
+}
+
+static bool isTxnPending() {
+ txnManager_s *mgr = &db.txnManager;
+ std::lock_guard<std::mutex>lock(mgr->m);
+ return mgr->txnPending;
+}
+
+static int fetchTxnData(hub_messages_e *id, void **data) {
+ txnManager_s *mgr = &db.txnManager;
+
+ if (!id || !data) {
+ ALOGW("Null params id %p, data %p", id, data);
+ return -1;
+ }
+
+ std::lock_guard<std::mutex>lock(mgr->m);
+ if (!mgr->txnPending) {
+ ALOGW("No Transactions pending");
+ return -1;
+ }
+
+ // else
+ *id = mgr->txnIdentifier;
+ *data = mgr->txnData;
+ return 0;
+}
+
int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
void *cookie);
@@ -152,13 +259,21 @@
}
}
-static int get_hub_id_for_app_instance(int id) {
+static int get_hub_handle_for_app_instance(int id) {
if (!db.appInstances.count(id)) {
ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
return -1;
}
- int hubHandle = db.appInstances[id].hubHandle;
+ return db.appInstances[id].hubHandle;
+}
+
+static int get_hub_id_for_app_instance(int id) {
+ int hubHandle = get_hub_handle_for_app_instance(id);
+
+ if (hubHandle < 0) {
+ return -1;
+ }
return db.hubInfo.hubs[hubHandle].hub_id;
}
@@ -184,7 +299,7 @@
return 0;
}
-static void send_query_for_apps() {
+static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
hub_message_t msg;
query_apps_request_t queryMsg;
@@ -194,23 +309,31 @@
msg.message_len = sizeof(queryMsg);
msg.message = &queryMsg;
+ ALOGD("Sending query for apps to hub %" PRIu32, hubHandle);
+ set_os_app_as_destination(&msg, hubHandle);
+ if (send_msg_to_hub(&msg, hubHandle) != 0) {
+ ALOGW("Could not query hub %" PRIu32 " for apps", hubHandle);
+ }
+}
+
+static void sendQueryForApps(uint64_t appId) {
for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
- ALOGD("Sending query for apps to hub %d", i);
- set_os_app_as_destination(&msg, i);
- if (send_msg_to_hub(&msg, i) != 0) {
- ALOGW("Could not query hub %i for apps", i);
- }
+ query_hub_for_apps(appId, i);
}
}
static int return_id(int id) {
// Note : This method is not thread safe.
- // id returned is guarenteed to be in use
- db.freeIds.push(id);
- return 0;
+ // id returned is guaranteed to be in use
+ if (id >= 0) {
+ db.freeIds.push(id);
+ return 0;
+ }
+
+ return -1;
}
-static int generate_id(void) {
+static int generate_id() {
// Note : This method is not thread safe.
int retVal = -1;
@@ -222,23 +345,31 @@
return retVal;
}
-int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
+
+static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
+ int appInstanceHandle, JNIEnv *env) {
+
+ ALOGI("Loading App");
+
// Not checking if the apps are indeed distinct
app_instance_info_s entry;
- int appInstanceHandle = generate_id();
-
assert(appInfo);
- if (appInstanceHandle < 0) {
- ALOGE("Cannot find resources to add app instance %d",
- appInstanceHandle);
- return -1;
+ if (db.appInstances.count(appInstanceHandle) == 0) {
+ appInstanceHandle = generate_id();
+ if (appInstanceHandle < 0) {
+ ALOGE("Cannot find resources to add app instance %d",
+ appInstanceHandle);
+ return -1;
+ }
}
entry.appInfo = *appInfo;
+
entry.instanceId = appInstanceHandle;
entry.truncName = appInfo->app_name.id;
entry.hubHandle = hubHandle;
+
db.appInstances[appInstanceHandle] = entry;
// Finally - let the service know of this app instance
@@ -254,17 +385,70 @@
return appInstanceHandle;
}
-int delete_app_instance(int id) {
+int delete_app_instance(int id, JNIEnv *env) {
if (!db.appInstances.count(id)) {
+ ALOGW("Cannot find App id : %d", id);
return -1;
}
return_id(id);
db.appInstances.erase(id);
+ if (env->CallIntMethod(db.jniInfo.jContextHubService,
+ db.jniInfo.contextHubServiceDeleteAppInstance,
+ id) != 0) {
+ ALOGW("Could not delete App id : %d", id);
+ return -1;
+ }
+
+ ALOGI("Deleted App id : %d", id);
return 0;
}
+static int startLoadAppTxn(uint64_t appId, int hubHandle) {
+ app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
+ int instanceId = generate_id();
+
+ if (!txnInfo || instanceId < 0) {
+ return_id(instanceId);
+ free(txnInfo);
+ return -1;
+ }
+
+ txnInfo->truncName = appId;
+ txnInfo->hubHandle = hubHandle;
+ txnInfo->instanceId = instanceId;
+
+ txnInfo->appInfo.app_name.id = appId;
+ txnInfo->appInfo.num_mem_ranges = 0;
+ txnInfo->appInfo.version = -1; // Awaited
+
+ if (addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
+ return_id(instanceId);
+ free(txnInfo);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int startUnloadAppTxn(uint32_t appInstanceHandle) {
+ uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
+ if (!txnData) {
+ ALOGW("Cannot allocate memory to start unload transaction");
+ return -1;
+ }
+
+ *txnData = appInstanceHandle;
+
+ if (addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
+ free(txnData);
+ ALOGW("Cannot start transaction to unload app");
+ return -1;
+ }
+
+ return 0;
+}
static void initContextHubService() {
int err = 0;
@@ -285,6 +469,7 @@
db.freeIds.push(i);
}
+ initTxnManager();
if (db.hubInfo.contextHubModule) {
int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
&db.hubInfo.hubs);
@@ -302,6 +487,7 @@
for (i = 0; i < db.hubInfo.numHubs; i++) {
db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
+ ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
context_hub_callback,
&db.hubInfo.cookies[i]) == 0) {
@@ -309,7 +495,7 @@
}
}
- send_query_for_apps();
+ sendQueryForApps(ALL_APPS);
} else {
ALOGW("No Context Hub Module present");
}
@@ -346,7 +532,8 @@
return ret;
}
-int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
+int handle_query_apps_response(const uint8_t *msg, int msgLen,
+ uint32_t hubHandle) {
JNIEnv *env;
if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
return -1;
@@ -354,53 +541,202 @@
int numApps = msgLen/sizeof(hub_app_info);
hub_app_info info;
- hub_app_info *unalignedInfoAddr = (hub_app_info*)msg;
+ const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
memcpy(&info, unalignedInfoAddr, sizeof(info));
- add_app_instance(&info, hubHandle, env);
+ // We will only have one instance of the app
+ // TODO : Change this logic once we support multiple instances of the same app
+ int appInstance = get_app_instance_for_app_id(info.app_name.id);
+ add_app_instance(&info, hubHandle, appInstance, env);
}
return 0;
}
+static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
+ status_response_t *rsp, int8_t *additionalData,
+ size_t additionalDataLen) {
+ JNIEnv *env;
-int handle_os_message(uint32_t msgType, uint32_t hubHandle,
- char *msg, int msgLen) {
- int retVal;
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+ ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32, msgType);
+ return;
+ }
- //ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
- // hubHandle, msgType, msgLen);
+ uint32_t header[MSG_HEADER_SIZE];
+ memset(header, 0, sizeof(header));
+
+ if (!additionalData) {
+ additionalDataLen = 0; // clamp
+ }
+ int msgLen = 1 + additionalDataLen;
+
+ int8_t *msg = new int8_t[msgLen];
+
+ if (!msg) {
+ ALOGW("Unexpected : Ran out of memory, cannot send response");
+ return;
+ }
+
+ header[HEADER_FIELD_MSG_TYPE] = msgType;
+ header[HEADER_FIELD_MSG_VERSION] = 0;
+ header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
+ header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
+
+ msg[0] = rsp->result;
+
+ if (additionalData) {
+ memcpy(&msg[1], additionalData, additionalDataLen);
+ }
+
+ jbyteArray jmsg = env->NewByteArray(msgLen);
+ jintArray jheader = env->NewIntArray(sizeof(header));
+
+ env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
+ env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
+
+ ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
+ header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
+ header[HEADER_FIELD_HUB_HANDLE]);
+
+ env->CallIntMethod(db.jniInfo.jContextHubService,
+ db.jniInfo.contextHubServiceMsgReceiptCallback,
+ jheader, jmsg);
+
+ delete[] msg;
+}
+
+void closeUnloadTxn(bool success) {
+ void *txnData = nullptr;
+ hub_messages_e txnId;
+
+ if (success && fetchTxnData(&txnId, &txnData) == 0 &&
+ txnId == CONTEXT_HUB_UNLOAD_APP) {
+ db.appInstances.erase(*(uint32_t *)txnData);
+ } else {
+ ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
+ }
+
+ closeTxn();
+}
+
+void closeLoadTxn(bool success, int *appInstanceHandle) {
+ void *txnData;
+ hub_messages_e txnId;
+
+ if (success && fetchTxnData(&txnId, &txnData) == 0 &&
+ txnId == CONTEXT_HUB_LOAD_APP) {
+ app_instance_info_s *info = (app_instance_info_s *)txnData;
+ *appInstanceHandle = info->instanceId;
+
+ JNIEnv *env;
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
+ add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
+ } else {
+ ALOGW("Could not attach to JVM !");
+ }
+ sendQueryForApps(info->appInfo.app_name.id);
+ } else {
+ ALOGW("Could not load the app successfully ! Unexpected failure");
+ }
+
+ closeTxn();
+}
+
+static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
+ status_response_t *rsp) {
+ // Workaround a bug in some HALs
+ if (msgLen == 1) {
+ rsp->result = msg[0];
+ return true;
+ }
+
+ if (!msg || msgLen != sizeof(*rsp)) {
+ ALOGW("Received invalid response %p of size %zu", msg, msgLen);
+ return false;
+ }
+
+ memcpy(rsp, msg, sizeof(*rsp));
+
+ // No sanity checks on return values
+ return true;
+}
+
+static void invalidateNanoApps(uint32_t hubHandle) {
+ JNIEnv *env;
+
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+ ALOGW("Could not attach to JVM !");
+ }
+
+ auto end = db.appInstances.end();
+ for (auto current = db.appInstances.begin(); current != end; ) {
+ app_instance_info_s info = current->second;
+ current++;
+ if (info.hubHandle == hubHandle) {
+ delete_app_instance(info.instanceId, env);
+ }
+ }
+}
+
+static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
+ const uint8_t *msg, int msgLen) {
+ int retVal = -1;
+
+ ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
+ hubHandle, msgType, msgLen);
+
+ struct status_response_t rsp;
switch(msgType) {
- case CONTEXT_HUB_APPS_ENABLE:
- retVal = 0;
- break;
- case CONTEXT_HUB_APPS_DISABLE:
- retVal = 0;
- break;
+ case CONTEXT_HUB_APPS_ENABLE:
+ case CONTEXT_HUB_APPS_DISABLE:
+ case CONTEXT_HUB_LOAD_APP:
+ case CONTEXT_HUB_UNLOAD_APP:
+ if (isValidOsStatus(msg, msgLen, &rsp)) {
+ if (msgType == CONTEXT_HUB_LOAD_APP) {
+ int appInstanceHandle;
+ closeLoadTxn(rsp.result == 0, &appInstanceHandle);
+ passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
+ sizeof(appInstanceHandle));
+ } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
+ closeUnloadTxn(rsp.result == 0);
+ passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
+ } else {
+ passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
+ }
+ retVal = 0;
+ }
+ break;
- case CONTEXT_HUB_LOAD_APP:
- retVal = 0;
- break;
+ case CONTEXT_HUB_QUERY_APPS:
+ rsp.result = 0;
+ retVal = handle_query_apps_response(msg, msgLen, hubHandle);
+ passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
+ break;
- case CONTEXT_HUB_UNLOAD_APP:
- retVal = 0;
- break;
+ case CONTEXT_HUB_QUERY_MEMORY:
+ // Deferring this use
+ retVal = 0;
+ break;
- case CONTEXT_HUB_QUERY_APPS:
- retVal = handle_query_apps_response(msg, msgLen, hubHandle);
- break;
+ case CONTEXT_HUB_OS_REBOOT:
+ if (isValidOsStatus(msg, msgLen, &rsp)) {
+ rsp.result = 0;
+ ALOGW("Context Hub handle %d restarted", hubHandle);
+ closeTxn();
+ passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
+ invalidateNanoApps(hubHandle);
+ query_hub_for_apps(ALL_APPS, hubHandle);
+ retVal = 0;
+ }
+ break;
- case CONTEXT_HUB_QUERY_MEMORY:
- retVal = 0;
- break;
-
- default:
- retVal = -1;
- break;
-
+ default:
+ retVal = -1;
+ break;
}
return retVal;
@@ -420,10 +756,12 @@
}
}
+
int context_hub_callback(uint32_t hubId,
const struct hub_message_t *msg,
void *cookie) {
if (!msg) {
+ ALOGW("NULL message");
return -1;
}
if (!sanity_check_cookie(cookie, hubId)) {
@@ -433,11 +771,12 @@
return -1;
}
+
uint32_t messageType = msg->message_type;
uint32_t hubHandle = *(uint32_t*) cookie;
if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
- handle_os_message(messageType, hubHandle, (char*) msg->message, msg->message_len);
+ handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
} else {
int appHandle = get_app_instance_for_app_id(msg->app_name.id);
if (appHandle < 0) {
@@ -528,7 +867,9 @@
env->GetMethodID(db.jniInfo.contextHubServiceClass,
"addAppInstance", "(IIJI)I");
-
+ db.jniInfo.contextHubServiceDeleteAppInstance =
+ env->GetMethodID(db.jniInfo.contextHubServiceClass,
+ "deleteAppInstance", "(I)I");
return 0;
}
@@ -538,8 +879,6 @@
jintArray jintBuf;
jobjectArray jmemBuf;
- int dummyConnectedSensors[] = {1, 2, 3, 4, 5};
-
jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
db.jniInfo.contextHubInfoCtor);
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
@@ -569,11 +908,21 @@
hub->max_supported_msg_len);
- // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
- // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
- // hub->connected_sensors);
- jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
- env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
+ jintBuf = env->NewIntArray(hub->num_connected_sensors);
+ int *connectedSensors = new int[hub->num_connected_sensors];
+
+ if (!connectedSensors) {
+ ALOGW("Cannot allocate memory! Unexpected");
+ assert(false);
+ } else {
+ for (unsigned int i = 0; i < hub->num_connected_sensors; i++) {
+ connectedSensors[i] = hub->connected_sensors[i].sensor_id;
+ }
+ }
+
+ env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
+ connectedSensors);
+
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
env->DeleteLocalRef(jintBuf);
@@ -584,6 +933,7 @@
env->DeleteLocalRef(jmemBuf);
+ delete[] connectedSensors;
return jHub;
}
@@ -622,33 +972,98 @@
jbyte *data = env->GetByteArrayElements(data_, 0);
int dataBufferLength = env->GetArrayLength(data_);
+ if (numHeaderElements < MSG_HEADER_SIZE) {
+ ALOGW("Malformed header len");
+ return -1;
+ }
- if (numHeaderElements >= MSG_HEADER_SIZE) {
- bool setAddressSuccess;
- int hubId;
- hub_message_t msg;
+ uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
+ uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
+ int hubHandle = -1;
+ int hubId;
+ uint64_t appId;
+
+ if (msgType == CONTEXT_HUB_UNLOAD_APP) {
+ hubHandle = get_hub_handle_for_app_instance(appInstanceHandle);
+ } else if (msgType == CONTEXT_HUB_LOAD_APP) {
+ if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) {
+ return -1;
+ }
+ uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO];
+ uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI];
+ appId = appIdHi << 32 | appIdLo;
+
+ hubHandle = header[HEADER_FIELD_HUB_HANDLE];
+ } else {
+ hubHandle = header[HEADER_FIELD_HUB_HANDLE];
+ }
+
+ if (hubHandle < 0) {
+ ALOGD("Invalid hub Handle %d", hubHandle);
+ return -1;
+ }
+
+ if (msgType == CONTEXT_HUB_LOAD_APP ||
+ msgType == CONTEXT_HUB_UNLOAD_APP) {
+
+ if (isTxnPending()) {
+ ALOGW("Cannot load or unload app while a transaction is pending !");
+ return -1;
+ }
+
+ if (msgType == CONTEXT_HUB_LOAD_APP) {
+ if (startLoadAppTxn(appId, hubHandle) != 0) {
+ ALOGW("Cannot Start Load Transaction");
+ return -1;
+ }
+ } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
+ if (startUnloadAppTxn(appInstanceHandle) != 0) {
+ ALOGW("Cannot Start UnLoad Transaction");
+ return -1;
+ }
+ }
+ }
+
+ bool setAddressSuccess = false;
+ hub_message_t msg;
+
+ msg.message_type = msgType;
+
+ if (msgType == CONTEXT_HUB_UNLOAD_APP) {
+ msg.message_len = sizeof(db.appInstances[appInstanceHandle].appInfo.app_name);
+ msg.message = &db.appInstances[appInstanceHandle].appInfo.app_name;
+ setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
+ hubId = get_hub_id_for_hub_handle(hubHandle);
+ } else {
+ msg.message_len = dataBufferLength;
+ msg.message = data;
if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
- setAddressSuccess = (set_os_app_as_destination(&msg, header[HEADER_FIELD_HUB_HANDLE]) == 0);
- hubId = get_hub_id_for_hub_handle(header[HEADER_FIELD_HUB_HANDLE]);
+ setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
+ hubId = get_hub_id_for_hub_handle(hubHandle);
} else {
setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
}
+ }
- if (setAddressSuccess && hubId >= 0) {
- msg.message_type = header[HEADER_FIELD_MSG_TYPE];
- msg.message_len = dataBufferLength;
- msg.message = data;
- retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
- } else {
- ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
- header[HEADER_FIELD_APP_INSTANCE],
- header[HEADER_FIELD_HUB_HANDLE],
- (int)setAddressSuccess);
- }
+ if (setAddressSuccess && hubId >= 0) {
+ ALOGD("Asking HAL to remove app");
+ retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
} else {
- ALOGD("Malformed header len");
+ ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
+ header[HEADER_FIELD_APP_INSTANCE],
+ header[HEADER_FIELD_HUB_HANDLE],
+ (int)setAddressSuccess);
+ }
+
+ if (retVal != 0) {
+ ALOGD("Send Message failure - %d", retVal);
+ if (msgType == CONTEXT_HUB_LOAD_APP) {
+ closeLoadTxn(false, nullptr);
+ } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
+ closeUnloadTxn(false);
+ }
}
env->ReleaseIntArrayElements(header_, header, 0);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 3d952b0..dcc2aa0 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -546,9 +546,9 @@
env->ReleaseStringCritical(name, str);
}
- if (name8.size() > 0) {
+ if (!name8.isEmpty()) {
const char* procName = name8.string();
- set_process_name(procName);
+ pthread_setname_np(pthread_self(), procName);
AndroidRuntime::getRuntime()->setArgv0(procName);
}
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 50e982f..5637dbc 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -504,7 +504,7 @@
ContextFactory factory;
RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
proxy->loadSystemProperties();
- proxy->setSwapBehavior(kSwap_discardBuffer);
+ proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
proxy->initialize(surface);
// Shadows can't be used via this interface, so just set the light source
// to all 0s.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 42c0c93..99c01bf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -49,6 +49,7 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" />
<protected-broadcast android:name="android.intent.action.UID_REMOVED" />
<protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
diff --git a/core/res/res/drawable/notification_material_action_background_emphasized.xml b/core/res/res/drawable/notification_material_action_background_emphasized.xml
new file mode 100644
index 0000000..b7153ba
--- /dev/null
+++ b/core/res/res/drawable/notification_material_action_background_emphasized.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_dark">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</ripple>
+
diff --git a/core/res/res/layout/notification_material_action_emphasized.xml b/core/res/res/layout/notification_material_action_emphasized.xml
new file mode 100644
index 0000000..992e43e
--- /dev/null
+++ b/core/res/res/layout/notification_material_action_emphasized.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button_holder"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="#ff000000">
+ <Button
+ style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+ android:id="@+id/action0"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textColor="#ffffffff"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:background="@drawable/notification_material_action_background_emphasized"
+ />
+</FrameLayout>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6a16a3d..5185527 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -937,7 +937,7 @@
<string name="selectAll" msgid="6876518925844129331">"انتخاب همه"</string>
<string name="cut" msgid="3092569408438626261">"برش"</string>
<string name="copy" msgid="2681946229533511987">"کپی"</string>
- <string name="paste" msgid="5629880836805036433">"جای گذاری"</string>
+ <string name="paste" msgid="5629880836805036433">"جایگذاری"</string>
<string name="paste_as_plain_text" msgid="5427792741908010675">"جایگذاری به عنوان متن ساده"</string>
<string name="replace" msgid="5781686059063148930">"جایگزین شود..."</string>
<string name="delete" msgid="6098684844021697789">"حذف"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 5d6c761..b388cb7 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -975,7 +975,7 @@
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួលជាមួយ %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"កែសម្រួល"</string>
<string name="whichSendApplication" msgid="6902512414057341668">"ចែករំលែកជាមួយ"</string>
- <string name="whichSendApplicationNamed" msgid="2799370240005424391">"ចែករំលែកជាមួយ"</string>
+ <string name="whichSendApplicationNamed" msgid="2799370240005424391">"ចែករំលែកជាមួយ %1$s"</string>
<string name="whichSendApplicationLabel" msgid="4579076294675975354">"ចែករំលែក"</string>
<string name="whichSendToApplication" msgid="8272422260066642057">"ផ្ញើដោយប្រើ"</string>
<string name="whichSendToApplicationNamed" msgid="7768387871529295325">"ផ្ញើដោយប្រើ %1$s"</string>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
index 91eee7d..45eb981 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -20,5 +20,7 @@
<color name="accent_material_dark">#ff5e97f6</color>
<color name="accent_material_light">#ff4285f4</color>
+ <color name="primary_material_dark">#4D4D4D</color>
+
<color name="button_material_dark">#ff999999</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cd56f0f..a0f1dc4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -764,7 +764,7 @@
1 - AUTO_MODE_CUSTOM
2 - AUTO_MODE_TWILIGHT
-->
- <integer name="config_defaultNightDisplayAutoMode">1</integer>
+ <integer name="config_defaultNightDisplayAutoMode">0</integer>
<!-- Default time when Night display is automatically activated.
Represented as milliseconds from midnight (e.g. 79200000 == 10pm). -->
@@ -2538,4 +2538,12 @@
<!-- Package name for the device provisioning package. -->
<string name="config_deviceProvisioningPackage"></string>
+
+ <!-- Colon separated list of package names that should be granted DND access -->
+ <string name="config_defaultDndAccessPackages" translatable="false">com.android.camera2</string>
+
+ <!-- User restrictions set when the first user is created.
+ Note: Also update appropriate overlay files. -->
+ <string-array translatable="false" name="config_defaultFirstUserRestrictions">
+ </string-array>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7144ef0..23bbed6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2796,6 +2796,9 @@
<!-- [CHAR LIMIT=200] Body of notification that is shown when performing a system upgrade. -->
<string name="android_upgrading_notification_body">Some apps may not work properly until the upgrade finishes</string>
+ <!-- [CHAR LIMIT=40] Toast that is shown when an app is still upgrading. -->
+ <string name="app_upgrading_toast"><xliff:g id="application">%1$s</xliff:g> is upgrading\u2026</string>
+
<!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog for each .apk that is optimized. -->
<string name="android_upgrading_apk">Optimizing app
<xliff:g id="number" example="123">%1$d</xliff:g> of
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5045f33..bd3d5cb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2630,6 +2630,8 @@
<!-- Used internally for assistant to launch activity transitions -->
<java-symbol type="id" name="cross_task_transition" />
+ <java-symbol type="id" name="button_holder" />
+
<java-symbol type="bool" name="config_useRoundIcon" />
<!-- For System navigation keys -->
@@ -2638,9 +2640,14 @@
<java-symbol type="layout" name="unsupported_display_size_dialog_content" />
<java-symbol type="string" name="unsupported_display_size_message" />
+ <java-symbol type="layout" name="notification_material_action_emphasized" />
+
<!-- Package name for the device provisioning package -->
<java-symbol type="string" name="config_deviceProvisioningPackage" />
+ <!-- Colon separated list of package names that should be granted DND access -->
+ <java-symbol type="string" name="config_defaultDndAccessPackages" />
+
<!-- Used for MimeIconUtils. -->
<java-symbol type="drawable" name="ic_doc_apk" />
<java-symbol type="drawable" name="ic_doc_audio" />
@@ -2670,4 +2677,7 @@
<java-symbol type="integer" name="config_defaultNightDisplayAutoMode" />
<java-symbol type="integer" name="config_defaultNightDisplayCustomStartTime" />
<java-symbol type="integer" name="config_defaultNightDisplayCustomEndTime" />
+
+ <!-- Default first user restrictions -->
+ <java-symbol type="array" name="config_defaultFirstUserRestrictions" />
</resources>
diff --git a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
new file mode 100644
index 0000000..19a390a
--- /dev/null
+++ b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.app;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.app.ApplicationErrorReport.CrashInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApplicationErrorReportTest {
+
+ @Test
+ public void testHugeStacktraceLeadsToReasonableReport() {
+ Throwable deepStackTrace = deepStackTrace();
+ CrashInfo crashInfo = new CrashInfo(deepStackTrace);
+
+ assertTrue("stack trace is longer than 50'000 characters",
+ crashInfo.stackTrace.length() < 50000);
+ }
+
+ @Test
+ public void testHugeExceptionMessageLeadsToReasonableReport() {
+ StringBuilder msg = new StringBuilder();
+ for (int i = 0; i < 1000000; i++) {
+ msg.append('x');
+ }
+
+ CrashInfo crashInfo = new CrashInfo(new Throwable(msg.toString()));
+
+ assertTrue("message is longer than 50'000 characters",
+ crashInfo.exceptionMessage.length() < 50000);
+ }
+
+ @Test
+ public void testTruncationKeepsStartAndEndIntact() {
+ StringBuilder msg = new StringBuilder("start");
+ for (int i = 0; i < 1000000; i++) {
+ msg.append('x');
+ }
+ msg.append("end");
+
+ CrashInfo crashInfo = new CrashInfo(new Throwable(msg.toString()));
+
+ String exceptionMessage = crashInfo.exceptionMessage;
+ assertEquals("start", exceptionMessage.substring(0, "start".length()));
+ assertEquals("end", exceptionMessage.substring(exceptionMessage.length() - "end".length()));
+ }
+
+ /**
+ * @return a Throwable with a very long stack trace.
+ */
+ private Throwable deepStackTrace() {
+ return stackTraceGenerator__aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa(1000);
+ }
+
+ private Throwable stackTraceGenerator__aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa(
+ int d) {
+ if (d > 0) {
+ return stackTraceGenerator__aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa(d - 1);
+ } else {
+ return new Throwable("here");
+ }
+ }
+}
diff --git a/docs/docs-preview-index.html b/docs/docs-preview-index.html
index e26b57c..8d5422b 100644
--- a/docs/docs-preview-index.html
+++ b/docs/docs-preview-index.html
@@ -79,19 +79,16 @@
<h2>Get Started</h2>
<ul>
- <li>View the <a href="reference/packages.html">API Reference</a></li>
+ <li>View the <a href="reference/packages.html">offline API Reference</a></li>
<li>Read Diff Reports:</a>
<ul>
- <li><a href="sdk/api_diff/n-preview-1/changes.html"
- >API 23 --> Preview 1</a></li>
+ <li><a href="https://developer.android.com/sdk/api_diff/24/changes.html"
+ >API 23 --> API 24</a></li>
</ul>
</li>
- <li>Downloads and additional documentation are available at the
+ <li>For more information, visit the
<a href="http://developer.android.com/preview/index.html">
Android N Developer Preview site</a></li>
- <li>For information about Developer Preview 1, visit the
- <a href="http://developer.android.com/preview/support.html">Support</a>
- page.</li>
</ul>
diff --git a/docs/html-intl/intl/es/preview/download-ota.jd b/docs/html-intl/intl/es/preview/download-ota.jd
index d3e8be9..2b2bcbf 100644
--- a/docs/html-intl/intl/es/preview/download-ota.jd
+++ b/docs/html-intl/intl/es/preview/download-ota.jd
@@ -178,7 +178,7 @@
<ol>
<li>Descargar una imagen de dispositivo inalámbrico de la tabla que verás a continuación.</li>
<li>Reinicia el dispositivo en modo Recuperación. Para leer más información sobre cómo
- aplicar este modo en dispositivos Nexus, visita la sección
+ aplicar este modo en dispositivos Nexus, visita la sección
<a href="https://support.google.com/nexus/answer/4596836">Reset your Nexus
device to factory settings</a>.
</li>
@@ -202,65 +202,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-ota-npd35k-b8cfbd80.zip</a><br>
- MD5: 15fe2eba9b01737374196bdf0a792fe9<br>
- SHA-1: 5014b2bba77f9e1a680ac3f90729621c85a14283
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-ota-npd35k-078e6fa5.zip</a><br>
- MD5: e8b12f7721c53af9a450f7058928a5fc<br>
- SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-ota-npd35k-88457699.zip</a><br>
- MD5: 3fac09fef759dde26e57cb80b20b6477<br>
- SHA-1: 27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-ota-npd35k-51dbae76.zip</a><br>
- MD5: 58312c4a5971818ef5c77a3f446003da<br>
- SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-ota-npd35k-834f047f.zip</a><br>
- MD5: 92b7d1fa252f7394e70f957c72d4aac8<br>
- SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-ota-npd35k-6ac91298.zip</a><br>
- MD5: 1461622ad53ea842b2722fa7b49b8172<br>
- SHA-1: 409c061668ab270774877d7f3eae44fa48d2b931
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-ota-npd35k-a0b2347f.zip</a><br>
- MD5: c60117f3640cc6db12386fd632289c7d<br>
- SHA-1: 87349c767c69efb4172c90ce1d88cf578c3d28b3
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-ota-npd35k-09897a1d.zip</a><br>
- MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
- SHA-1: 6f33742290eb46f2561891f38ca2e754b4e50c6a
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html-intl/intl/es/preview/download.jd b/docs/html-intl/intl/es/preview/download.jd
index d489074..4662d5b 100644
--- a/docs/html-intl/intl/es/preview/download.jd
+++ b/docs/html-intl/intl/es/preview/download.jd
@@ -209,7 +209,7 @@
<h2 id="device-preview">Configurar un dispositivo de hardware</h2>
<p>
- En N Developer Preview se ofrecen actualizaciones del sistema para una variedad de dispositivos de hardware
+ En N Developer Preview se ofrecen actualizaciones del sistema para una variedad de dispositivos de hardware
que puedes usar para realizarle pruebas a tu aplicación, desde teléfonos hasta tablets y TV.
</p>
@@ -300,65 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npd35k-factory-5ba40535.tgz</a><br>
- MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
- SHA-1: 5ba4053577007d15c96472206e3a79bc80ab194c
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npd35k-factory-a33bf20c.tgz</a><br>
- MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
- SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npd35k-factory-81c341d5.tgz</a><br>
- MD5: e93de7949433339856124c3729c15ebb<br>
- SHA-1: 81c341d57ef2cd139569b055d5d59e9e592a7abd
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npd35k-factory-2b50e19d.tgz</a><br>
- MD5: 565be87ebb2d5937e2abe1a42645864b<br>
- SHA-1: 2b50e19dae2667b27f911e3c61ed64860caf43e1
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
- MD5: a8464e15c6683fe2afa378a63e205fda<br>
- SHA-1: 2e89ebe67a46b2f3beb050746c13341cd11fa678
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npd35k-factory-1de74874.tgz</a><br>
- MD5: c0dbb7db671f61b2785da5001cedefcb<br>
- SHA-1: 1de74874f8d83e14d642f13b5a2130fc2aa55873
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npd35k-factory-b4eed85d.tgz</a><br>
- MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
- SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
- MD5: 7d34a9774fdd6e025d485ce6cfc23c4c<br>
- SHA-1: 5ab1212bc9417269d391aacf1e672fff24b4ecc5
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
@@ -377,7 +385,7 @@
Si quieres desinstalar la muestra desde un dispositivo, puedes hacerlo de las
siguientes maneras: </p>
<ul>
- <li><strong>Obtener una imagen de sistema con las especificaciones de fábrica</strong> y luego actualízala de manera manual
+ <li><strong>Obtener una imagen de sistema con las especificaciones de fábrica</strong> y luego actualízala de manera manual
para el dispositivo.
<ul>
<li>Para <strong>los dispositivos Nexus y Pixel C</strong>, consulta
@@ -466,8 +474,8 @@
<p>
A fin de garantizar la mejor experiencia en el emulador de Android, verifica que estás utilizando
-Android Studio 2.1 o una versión superior, compatible con el <a href="http://tools.android.com/tech-docs/emulator">emulador de Android 2.0</a>,
-cuyo rendimiento es mayor si se lo compara con el emulador utilizado en
+Android Studio 2.1 o una versión superior, compatible con el <a href="http://tools.android.com/tech-docs/emulator">emulador de Android 2.0</a>,
+cuyo rendimiento es mayor si se lo compara con el emulador utilizado en
Android Studio 1.5.</p>
<p>Para obtener más información sobre la creación de dispositivos virtuales, consulta <a href="{@docRoot}tools/devices/index.html">Administración de dispositivos virtuales</a>.
diff --git a/docs/html-intl/intl/in/preview/download-ota.jd b/docs/html-intl/intl/in/preview/download-ota.jd
index 1efe9b7..4adf9bb 100644
--- a/docs/html-intl/intl/in/preview/download-ota.jd
+++ b/docs/html-intl/intl/in/preview/download-ota.jd
@@ -202,65 +202,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-ota-npd35k-b8cfbd80.zip</a><br>
- MD5: 15fe2eba9b01737374196bdf0a792fe9<br>
- SHA-1: 5014b2bba77f9e1a680ac3f90729621c85a14283
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-ota-npd35k-078e6fa5.zip</a><br>
- MD5: e8b12f7721c53af9a450f7058928a5fc<br>
- SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-ota-npd35k-88457699.zip</a><br>
- MD5: 3fac09fef759dde26e57cb80b20b6477<br>
- SHA-1: 27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-ota-npd35k-51dbae76.zip</a><br>
- MD5: 58312c4a5971818ef5c77a3f446003da<br>
- SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-ota-npd35k-834f047f.zip</a><br>
- MD5: 92b7d1fa252f7394e70f957c72d4aac8<br>
- SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-ota-npd35k-6ac91298.zip</a><br>
- MD5: 1461622ad53ea842b2722fa7b49b8172<br>
- SHA-1: 409c061668ab270774877d7f3eae44fa48d2b931
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-ota-npd35k-a0b2347f.zip</a><br>
- MD5: c60117f3640cc6db12386fd632289c7d<br>
- SHA-1: 87349c767c69efb4172c90ce1d88cf578c3d28b3
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-ota-npd35k-09897a1d.zip</a><br>
- MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
- SHA-1: 6f33742290eb46f2561891f38ca2e754b4e50c6a
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html-intl/intl/in/preview/download.jd b/docs/html-intl/intl/in/preview/download.jd
index a759a11..abf911d 100644
--- a/docs/html-intl/intl/in/preview/download.jd
+++ b/docs/html-intl/intl/in/preview/download.jd
@@ -300,65 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npd35k-factory-5ba40535.tgz</a><br>
- MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
- SHA-1: 5ba4053577007d15c96472206e3a79bc80ab194c
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npd35k-factory-a33bf20c.tgz</a><br>
- MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
- SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npd35k-factory-81c341d5.tgz</a><br>
- MD5: e93de7949433339856124c3729c15ebb<br>
- SHA-1: 81c341d57ef2cd139569b055d5d59e9e592a7abd
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npd35k-factory-2b50e19d.tgz</a><br>
- MD5: 565be87ebb2d5937e2abe1a42645864b<br>
- SHA-1: 2b50e19dae2667b27f911e3c61ed64860caf43e1
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
- MD5: a8464e15c6683fe2afa378a63e205fda<br>
- SHA-1: 2e89ebe67a46b2f3beb050746c13341cd11fa678
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npd35k-factory-1de74874.tgz</a><br>
- MD5: c0dbb7db671f61b2785da5001cedefcb<br>
- SHA-1: 1de74874f8d83e14d642f13b5a2130fc2aa55873
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npd35k-factory-b4eed85d.tgz</a><br>
- MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
- SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
- MD5: 7d34a9774fdd6e025d485ce6cfc23c4c<br>
- SHA-1: 5ab1212bc9417269d391aacf1e672fff24b4ecc5
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
@@ -458,7 +466,7 @@
<strong>x86</strong> ABI), kemudian klik <strong>Next</strong>.
(Hanya citra sistem x86 yang saat ini didukung dengan Android Emulator
untuk Android N Preview.)
- <li>Selesaikan konfigurasi AVD selanjutnya dan klik
+ <li>Selesaikan konfigurasi AVD selanjutnya dan klik
<strong>Finish</strong>.</li>
</ol>
diff --git a/docs/html-intl/intl/ja/preview/download-ota.jd b/docs/html-intl/intl/ja/preview/download-ota.jd
index 1107baf..835597b 100644
--- a/docs/html-intl/intl/ja/preview/download-ota.jd
+++ b/docs/html-intl/intl/ja/preview/download-ota.jd
@@ -202,65 +202,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-ota-npd35k-b8cfbd80.zip</a><br>
- MD5:15fe2eba9b01737374196bdf0a792fe9<br>
- SHA-1:5014b2bba77f9e1a680ac3f90729621c85a14283
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-ota-npd35k-078e6fa5.zip</a><br>
- MD5: e8b12f7721c53af9a450f7058928a5fc<br>
- SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-ota-npd35k-88457699.zip</a><br>
- MD5:3fac09fef759dde26e57cb80b20b6477<br>
- SHA-1:27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-ota-npd35k-51dbae76.zip</a><br>
- MD5:58312c4a5971818ef5c77a3f446003da<br>
- SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-ota-npd35k-834f047f.zip</a><br>
- MD5:92b7d1fa252f7394e70f957c72d4aac8<br>
- SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-ota-npd35k-6ac91298.zip</a><br>
- MD5:1461622ad53ea842b2722fa7b49b8172<br>
- SHA-1:409c061668ab270774877d7f3eae44fa48d2b931
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-ota-npd35k-a0b2347f.zip</a><br>
- MD5: c60117f3640cc6db12386fd632289c7d<br>
- SHA-1:87349c767c69efb4172c90ce1d88cf578c3d28b3
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
- <td>General Mobile 4G(Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-ota-npd35k-09897a1d.zip</a><br>
- MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
- SHA-1:6f33742290eb46f2561891f38ca2e754b4e50c6a
+ <td>General Mobile 4G (Android One) <br>"seed"</td>
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html-intl/intl/ja/preview/download.jd b/docs/html-intl/intl/ja/preview/download.jd
index 52c3c6c..705a90b 100644
--- a/docs/html-intl/intl/ja/preview/download.jd
+++ b/docs/html-intl/intl/ja/preview/download.jd
@@ -300,65 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npd35k-factory-5ba40535.tgz</a><br>
- MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
- SHA-1:5ba4053577007d15c96472206e3a79bc80ab194c
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npd35k-factory-a33bf20c.tgz</a><br>
- MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
- SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npd35k-factory-81c341d5.tgz</a><br>
- MD5: e93de7949433339856124c3729c15ebb<br>
- SHA-1:81c341d57ef2cd139569b055d5d59e9e592a7abd
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npd35k-factory-2b50e19d.tgz</a><br>
- MD5:565be87ebb2d5937e2abe1a42645864b<br>
- SHA-1:2b50e19dae2667b27f911e3c61ed64860caf43e1
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
- MD5: a8464e15c6683fe2afa378a63e205fda<br>
- SHA-1:2e89ebe67a46b2f3beb050746c13341cd11fa678
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npd35k-factory-1de74874.tgz</a><br>
- MD5: c0dbb7db671f61b2785da5001cedefcb<br>
- SHA-1:1de74874f8d83e14d642f13b5a2130fc2aa55873
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npd35k-factory-b4eed85d.tgz</a><br>
- MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
- SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
- <td>General Mobile 4G(Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
- MD5:7d34a9774fdd6e025d485ce6cfc23c4c<br>
- SHA-1:5ab1212bc9417269d391aacf1e672fff24b4ecc5
+ <td>General Mobile 4G (Android One) <br>"seed"</td>
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
diff --git a/docs/html-intl/intl/ko/preview/download-ota.jd b/docs/html-intl/intl/ko/preview/download-ota.jd
index 886b8a8..ee08846 100644
--- a/docs/html-intl/intl/ko/preview/download-ota.jd
+++ b/docs/html-intl/intl/ko/preview/download-ota.jd
@@ -202,65 +202,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-ota-npd35k-b8cfbd80.zip</a><br>
- MD5: 15fe2eba9b01737374196bdf0a792fe9<br>
- SHA-1: 5014b2bba77f9e1a680ac3f90729621c85a14283
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-ota-npd35k-078e6fa5.zip</a><br>
- MD5: e8b12f7721c53af9a450f7058928a5fc<br>
- SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-ota-npd35k-88457699.zip</a><br>
- MD5: 3fac09fef759dde26e57cb80b20b6477<br>
- SHA-1: 27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-ota-npd35k-51dbae76.zip</a><br>
- MD5: 58312c4a5971818ef5c77a3f446003da<br>
- SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-ota-npd35k-834f047f.zip</a><br>
- MD5: 92b7d1fa252f7394e70f957c72d4aac8<br>
- SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-ota-npd35k-6ac91298.zip</a><br>
- MD5: 1461622ad53ea842b2722fa7b49b8172<br>
- SHA-1: 409c061668ab270774877d7f3eae44fa48d2b931
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-ota-npd35k-a0b2347f.zip</a><br>
- MD5: c60117f3640cc6db12386fd632289c7d<br>
- SHA-1: 87349c767c69efb4172c90ce1d88cf578c3d28b3
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
- <td>General Mobile 4G(Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-ota-npd35k-09897a1d.zip</a><br>
- MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
- SHA-1: 6f33742290eb46f2561891f38ca2e754b4e50c6a
+ <td>General Mobile 4G (Android One) <br>"seed"</td>
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html-intl/intl/ko/preview/download.jd b/docs/html-intl/intl/ko/preview/download.jd
index 802420b..88c45cd 100644
--- a/docs/html-intl/intl/ko/preview/download.jd
+++ b/docs/html-intl/intl/ko/preview/download.jd
@@ -300,65 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npd35k-factory-5ba40535.tgz</a><br>
- MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
- SHA-1: 5ba4053577007d15c96472206e3a79bc80ab194c
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npd35k-factory-a33bf20c.tgz</a><br>
- MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
- SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npd35k-factory-81c341d5.tgz</a><br>
- MD5: e93de7949433339856124c3729c15ebb<br>
- SHA-1: 81c341d57ef2cd139569b055d5d59e9e592a7abd
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npd35k-factory-2b50e19d.tgz</a><br>
- MD5: 565be87ebb2d5937e2abe1a42645864b<br>
- SHA-1: 2b50e19dae2667b27f911e3c61ed64860caf43e1
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
- MD5: a8464e15c6683fe2afa378a63e205fda<br>
- SHA-1: 2e89ebe67a46b2f3beb050746c13341cd11fa678
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npd35k-factory-1de74874.tgz</a><br>
- MD5: c0dbb7db671f61b2785da5001cedefcb<br>
- SHA-1: 1de74874f8d83e14d642f13b5a2130fc2aa55873
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npd35k-factory-b4eed85d.tgz</a><br>
- MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
- SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
- <td>General Mobile 4G(Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
- MD5: 7d34a9774fdd6e025d485ce6cfc23c4c<br>
- SHA-1: 5ab1212bc9417269d391aacf1e672fff24b4ecc5
+ <td>General Mobile 4G (Android One) <br>"seed"</td>
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
diff --git a/docs/html-intl/intl/pt-br/preview/download-ota.jd b/docs/html-intl/intl/pt-br/preview/download-ota.jd
index 693aa92..3f817ed 100644
--- a/docs/html-intl/intl/pt-br/preview/download-ota.jd
+++ b/docs/html-intl/intl/pt-br/preview/download-ota.jd
@@ -165,7 +165,7 @@
<p>
Esta página fornece links para imagens OTA de dispositivo e descreve
como aplicar manualmente uma atualização OTA em um dispositivo. Esse procedimento pode ser útil
- para recuperar dispositivos que receberam atualizações OTA usando o programa beta
+ para recuperar dispositivos que receberam atualizações OTA usando o programa beta
do Android e não estão ligando após a instalação.
</p>
@@ -179,7 +179,7 @@
<li>Baixe uma imagem OTA de dispositivo na tabela abaixo.</li>
<li>Reinicialize o dispositivo para ficar em modo Recovery. Para obter mais informações sobre como colocar
dispositivos Nexus nesse modo, consulte
- <a href="https://support.google.com/nexus/answer/4596836">Redefinição do
+ <a href="https://support.google.com/nexus/answer/4596836">Redefinição do
dispositivo Nexus para voltar à configuração de fábrica</a>.
</li>
<li>No dispositivo, selecione <strong>ADB sideload</strong>.</li>
@@ -202,65 +202,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-ota-npd35k-b8cfbd80.zip</a><br>
- MD5: 15fe2eba9b01737374196bdf0a792fe9<br>
- SHA-1: 5014b2bba77f9e1a680ac3f90729621c85a14283
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-ota-npd35k-078e6fa5.zip</a><br>
- MD5: e8b12f7721c53af9a450f7058928a5fc<br>
- SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-ota-npd35k-88457699.zip</a><br>
- MD5: 3fac09fef759dde26e57cb80b20b6477<br>
- SHA-1: 27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-ota-npd35k-51dbae76.zip</a><br>
- MD5: 58312c4a5971818ef5c77a3f446003da<br>
- SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-ota-npd35k-834f047f.zip</a><br>
- MD5: 92b7d1fa252f7394e70f957c72d4aac8<br>
- SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-ota-npd35k-6ac91298.zip</a><br>
- MD5: 1461622ad53ea842b2722fa7b49b8172<br>
- SHA-1: 409c061668ab270774877d7f3eae44fa48d2b931
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-ota-npd35k-a0b2347f.zip</a><br>
- MD5: c60117f3640cc6db12386fd632289c7d<br>
- SHA-1: 87349c767c69efb4172c90ce1d88cf578c3d28b3
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-ota-npd35k-09897a1d.zip</a><br>
- MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
- SHA-1: 6f33742290eb46f2561891f38ca2e754b4e50c6a
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html-intl/intl/pt-br/preview/download.jd b/docs/html-intl/intl/pt-br/preview/download.jd
index b0f23e5..111c183 100644
--- a/docs/html-intl/intl/pt-br/preview/download.jd
+++ b/docs/html-intl/intl/pt-br/preview/download.jd
@@ -286,7 +286,7 @@
</p>
<p>
- Se decidir que deseja obter atualizações por OTA após atualizar um dispositivo manualmente,
+ Se decidir que deseja obter atualizações por OTA após atualizar um dispositivo manualmente,
basta inscrevê-lo no <a href="https://g.co/androidbeta">programa beta
do Android</a>. É possível inscrever dispositivos a qualquer momento para receber a próxima atualização do Preview
por OTA.
@@ -300,65 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npd35k-factory-5ba40535.tgz</a><br>
- MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
- SHA-1: 5ba4053577007d15c96472206e3a79bc80ab194c
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npd35k-factory-a33bf20c.tgz</a><br>
- MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
- SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npd35k-factory-81c341d5.tgz</a><br>
- MD5: e93de7949433339856124c3729c15ebb<br>
- SHA-1: 81c341d57ef2cd139569b055d5d59e9e592a7abd
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npd35k-factory-2b50e19d.tgz</a><br>
- MD5: 565be87ebb2d5937e2abe1a42645864b<br>
- SHA-1: 2b50e19dae2667b27f911e3c61ed64860caf43e1
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
- MD5: a8464e15c6683fe2afa378a63e205fda<br>
- SHA-1: 2e89ebe67a46b2f3beb050746c13341cd11fa678
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npd35k-factory-1de74874.tgz</a><br>
- MD5: c0dbb7db671f61b2785da5001cedefcb<br>
- SHA-1: 1de74874f8d83e14d642f13b5a2130fc2aa55873
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npd35k-factory-b4eed85d.tgz</a><br>
- MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
- SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
- MD5: 7d34a9774fdd6e025d485ce6cfc23c4c<br>
- SHA-1: 5ab1212bc9417269d391aacf1e672fff24b4ecc5
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
@@ -390,7 +398,7 @@
</ul>
</li>
<li><strong>Cancele a inscrição do dispositivo no programa beta do Android</strong>. Se o
- dispositivo estiver inscrito no <a href="https://g.co/androidbeta">programa beta
+ dispositivo estiver inscrito no <a href="https://g.co/androidbeta">programa beta
do Android</a>, independentemente de qual ele seja, você poderá simplesmente cancelar a inscrição.
<p>
O dispositivo receberá uma atualização por OTA para a versão
@@ -465,7 +473,7 @@
<p>Agora, é possível iniciar o emulador do Android com o AVD Android N Preview.</p>
<p>
-Para ter a melhor experiência possível com o emulador do Android, instale o
+Para ter a melhor experiência possível com o emulador do Android, instale o
Android Studio 2.1 ou mais recente, que oferece suporte ao <a href="http://tools.android.com/tech-docs/emulator">Android Emulator 2.0</a>,
cujo desempenho é muito superior ao do emulador no
Android Studio 1.5.</p>
diff --git a/docs/html-intl/intl/ru/preview/download.jd b/docs/html-intl/intl/ru/preview/download.jd
index b286cad..3af4a5a 100644
--- a/docs/html-intl/intl/ru/preview/download.jd
+++ b/docs/html-intl/intl/ru/preview/download.jd
@@ -107,7 +107,7 @@
9.3. Google вправе в любое время прекратить действие настоящего Лицензионного соглашения, отправив предварительное уведомление или без него.
9.4 Действие настоящего Лицензионного соглашения автоматически прекращается без предварительного уведомления или выполнения иных действий сразу после следующего:
-(A) компания Google прекращает предоставление Preview или определенных частей Preview пользователям в той стране, в которой вы проживаете или используете услуги компании;
+(A) компания Google прекращает предоставление Preview или определенных частей Preview пользователям в той стране, в которой вы проживаете или используете услуги компании;
(B) компания Google выпускает окончательную версию Android SDK.
9.5 В случае прекращения действия настоящего Лицензионного соглашения прекращается действие лицензии, предоставленной в рамках Лицензионного соглашения, и вам следует незамедлительно прекратить любое использование Preview, тогда как положения, изложенные в разделах 10, 11, 12 и 14 продолжают действовать бессрочно.
@@ -264,7 +264,7 @@
вручную записать его во флэш-память устройства. См. информацию в следующей таблице, чтобы загрузить системный образ
для своего тестового устройства. Запись вручную во флэш-память устройства удобна, если требуется
точное управление средой тестирования или частая переустановка,
-например при автоматическом тестировании.
+например при автоматическом тестировании.
</p>
<!-- You can flash by ota or system image --><p>
@@ -289,7 +289,7 @@
Если вы захотите получить обновления по беспроводной связи после записи на устройство вручную,
вам нужно просто зарегистрировать устройство в <a href="https://g.co/androidbeta">программе
бета-тестировании Android</a>. Вы можете зарегистрировать устройство в любое время для получения следующего обновления предварительной версии
-по беспроводной связи.
+по беспроводной связи.
</p>
<table>
@@ -300,64 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npc56p-preview-6c877a3d.tgz</a><br>
- MD5: b5cf874021023b398f5b983b24913f5d<br>
- SHA-1: 6c877a3d9fae7ec8a1678448e325b77b7a7b143a
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npc56p-preview-54b13c67.tgz</a><br>
- MD5: af183638cf34e0eb944a1957d7696f60<br>
- SHA-1: 54b13c6703d369cc79a8fd8728fe4103c6343973
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npc56p-preview-85ffc1b1.tgz</a><br>
- MD5: bc4934ea7bd325753eee1606d3725a24<br>
- SHA-1: 85ffc1b1be402b1b96f9ba10929e86bba6c6c588
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npc56p-preview-0e8ec8ef.tgz</a><br>
- MD5: c901334c6158351e945f188167ae56f4<br>
- SHA-1: 0e8ec8ef98c7a8d4f58d15f90afc5176303efca4
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npc56p-preview-1bafdbfb.tgz</a><br>
- MD5: 7bb95bebc478d7257cccb4652899d1b4<br>
- SHA-1: 1bafdbfb502e979a9fe4c257a379c4c7af8a3ae6
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npc56r-preview-7027d5b6.tgz</a><br>
- MD5: f5d3d8f75836ccfe4c70e8162e498be4<br>
- SHA-1: 7027d5b662bceda4c80a91a0a14ef0e5a7ba795b
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npc56p-preview-335a86a4.tgz</a><br>
- MD5: 4e21fb183bbbf467bee91598d587fd2e<br>
- SHA-1: 335a86a435ee51f18464de343ad2e071c38f0e92
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
+
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npc56p-preview-82472ebc.tgz</a><br>
- MD5: 983e083bc7cd0c4a2d39d6ebaa20202a<br>
- SHA-1: 82472ebc9a6054a103f53cb400a1351913c95127
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
diff --git a/docs/html-intl/intl/vi/preview/download.jd b/docs/html-intl/intl/vi/preview/download.jd
index f6aa7cc..8b2a272 100644
--- a/docs/html-intl/intl/vi/preview/download.jd
+++ b/docs/html-intl/intl/vi/preview/download.jd
@@ -209,7 +209,7 @@
<h2 id="device-preview">Thiết lập thiết bị phần cứng</h2>
<p>
- Bản N Developer Preview cung cấp các cập nhật hệ thống cho một loạt các thiết bị phần cứng
+ Bản N Developer Preview cung cấp các cập nhật hệ thống cho một loạt các thiết bị phần cứng
mà bạn có thể sử dụng để kiểm thử ứng dụng của bạn, từ điện thoại tới máy tính bảng và TV.
</p>
@@ -220,8 +220,8 @@
<ul>
<li><strong>Đăng ký cập nhật hệ thống tự động qua vô tuyến cho thiết bị</strong> thông qua
- <a href="https://g.co/androidbeta">Chương trình Android Beta</a>. Sau khi đăng ký, thiết bị của bạn sẽ nhận được
- qua sóng vô tuyến các cập nhật định kỳ về tất cả bản dựng theo mốc trong bản N Developer Preview. Cách tiếp cận này
+ <a href="https://g.co/androidbeta">Chương trình Android Beta</a>. Sau khi đăng ký, thiết bị của bạn sẽ nhận được
+ qua sóng vô tuyến các cập nhật định kỳ về tất cả bản dựng theo mốc trong bản N Developer Preview. Cách tiếp cận này
được khuyến khích bởi nó cho phép bạn chuyển tiếp liền mạch từ môi trường hiện tại của bạn
qua nhiều bản phát hành khác nhau của N Developer Preview.</li>
<li><strong>Tải xuống ảnh hệ thống của Developer Preview và flash thiết bị</strong>.
@@ -264,7 +264,7 @@
flash thủ công nó vào thiết bị của bạn. Xem bảng dưới đây để tải xuống ảnh hệ thống
cho thiết bị kiểm thử của bạn. Việc flash thủ công thiết bị sẽ hữu ích nếu bạn cần
kiểm soát chính xác môi trường kiểm thử hoặc cần phải cài đặt lại thường xuyên,
- chẳng hạn như cho kiểm thử tự động.
+ chẳng hạn như cho kiểm thử tự động.
</p>
<!-- You can flash by ota or system image --><p>
@@ -286,10 +286,10 @@
</p>
<p>
- Nếu bạn quyết định muốn nhận cập nhật qua vô tuyến sau khi đã flash thủ công thiết bị,
+ Nếu bạn quyết định muốn nhận cập nhật qua vô tuyến sau khi đã flash thủ công thiết bị,
tất cả những gì bạn cần làm là đăng ký <a href="https://g.co/androidbeta">Chương trình Android
Beta</a> cho thiết bị. Bạn có thể đăng ký thiết bị bất cứ lúc nào để nhận được
- bản cập nhật qua vô tuyến tiếp theo của Preview.
+ bản cập nhật qua vô tuyến tiếp theo của Preview.
</p>
<table>
@@ -300,64 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npc56p-preview-6c877a3d.tgz</a><br>
- MD5: b5cf874021023b398f5b983b24913f5d<br>
- SHA-1: 6c877a3d9fae7ec8a1678448e325b77b7a7b143a
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npc56p-preview-54b13c67.tgz</a><br>
- MD5: af183638cf34e0eb944a1957d7696f60<br>
- SHA-1: 54b13c6703d369cc79a8fd8728fe4103c6343973
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npc56p-preview-85ffc1b1.tgz</a><br>
- MD5: bc4934ea7bd325753eee1606d3725a24<br>
- SHA-1: 85ffc1b1be402b1b96f9ba10929e86bba6c6c588
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npc56p-preview-0e8ec8ef.tgz</a><br>
- MD5: c901334c6158351e945f188167ae56f4<br>
- SHA-1: 0e8ec8ef98c7a8d4f58d15f90afc5176303efca4
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npc56p-preview-1bafdbfb.tgz</a><br>
- MD5: 7bb95bebc478d7257cccb4652899d1b4<br>
- SHA-1: 1bafdbfb502e979a9fe4c257a379c4c7af8a3ae6
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npc56r-preview-7027d5b6.tgz</a><br>
- MD5: f5d3d8f75836ccfe4c70e8162e498be4<br>
- SHA-1: 7027d5b662bceda4c80a91a0a14ef0e5a7ba795b
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npc56p-preview-335a86a4.tgz</a><br>
- MD5: 4e21fb183bbbf467bee91598d587fd2e<br>
- SHA-1: 335a86a435ee51f18464de343ad2e071c38f0e92
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
+
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npc56p-preview-82472ebc.tgz</a><br>
- MD5: 983e083bc7cd0c4a2d39d6ebaa20202a<br>
- SHA-1: 82472ebc9a6054a103f53cb400a1351913c95127
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
@@ -423,7 +432,7 @@
<li>Nhấp vào tab <strong>SDK Tools</strong>, rồi chọn
<strong>Android SDK Build Tools</strong>, <strong>Android SDK
- Platform-Tools</strong>, và các hộp kiểm <strong>Android SDK Tools</strong>
+ Platform-Tools</strong>, và các hộp kiểm <strong>Android SDK Tools</strong>
.
</li>
@@ -464,7 +473,7 @@
<p class="note"><strong>Lưu ý:</strong>
Nếu bạn hiện đang sử dụng Android Studio 2.0 Beta, một vấn đề đã được biết đến
- sẽ ngăn cản bạn tạo AVD bằng ảnh hệ thống của N Preview, vì vậy
+ sẽ ngăn cản bạn tạo AVD bằng ảnh hệ thống của N Preview, vì vậy
hiện bạn cần sử dụng preview của Android Studio 2.1 để tạo các AVD.
</p>
diff --git a/docs/html-intl/intl/zh-cn/preview/download-ota.jd b/docs/html-intl/intl/zh-cn/preview/download-ota.jd
index ab1408f..5d17abc 100644
--- a/docs/html-intl/intl/zh-cn/preview/download-ota.jd
+++ b/docs/html-intl/intl/zh-cn/preview/download-ota.jd
@@ -202,65 +202,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-ota-npd35k-b8cfbd80.zip</a><br>
- MD5:15fe2eba9b01737374196bdf0a792fe9<br>
- SHA-1:5014b2bba77f9e1a680ac3f90729621c85a14283
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-ota-npd35k-078e6fa5.zip</a><br>
- MD5: e8b12f7721c53af9a450f7058928a5fc<br>
- SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-ota-npd35k-88457699.zip</a><br>
- MD5:3fac09fef759dde26e57cb80b20b6477<br>
- SHA-1:27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-ota-npd35k-51dbae76.zip</a><br>
- MD5:58312c4a5971818ef5c77a3f446003da<br>
- SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-ota-npd35k-834f047f.zip</a><br>
- MD5:92b7d1fa252f7394e70f957c72d4aac8<br>
- SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-ota-npd35k-6ac91298.zip</a><br>
- MD5:1461622ad53ea842b2722fa7b49b8172<br>
- SHA-1:409c061668ab270774877d7f3eae44fa48d2b931
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-ota-npd35k-a0b2347f.zip</a><br>
- MD5: c60117f3640cc6db12386fd632289c7d<br>
- SHA-1:87349c767c69efb4172c90ce1d88cf578c3d28b3
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-ota-npd35k-09897a1d.zip</a><br>
- MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
- SHA-1:6f33742290eb46f2561891f38ca2e754b4e50c6a
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html-intl/intl/zh-cn/preview/download.jd b/docs/html-intl/intl/zh-cn/preview/download.jd
index 0aa115f..06bf2bf 100644
--- a/docs/html-intl/intl/zh-cn/preview/download.jd
+++ b/docs/html-intl/intl/zh-cn/preview/download.jd
@@ -300,65 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npd35k-factory-5ba40535.tgz</a><br>
- MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
- SHA-1:5ba4053577007d15c96472206e3a79bc80ab194c
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npd35k-factory-a33bf20c.tgz</a><br>
- MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
- SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npd35k-factory-81c341d5.tgz</a><br>
- MD5: e93de7949433339856124c3729c15ebb<br>
- SHA-1:81c341d57ef2cd139569b055d5d59e9e592a7abd
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npd35k-factory-2b50e19d.tgz</a><br>
- MD5:565be87ebb2d5937e2abe1a42645864b<br>
- SHA-1:2b50e19dae2667b27f911e3c61ed64860caf43e1
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
- MD5: a8464e15c6683fe2afa378a63e205fda<br>
- SHA-1:2e89ebe67a46b2f3beb050746c13341cd11fa678
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npd35k-factory-1de74874.tgz</a><br>
- MD5: c0dbb7db671f61b2785da5001cedefcb<br>
- SHA-1:1de74874f8d83e14d642f13b5a2130fc2aa55873
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npd35k-factory-b4eed85d.tgz</a><br>
- MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
- SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
- MD5:7d34a9774fdd6e025d485ce6cfc23c4c<br>
- SHA-1:5ab1212bc9417269d391aacf1e672fff24b4ecc5
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
diff --git a/docs/html-intl/intl/zh-tw/preview/download.jd b/docs/html-intl/intl/zh-tw/preview/download.jd
index a98000a..caa2a55 100644
--- a/docs/html-intl/intl/zh-tw/preview/download.jd
+++ b/docs/html-intl/intl/zh-tw/preview/download.jd
@@ -264,7 +264,7 @@
-
+
</p>
<!-- You can flash by ota or system image --><p>
@@ -289,7 +289,7 @@
如果您決定手動更新裝置後要接收 OTA 更新,您唯一要做的事是在 <a href="https://g.co/androidbeta">Android Beta 計劃</a>中註冊裝置。您可以隨時註冊裝置,以隔空傳輸方式接收下一個「Preview」更新。
-
+
</p>
<table>
@@ -300,64 +300,73 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
- <td><a href="#top" onclick="onDownload(this)">bullhead-npc56p-preview-6c877a3d.tgz</a><br>
- MD5:b5cf874021023b398f5b983b24913f5d<br>
- SHA-1:6c877a3d9fae7ec8a1678448e325b77b7a7b143a
+ <td><a href="#top" onclick="onDownload(this)"
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
- <td><a href="#top" onclick="onDownload(this)">shamu-npc56p-preview-54b13c67.tgz</a><br>
- MD5:af183638cf34e0eb944a1957d7696f60<br>
- SHA-1:54b13c6703d369cc79a8fd8728fe4103c6343973
+ <td><a href="#top" onclick="onDownload(this)"
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
- <td><a href="#top" onclick="onDownload(this)">angler-npc56p-preview-85ffc1b1.tgz</a><br>
- MD5:bc4934ea7bd325753eee1606d3725a24<br>
- SHA-1:85ffc1b1be402b1b96f9ba10929e86bba6c6c588
+ <td><a href="#top" onclick="onDownload(this)"
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
- <td><a href="#top" onclick="onDownload(this)">volantis-npc56p-preview-0e8ec8ef.tgz</a><br>
- MD5:c901334c6158351e945f188167ae56f4<br>
- SHA-1:0e8ec8ef98c7a8d4f58d15f90afc5176303efca4
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
- <td><a href="#top" onclick="onDownload(this)">volantisg-npc56p-preview-1bafdbfb.tgz</a><br>
- MD5:7bb95bebc478d7257cccb4652899d1b4<br>
- SHA-1:1bafdbfb502e979a9fe4c257a379c4c7af8a3ae6
+ <td><a href="#top" onclick="onDownload(this)"
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
- <td><a href="#top" onclick="onDownload(this)">fugu-npc56r-preview-7027d5b6.tgz</a><br>
- MD5:f5d3d8f75836ccfe4c70e8162e498be4<br>
- SHA-1:7027d5b662bceda4c80a91a0a14ef0e5a7ba795b
+ <td><a href="#top" onclick="onDownload(this)"
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
- <td><a href="#top" onclick="onDownload(this)">ryu-npc56p-preview-335a86a4.tgz</a><br>
- MD5:4e21fb183bbbf467bee91598d587fd2e<br>
- SHA-1:335a86a435ee51f18464de343ad2e071c38f0e92
+ <td><a href="#top" onclick="onDownload(this)"
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
+
<tr id="seed">
- <td>一般行動裝置 4G (Android One) <br>"seed"</td>
- <td><a href="#top" onclick="onDownload(this)">seed_l8150-npc56p-preview-82472ebc.tgz</a><br>
- MD5:983e083bc7cd0c4a2d39d6ebaa20202a<br>
- SHA-1:82472ebc9a6054a103f53cb400a1351913c95127
+ <td>General Mobile 4G (Android One) <br>"seed"</td>
+ <td><a href="#top" onclick="onDownload(this)"
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 11e06f1..0ee8157 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -361,6 +361,8 @@
to: /about/dashboards/index.html
- from: /resources/community-groups.html
to: /support.html
+- from: /community/index.html
+ to: /support.html
- from: /guide/tutorials/
to: /resources/tutorials/
- from: /resources/tutorials/views/hello-linearlayout.html
@@ -801,8 +803,8 @@
to: http://android-developers.blogspot.com/2016/03/first-preview-of-android-n-developer.html
- from: /reference/org/apache/http/...
to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
-- from: /shareables/
- to: https://commondatastorage.googleapis.com/androiddevelopers/shareables/
+- from: /shareables/...
+ to: https://commondatastorage.googleapis.com/androiddevelopers/shareables/...
- from: /downloads/
to: https://commondatastorage.googleapis.com/androiddevelopers/
- from: /training/performance/battery/network/action-any-traffic.html
@@ -1193,3 +1195,7 @@
to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle
- from: /r/studio-ui/sdk-manager.html
to: https://developer.android.com/studio/intro/update.html#sdk-manager
+- from: /r/studio-ui/newjclass.html
+ to: /studio/write/index.html
+- from: /r/studio-ui/menu-help.html
+ to: /studio/intro/index.html
diff --git a/docs/html/community/index.html b/docs/html/community/index.html
deleted file mode 100644
index e3834ba..0000000
--- a/docs/html/community/index.html
+++ /dev/null
@@ -1,320 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Android Developers Community</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
- var toRoot = "/";
- var devsite = false;
-</script>
-
-<script type="text/javascript">
- var _gaq = _gaq || [];
- _gaq.push(['_setAccount', 'UA-5831155-1']);
- _gaq.push(['_trackPageview']);
-
- (function() {
- var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
- ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
- })();
-</script>
-
-<style>
-#header {
- padding: 2.2em 0 0.2em 0;
-}
-#header-wrap h1 {
- margin:0;
- padding:0;
- line-height:16px;
-}
-#body-content {
- margin-top:20px;
-}
-#nav-x.wrap {
- overflow:auto;
-}
-h2 {
- border-bottom:1px solid #CCC;
-}
-</style>
-</head>
-
-
-
-
-
-
-<body>
-
-
-<!-- Header -->
-<div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo">
- <a href="/index.html">
- <img src="http://developer.android.com/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
- </a>
- </div>
- <div class="col-8">
- <h1>Community Outreach</h1>
- </div>
-
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
- <div class="morehover" id="moremenu">
- <div class="top"></div>
- <div class="mid">
- <div class="header">Links</div>
- <ul style="margin-bottom:0">
- <li><a href="https://www.youtube.com/user/androiddevelopers">Android Developers Live</a></li>
- <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
- <li><a href="http://developer.android.com/training/">Android Developer Training</a></li>
- <li><a href="http://developer.android.com/samples/">Samples</a></li>
- </ul>
- <br class="clear-fix">
- </div>
- <div class="bottom"></div>
- </div><!-- end morehover -->
- </div><!-- end menu-container -->
- </div><!-- end header-wrap -->
-</div>
-<!-- /Header -->
-
-<div id="nav-x" class="wrap">
- <ul class="nav-x col-9 develop">
- <li><a href="#News">News</a></li>
- <li><a href="#Community">Community</a></li>
- <li><a href="#Content">Content</a></li>
- <li><a href="#Social">Social</a></li>
- </ul>
-</div>
-
-
-<!-- MAIN CONTENT -->
-
-
-<div class="wrap" id="body-content">
-
-<img src="/images/community/aco1small.png" alt="" style="float:right;margin:20px 0 0 40px">
-
-<p style="clear:left">
- Android is working with communities to
-<ul>
-<li>Create a cooperative relationship between highly impactful communities and high performing developers</li>
-<li>Strengthen relationships between Android and coding communities so that developers have a motivation to interact with those communities</li>
-<li>Reward communities for attracting developers by providing them with resources and direct access to the Android team</li></ul>
-<p>Our IMPACT is measured by <strong>good apps</strong> and a <strong>thriving community</strong></p>
-
-<h2 id="News" style="clear:left">News</h2>
-<p>Our current theme is on the <b><em>Android 4.4 KitKat and Updated Developer Tools</em></b> release, with new ways to create beautiful apps, printing and storage frameworks, low-power sensors, new media capabilities and RenderScript in the NDK.</p>
-
-<div class="col-8" style="margin-left:0">
-<img src="/images/community/kk-hero2.jpg" alt="" height="277">
-</div>
-
-<div class="col-8" style="margin-right:0">
-<h3 style="margin-top:0"><a href="http://developer.android.com/about/versions/kitkat.html">Android 4.4 Platform Highlights</a></h3>
-<p>Android KitKat brings all of Android's most innovative, most beautiful, and most useful features to more devices everywhere.</p>
-
-<h3><a href="http://developer.android.com/about/versions/android-4.4.html">Android 4.4 APIs</a></h3>
-<p>Android 4.4 (KITKAT) is a new release for the Android platform that offers new features for users and app developers. This document provides an introduction to the most notable new APIs.</p>
-
-<h3><a href="https://play.google.com/store/devices/details?id=nexus_5_white_32gb">New Nexus 5</a></h3>
-<p>Nexus 5 helps you capture the everyday and the epic in fresh new ways. It's the slimmest and fastest Nexus phone ever made, powered by Android 4.4, KitKat.</p>
-</div>
-<p></p>
-
-<h2 id="Community" style="clear:left">Community Spotlight</h2>
-
-<div class="col-8" style="margin-left:0">
-<h3>Android Community Groups</h3>
-<h4>July 2013</h4>
-<p><a href="mailto:gtugam@gmail.com">GDG Armenia</a> held <a href="http://eca.hackathon.am/">ecaHack Yerevan</a>, an Android hackathon featuring "Angry Designers vs Android Developers", where the designers had a look into developers apps and gave them some advices regarding to design. The hackathon was sponsored by Alcatel One Touch and each member of the winner team got one Alcatel One Touch Idol. Check out the <a href="https://plus.google.com/u/0/events/gallery/cgj9d39gphiephlq0e2899dv6j4?cfem=1">photos.</a></p>
-<h4>September 2013</h4>
-<p><a href="mailto:soham.mondal@gmail.com">GDG Blrdroid</a> held a <a href="http://www.meetup.com/blrdroid/events/140665852/">meetup</a> on performance optimisation.</p>
-<p><a href="mailto:baileye@gmail.com">GDG Dublin</a> held their meetup with a talk on AdMob for Android and iOS, entitled “Admob for Android and iOS developers”. </p>
-<p>GDG Mbale’s <a href="mailto:nsubugahassan@gmail.com">Hassan Nsubuga</a> has been managing a university <a href="https://plus.google.com/103735976334615631393/posts/gQMWCGUhMBn">course session</a> since September. They are now through with the basics and have a firm foundation, so this month they will be doing a lot of advanced stuff including exploring the latest API enhancements with KitKat. </p>
-<p><a href="mailto:wojtek.kalicinski@gmail.com">GDG Warsaw</a> held an Android Barcamp focused on App Quality. The discussion was moderated by GDG organisers, but the talks were given by the community members, including some top Android companies and developers in Poland.</p>
-<h4>October 2013</h4>
-<p><a href="mailto:benjamin.r.m.weiss@gmail.com">GDG Berlin Android</a> held their <a href="https://berlin.ticketbud.com/devfest-berlin-2013">DevFest</a>.</p>
-<p><a href="mailto:soham.mondal@gmail.com">GDG Blrdroid</a> held their <a href="http://www.meetup.com/blrdroid/events/144457162/">meetup</a> in collaboration with GDG Bangalore, where they talked about a wider range of things from incorporating user feedback to effectively using the cell radio. David McLaughlin from the Developer Relations team also visited during the meetup and delivered the keynote. They also hit a milestone with its 4th anniversary on the 9th of October and crossed 4300 members in the past few days so its been a memorable couple of months for them.</p>
-<p><a href="mailto:hir3npatel@gmail.com">GDG Cape Town</a> held an <a href="https://plus.google.com/108309780217630451504/posts/9BTCEqnBHoQ">Android Workshop</a> where they gave away lots of branded KitKats.</p>
-<p><a href="mailto:baileye@gmail.com">GDG Dublin</a> held its DevFest, which featured a codeLab on Android titled “Codelab: Intro to Android Development.”</p>
-<p><a href="mailto:hugo@dutchaug.org">GDG Dutch Android User Group</a> held their <a href="http://www.devfest.nl/program">DevFest</a>. They had a bunch of Android sessions, mostly by local speakers. In addition to the Android sessions, they also ran a workshop on writing custom views.</p>
-<p><a href="mailto:hugo@dutchaug.org">Hugo Visser</a> from the Dutch Android User Group spoke at <a href="https://bitbucket.org/qbusict/cupboard">DroidCon UK barcamp</a>, where he delivered a talk on Cupboard, a simple and lightweight persistence framework, specifically for Android.</p>
-<p><a href="mailto:prajyotmainkar@gmail.com">GDG GAUG</a> held the <a href="https://plus.google.com/110448195989468248957/posts/8doJuCpySWS">Google Devfest 2013</a>, where they had two tracks and more than 200 delegates attending. They also had a <a href="https://plus.google.com/110448195989468248957/posts/6rxLzj2Rpde">Hackathon</a> and they hit the <a href="https://plus.google.com/110448195989468248957">1000 member</a> mark this month, which makes them the second largest android community in India after GDG Blrdroid. </p>
-<p><a href="mailto:cyrilleguipie@gmail.com">GDG Miage</a> held their DevFest where they gave a talk about Intents and Services. The also held a startup Weekend Bootcamp where they talked about Activites and Layouts. They will also hold an Android Workshop in December.</p>
-<p><a href="mailto:gabriel.kb@gmail.com">GDG Uruguay</a> had their <a href="http://gdg.uy/devfest2013">DevFest</a>, where they held an Android workshop for beginners as an Android vs iOS comparison, a session on best practices using YouTube APIs in Android, and What's new in Google for developers (with a special section about Android). You can see pictures on <a href="https://plus.google.com/114520966453242230657/posts/dqZAuMqc12Z">the G+ page</a>. </p>
-
-<h4>November 2013</h4>
-<p><a href="mailto:yorogoule@gmail.com">Abidjandroid/GDG Côte d'Ivoire</a> held an Android Launch Party featuring the KitKat release.</p>
-<p>The <a href="mailto:hugo@dutchaug.org">Dutch Android User Group</a> had a very interactive presentation on Android Code Puzzlers and Tips & tricks, where they rewarded participation by giving out books, tshirts, jelly beans and kitkats. The presentation was at the <a href="http://www.nljug.org/jfall">Dutch JFall conference</a>, organized by the NLJUG. It's a large yearly Java conference and the DAUG had the only Android session there.</p>
-<p>The <a href="mailto:benjamin.r.m.weiss@gmail.com">GDG Berlin Android</a> meetup this month featured the KitKat release.</p>
-<p><a href="mailto:soham.mondal@gmail.com">The GDG Blrdroid</a> <a href="http://www.meetup.com/blrdroid/events/148210762/%20">meetup</a> was another focused on KitKat.</p>
-<p>At the <a href="mailto:amahdy7@gmail.com">GDG Cairo</a> <a href="https://plus.google.com/events/co59j0870in5a4kh8n5navifnm8">DevFest</a> there was a "What's new in Android SDK" session on day 1, and an Android workshop on day 2. Kitkat also provided interest in the sessions and the snacks bar. The KitKat <a href="http://buff.ly/HNE7yq">presentation</a>, the track organization, and everything related to it were all organized by women.</p>
-<p><a href="mailto:hir3npatel@gmail.com">GDG Cape Town</a> held an Android Workshop.</p>
-<p><a href="mailto:alessandro.gbridge@gmail.com">GDG Udine</a> organized a talk after the release of KitKat for a school in Pordenone.</p>
-<p><a href="mailto:hugo@dutchaug.org">Hugo Visser</a> from Droidcon Netherlands organized an Android hackathon themed "Location, Location, Location". </p>
-<p><a href="mailto:eyal.lezmy@gmail.com">Paris Android User Group</a> welcomed <a href="https://plus.google.com/+RomainGuy">Romain Guy</a> and <a href="https://plus.google.com/+ChetHaase">Chet Haase</a> to their meetup this month. They’ll be meeting up with other GDG leads and UG managers meet at <a href="https://plus.google.com/events/cupo201fjreo9g9t2e596gv8nd4">Devoxx</a> next Thursday.</p>
-<p><a href="mailto:wojtek.kalicinski@gmail.com">GDG Warsaw</a> had over 250 attendees at their DevFest, which featured session tracks on Android and Web and a whole day of Code Labs in Android, AngularJS and Arduino.</p>
-<h4>December 2013</h4>
-<p><a href="mailto:prajyotmainkar@gmail.com">GDG GAUG</a> are planning a codelab and hackathon.</p>
-<p><a href="mailto:psvensson@gmail.com">Peter Svensson</a> spoke at <a href="http://swdc.se/droidcon/events/stockholm-2013/">DroidCon Stockholm</a></p>
-The unstoppable <a href="mailto:bonbhel@gmail.com">Max Bonbhel</a> from the African GDG Android is hosting AAC 2014 and Android GDG Barcamp events in December. Also, in order to encourage African Java developers to move to the Android platform, he created the <a href="https://docs.google.com/spreadsheet/ccc?key=0AtFPan-z2ps-dHBtX1luY2pRQjdtRjliUGcxMVBNeVE&usp=sharing#gid=0">Africa Android Training (AAT) program</a>. The training material targets developers with different levels of experience in Java development. More than 60 developers have been taking part in the weekly sessions. The next 10 sessions will start Saturday, November 9, 2013. 260 GDG and Java User Group members have already registered from 12 Countries.
-<p> </p>
-</div>
-
-<div class="col-8" style="margin-right:0">
-<h3>Android Community Experts</h3>
-
-<h4>October 2013</h4>
-<p><a href="mailto:eyal.lezmy@gmail.com">Eyal Lezmy</a> presented two sessions. “<a href="http://bit.ly/andbigfail">Play Store bashing, learn from the biggest fails</a>” looked at several applications, mainly developed by huge companies, and analyzed why they failed to satisfy the users or the Android guidelines. “<a href="http://bit.ly/lifeofapp">Android, the life of your app</a>” tells a story, living the life of a user, identify the frustrations he can encounter and present ways to avoid it, as a developer.</p>
-<p><a href="mailto:mariux01@gmail.com">Mario Viviani</a> presented and recorded the next <a href="http://www.youtube.com/watch?v=jaT0bYhhaGY">Android App Clinic - Italia</a>. This episode was regarding the Cards UI and SMS app support in Android 4.4. They experimented with a short form of the video (10 minutes instead of 20) and in less than day it got almost 400+ views -- which is great considering it's in Italian! The previous episode reached 1300 views all-time and was the most successful video of GDL Italia in Q2.</p>
-<p><a href="mailto:m.kaeppler@gmail.com">Matthias Käppler</a> contributed the <a href="https://github.com/Netflix/RxJava/tree/master/rxjava-contrib/rxjava-android">first Android specific component</a> to the RxJava project, and spoke about <a href="http://uk.droidcon.com/2013/sessions/conquering-concurrency-bringing-the-reactive-extensions-to-the-android-platform/">RxJava and reactive programming on Android</a> at DroidCon UK. He has also open sourced <a href="https://github.com/mttkay/memento">Memento</a>, an Android annotation processor to replace the deprecated onRetainNonConfigurationInstance.</p>
-<p><a href="mailto:wojtek.kalicinski@gmail.com">Wojtek Kaliciński</a>’s talk, "Android - is it time for a break yet?" highlights not only what's new in Android 4.4 KitKat, but also how to take your app to the next level by making sure you provide the best app experience possible to all 4.0+ users.</p>
-<a href="https://plus.sandbox.google.com/110448195989468248957/posts"><img src="/images/community/hackathon-gdgaug.jpg" alt="" align="right"></a>
-
-</div>
-
-<h2 id="Content" style="clear:left">New Content</h2>
-<div class="col-8" style="margin-left:0">
-<p><h4>Android 4.4 What's New</h4>
-KitKat has been optimized to run on a much broader range of devices, with special focus on the millions of entry-level devices that have as little as 512MB RAM. To help, we've created new APIs, better tools, and better documentation to let you create apps that perform well on all devices.<br>
-Check out this video summary of some of the most significant developer features in the latest Android release, including new ways to make your apps beautiful, NFC Host Card Emulation, a printing framework, the storage access framework, low-power step detector and step counter sensors, and more!<br>
-<h5><a href="http://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></h5>
-<i>Be sure to get the <a href="http://developer.android.com/about/versions/android-4.4.html">full Android 4.4 API Overview</a>, and take a look at our <a href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">related DevBytes videos</a></i></p>
-
-<p><h4>WebView in Android 4.4</h4>
-Android 4.4 (API level 19) introduces a new version of WebView that is based on Chromium. This change upgrades WebView performance and standards support for HTML5, CSS3, and JavaScript to match the latest web browsers. Any apps using WebView will inherit these upgrades when running on Android 4.4 and higher.
-<h5><a href="http://developer.android.com/guide/webapps/migrating.html">API Guide</a></h5>
-</p>
-
-<p><h4>Android 4.4 Immersive Mode</h4>
-With Android 4.4 KitKat, your apps can now truly go full-screen with a new Immersive Mode. Immersive Mode lets your apps hide the system's status and navigation bars while capturing all touch events—ideal for rich interactive content such as books and games. This video demonstrates how to use the new API, in addition to recapping earlier full-screen APIs on Android.
-<h5><a href="http://www.youtube.com/watch?v=cBi8fjv90E4&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></h5>
-<h5><a href="http://developer.android.com/samples/ImmersiveMode/index.html">Sample</a></h5>
-</p>
-
-<p>
-<h4>Android 4.4 Storage Access Framework - Provider</h4>
-Get up to speed on the new document storage API in Android 4.4 KitKat. This video gets you up and running with your own DocumentProvider by stepping you through the making of a simple cloud storage app.
-<h5><a href="http://www.youtube.com/watch?v=zxHVeXbK1P4&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></h5>
-<h5><a href="http://developer.android.com/guide/topics/providers/document-provider.html">Training</a></h5>
-<h5><a href="http://developer.android.com/samples/StorageProvider/index.html">Sample</a>, <a href="https://play.google.com/store/apps/details?id=com.box.android">Box Application</a></h5>
-</blockquote>
-
-</p>
-
-
-<p><h4>Android 4.4 Storage Access Framework - Client</h4>
-Get up to speed on the new storage access framework in Android 4.4 KitKat. This video teaches you how to quickly create, edit, save and delete documents provided by other apps as a client of the storage access framework.
-<h5><a href="http://www.youtube.com/watch?v=UFj9AEz0DHQ&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></h5>
-<h5><a href="http://developer.android.com/samples/StorageClient/index.html">Sample</a></h5>
-</p>
-
-<p><h4>Android 4.4 Closed Captioning</h4>
-Displaying closed captions in your app's videos can be quick and simple in Android 4.4 KitKat,. Learn how to attach timed text tracks to VideoView and allow users to customize how captions are displayed.
-<h5><a href="http://www.youtube.com/watch?v=hCRGc2PcmB8&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a>
-</p>
-</h5>
-</div>
-
-<div class="col-8" style="margin-right:0">
-
-<p>
-<h4>Android 4.4 Transitions</h4>
-In this episode, we introduce the new Transitions API in Android 4.4 Kitkat. This API provides a simple way for developers to provide animated segues to different scenes of their application, helping users to understand the application flow with very little code. The general approach is to tell the system that you'd like to run a transition animation, then make the necessary changes to your UI. The system figures out the differences and animates the changes.
-<h5><a href="http://www.youtube.com/watch?v=S3H7nJ4QaD8&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=3">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></p>
-</h5>
-<p><h4>Android 4.4: SMS APIs</h4>
-Android 4.4 KitKat introduces the new SMS APIs as well as the new concept of a default SMS app. This video discusses these new APIs and how your app should use them to send and receive SMS and MMS messages.<br>
-<h5><a href="http://www.youtube.com/watch?v=mdq0R2WQssQ&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></h5>
-<i>See also -<br>
-<a href="http://goo.gl/sw5NdH">Android Developer Blog post on Android 4.4 KitKat SMS APIs</a><br>
-<a href="http://goo.gl/7vTx3s">Android Protip on using booleans in your AndroidManifest.xml</a></i></p>
-
-
-<p><h4>Android 4.4 Printing API</h4>
-In this video, we introduce the new Printing API in Android 4.4 KitKat. This API provides a simple way for developers to print to cloud-connected printers using Google Cloud Print. It's really easy to print bitmaps, and HTML (that you generate on the device, or just web content).<br>
-<h5><a href="http://www.youtube.com/watch?v=Iub67ic87KI&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a></h5>
-<h5><a href="http://developer.android.com/training/printing/index.html">Training</a></h5>
-<i>Some pro-tips:</i>
-<ul>
- <li>For Webview/HTML printing, printing from javascript is not supported yet (window.print() for example). Also we are planning to address the limitations around WebView/HTML printing in future releases (eg: headers/footers, and specifying print ranges).</li>
-<li>We encourage developers to open Android Open Source bugs for features that they feel important as a feedback.</li>
-</ul>
-
-<p><h4>App Indexing</h4>
-In this episode we discuss the new App Indexing feature that we recently announced for Google Search for Android.<br>
-Currently, when you do a google search on the web, you get results that are links to websites. With App Indexing, you will be able to point Google Search users on Android directly to content within your app!
-If you’re an Android app developer who has a web presence and you want more control over how your content is accessed from search, via your website or Android app, App Indexing is a great feature for you to explore.
-Also, enabling your website and app for indexing is a way to increase engagement with your app by making the content more discoverable, and more accessible to users directly from the search results page.
-For information on App Indexing, please visit <a href="http://g.co/appindexing">http://g.co/appindexing</a>
-<h5><a href="http://www.youtube.com/watch?v=Xh_W82JgOms&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K">Video</a></h5>
-<h5><a href="https://drive.google.com/a/google.com/folderview?id=0BwhAiXVwzMoFc28wWEpyeE9qYTQ&usp=sharing">Presentation</a>
-</p>
-</h5>
-</div>
-
-<h2 id="Social" style="clear:left">Social</h2>
-<div class="col-8" style="margin-left:0">
-
-<h3 >G+</h3>
-
-<ul>
-<li><a href="https://plus.google.com/u/1/108967384991768947849/posts/1iVvwyfTM8y">What's New in Android 4.4</a>
- <ul>
- <li><a href="http://www.youtube.com/watch?v=HrFRY32i_sE">What's New in Android 4.4 [JAPANESE!]</a></li>
- <li><a href="https://www.youtube.com/watch?v=U9jAcwaETD4">What's New in Android 4.4 [KOREAN!]</a></li>
- <li><a href="https://plus.google.com/u/1/108967384991768947849/posts/WfqdvDG2Cyr">Quer saber das novidades do Android 4.4? [PORTUGUESE!]</a></li>
- </ul>
-</li>
-<li><a href="https://plus.google.com/u/1/+AndroidDevelopers/posts/femjRbay18f">Android 4.4 and Updated Developer Tools
-</a></li>
-<li><a href="https://plus.google.com/u/1/108967384991768947849/posts/P2q82aYN7do">Google Play Services 4.0
-</a></li>
-</ul>
-</div>
-
-<div class="col-8" style="margin-right:0">
-<h3>Blog</h3>
-
-<ul>
- <li><a href="http://android-developers.blogspot.hk/2013/10/android-44-kitkat-and-updated-developer.html">Android 4.4 KitKat and Updated Developer Tools</a></li>
- <li><a href="http://android-developers.blogspot.hk/2013/10/google-play-services-40.html">Google Play Services 4.0</a></li>
- <li><a href="http://android-developers.blogspot.hk/2013/10/making-your-app-content-more-accessible.html">Making your App Content more Accessible from Googl...</a></li>
- <li><a href="http://android-developers.blogspot.hk/2013/10/getting-your-sms-apps-ready-for-kitkat.html">Getting Your SMS Apps Ready for KitKat</a></li>
-</ul>
-</div>
-
-</div><!-- /MAIN CONTENT 'wrap' -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/distribute/stories/apps.jd b/docs/html/distribute/stories/apps.jd
index 9c2e8e9..76e9f5a 100644
--- a/docs/html/distribute/stories/apps.jd
+++ b/docs/html/distribute/stories/apps.jd
@@ -29,5 +29,5 @@
data-sortOrder="-timestamp"
data-cardSizes="6x6"
data-items-per-page="15"
- data-initial-results="3"></div>
+ data-initial-results="6"></div>
</div></section>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/aftenposten.jd b/docs/html/distribute/stories/apps/aftenposten.jd
new file mode 100644
index 0000000..f1f388e
--- /dev/null
+++ b/docs/html/distribute/stories/apps/aftenposten.jd
@@ -0,0 +1,80 @@
+page.title=Aftenposten Improves Retention by Allowing Readers to Customize Notifications
+page.metaDescription=Aftenposten upgraded their app and improved user retention.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/aftenposten.png
+page.timestamp=1468270114
+
+@jd:body
+
+<div class="figure" style="width:113px">
+ <img src="{@docRoot}images/distribute/stories/aftenposten-icon.png" height=
+ "106">
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ Aftenposten is one of the largest newspapers in Norway. Their <a class=
+ "external-link" href=
+ "https://play.google.com/store/apps/details?id=no.cita&e=-EnableAppDetailsPageRedesign">
+ news app</a> was released on Android in 2013.
+</p>
+
+<p>
+ Aftenposten found that sending too many notifications, with no user control
+ over the default <em>on</em> setting or differentiation between general and
+ breaking news, caused many people to uninstall their app. They changed the
+ user controls for notifications and used the native Android share button in
+ the app, <strong>which reduced user uninstalls</strong>.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ Aftenposten created a new onboarding flow that explained what notifications
+ were available, allowing readers to manage their preferences and customize up
+ to three topics. They also changed their custom share icon for the native
+ Android app.
+</p>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ The results showed that with the new notifications management onboarding
+ screen, <strong>uninstalls decreased by 9.2% over 60 days</strong>. And with
+ the option to customize notifications, 51% of readers decided to keep two out
+ of three topics turned on. This led to a <strong>28% decrease over 60 days in
+ the number of users muting notifications completely</strong>. It also
+ provided insight into users’ content preferences, with <em>Sport</em> being
+ the least-favored notification.
+</p>
+
+<p>
+ Aftenposten also increased share interactions by 17% just by replacing their
+ custom share icon with the native Android share icon.
+</p>
+
+<p>
+ Aftenposten commented that: <em>Many of our users who see the onboarding
+ screen interact with it by turning off at least one notification topic. This
+ means that users are accepting push from one or more topics, instead of
+ turning it off completely. Moreover, readers are sharing more articles since
+ we added the standard share Android icon.</em>
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Find out more about best practices for <a href=
+ "{@docRoot}design/patterns/notifications.html">Notifications</a> and <a href=
+ "{@docRoot}training/building-content-sharing.html">Building Apps with Content
+ Sharing</a>.
+</p>
diff --git a/docs/html/distribute/stories/apps/el-mundo.jd b/docs/html/distribute/stories/apps/el-mundo.jd
new file mode 100644
index 0000000..2ee813d
--- /dev/null
+++ b/docs/html/distribute/stories/apps/el-mundo.jd
@@ -0,0 +1,73 @@
+page.title=El Mundo Improves User Ratings and Engagement with Material Design
+page.metaDescription=El Mundo uses Material Design principles to enhance their app's user experience.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/el-mundo.png
+page.timestamp=1468270112
+
+@jd:body
+
+<div class="figure" style="width:113px">
+ <img src="{@docRoot}images/distribute/stories/el-mundo-icon.png" height=
+ "113">
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=com.gi.elmundo.main">El
+ Mundo</a>, one of Spain’s largest newspapers, integrated material design
+ principles into their app, which helped increase their Google Play Store
+ rating and improve user engagement.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ El Mundo decided to completely redesign their app to provide a higher quality
+ user experience, making it easier for their readers to engage with news
+ content. By implementing material design guidelines, they created a
+ consistent look and feel throughout their app.
+</p>
+
+<p>
+ After analyzing user comments, El Mundo discovered that readers considered
+ their app to be complicated and out-of-date. Therefore, they decided to
+ simplify the app’s functionality by removing features that were redundant.
+ They also removed sections of their app that were less relevant to their
+ readers, such as weather updates and movie trailers. Finally, they applied a
+ brand new internal development framework that they now use consistently
+ across all of their apps.
+</p>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ Following the re-launch of their material design app, El Mundo saw a
+ <strong>45% increase in the weekly install rate</strong>. Readers now spend
+ more time in the app, with the average time spent in-app increasing from one
+ to three minutes.
+</p>
+
+<p>
+ Additionally, this redesign resulted in more readers providing positive
+ feedback around the new experience, increasing the app rating in the Google
+ Play store by 25.8%, from 3.1 to 3.9.
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Learn how to integrate <a class="external-link" href=
+ "https://material.google.com">Material Design</a> guidelines and follow
+ <a class="external-link" href="https://design.google.com">design
+ principles</a> for your app.
+</p>
diff --git a/docs/html/distribute/stories/apps/segundamano.jd b/docs/html/distribute/stories/apps/segundamano.jd
new file mode 100644
index 0000000..4cbf817
--- /dev/null
+++ b/docs/html/distribute/stories/apps/segundamano.jd
@@ -0,0 +1,63 @@
+page.title=Segundamano Develops Android-First as Its Fastest Channel for Growth
+page.metaDescription=Segundamano developed Android app to increase potential for growth.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/segundamano.png
+page.timestamp=1468270110
+
+@jd:body
+
+<div class="figure" style="width:113px">
+ <img src="{@docRoot}images/distribute/stories/segundamano-icon.png" height=
+ "113">
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=mx.segundamano.android">Segundamano</a>
+ is a leading shopping application in Mexico for second-hand products. They
+ started by placing classified ads in newspapers, progressed to desktop, and
+ over the past year have seen significant growth in mobile, which now accounts
+ for 70% of their business. They have also seen <strong>270% year-over-year
+ growth on the Android platform alone</strong>.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ Segundamano shifted focus to mobile with their Android app because of the
+ high potential for growth. From July 2015 to January 2016, they saw an
+ increase of 55% in the number of classified ads on Android, higher than any
+ other platform. To leverage this momentum, Segundamano implemented two new
+ features on Android: premium offers and push notifications. Segundamano also
+ decided to implement material design in order to improve the in-app
+ experience and streamline the sales process for users.
+</p>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ Following Segundamano’s enhancements to the user experience, they've seen an
+ increase in their star rating, a 4.7% lift in monthly active users, and a 7%
+ increase in sales of premium listings. Additionally, year-to-date, their
+ <strong>installs are over seven times higher on Android than on other
+ platforms</strong>.
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Learn more about simplifying your in-app experience with <a href=
+ "{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
+ and the <a href="{@docRoot}design/material/index.html">material design
+ guidelines</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/tapps.jd b/docs/html/distribute/stories/apps/tapps.jd
new file mode 100644
index 0000000..1292139
--- /dev/null
+++ b/docs/html/distribute/stories/apps/tapps.jd
@@ -0,0 +1,366 @@
+page.title=Tapps Games Increases Installs by More Than 20% with Store Listing Experiments
+page.metaDescription=Tapps Games increased their use of store listing experiments in the Developer Console, with impressive results.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/tapps.png
+page.timestamp=1468270108
+
+@jd:body
+
+<style type="text/css">
+ span.positive{
+ color:green;
+ font-size: 125%;
+ font-weight:bold;">
+ }
+ span.negative{
+ color:red;
+ font-size: 125%;
+ font-weight:bold;">
+ }
+</style>
+
+<div class="figure" style="width:215px">
+ <img src="{@docRoot}images/distribute/stories/tapps-logo.png" height="65">
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/dev?id=6615809648420562690">Tapps</a> is
+ a mobile game publisher in São Paulo, Brazil. With a mission of <em>creating
+ fun for everyone</em>, Tapps has a portfolio of over 200 titles on the Google
+ Play Store, with roughly 70% of their installs coming from Android. Store
+ listing experiments have provided invaluable metrics to help their growing
+ team understand what makes the most effective product listings.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ Tapps has increased their use of store listing experiments in the Developer
+ Console. They recently expanded their marketing team to allocate greater time
+ and designated resources to the Developer Console tools. <strong>"We can’t
+ stress enough how much value the store listing experiments have brought us
+ over the past months. Right now, our marketing team has a substantial time
+ allocated to these tests every week,"</strong> said Felipe Watanabe, head of
+ marketing at Tapps. With icons and screenshots, Tapps tested variations in
+ color, character positioning, and the overall amount of graphic detail. In
+ the description tests, they found that shorter messages with clear calls to
+ action and appropriate language localizations were most successful.
+</p>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ By frequently conducting store listing experiments, Tapps gained valuable
+ insights that they have applied across their greater portfolio of games.
+ Results showed that shortening messaging, using contrasting colors,
+ reordering screenshots, and simplifying graphics often led to variant results
+ representing an average increase in performance between 5% and 50%. After
+ making changes based on the test results, Tapps saw <strong>install rates
+ increase beyond 20-30%</strong>.
+</p>
+
+<h4>
+ Screen tests
+</h4>
+
+<p>
+ The following table compares the install rates for three apps based on
+ changes to each app's screenshot.
+</p>
+
+<p class="table-caption">
+ <strong>Table 1</strong>. Screen test results
+</p>
+
+<table>
+ <tr>
+ <th>
+ Original
+ </th>
+ <th>
+ Variant
+ </th>
+ <th>
+ Variant results
+ </th>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-screen-orig-3.png"
+ width="240">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-screen-var-3.png"
+ width="240">
+ </td>
+ <td>
+ <span class="positive">+25%</span>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-screen-orig-1.png"
+ width="240">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-screen-var-1.png"
+ width="240">
+ </td>
+ <td>
+ <span class="positive">+17.1%</span>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-screen-orig-2.png"
+ width="240">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-screen-var-2.png"
+ width="240">
+ </td>
+ <td>
+ <span class="positive">+7.4%</span>
+ </td>
+ </tr>
+
+</table>
+
+<h4>
+ Icon tests
+</h4>
+
+<p>
+ The following tables compare install rates for three apps based on changes
+ to each app's icon.
+</p>
+
+<p class="table-caption">
+ <strong>Table 2</strong>. Icon 1 test results
+</p>
+
+<table>
+ <tr>
+ <th>
+ Original
+ </th>
+ <th>
+ Variant 1
+ </th>
+ <th>
+ Variant 2
+ </th>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-orig-1.png">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-var-1.png">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-var-1-2.png">
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ ---
+ </td>
+ <td>
+ <span class="negative">-29.6%</span>
+ </td>
+ <td>
+ <span class="positive">+20.8%</span>
+ </td>
+ </tr>
+</table>
+
+<p class="table-caption">
+ <strong>Table 3</strong>. Icon 2 test results
+</p>
+
+<table>
+ <tr>
+ <th>
+ Original
+ </th>
+ <th>
+ Variant 1
+ </th>
+ <th>
+ Variant 2
+ </th>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-orig-2.png">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-var-2.png">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-var-2-2.png">
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ ---
+ </td>
+ <td>
+ <span class="positive">+5.1%</span>
+ </td>
+ <td>
+ <span class="positive">+19.7%</span>
+ </td>
+ </tr>
+</table>
+
+<p class="table-caption">
+ <strong>Table 4</strong>. Icon 3 test results
+</p>
+
+<table>
+ <tr>
+ <th>
+ Original
+ </th>
+ <th>
+ Variant 1
+ </th>
+ <th>
+ Variant 2
+ </th>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-orig-3.png">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-var-3.png">
+ </td>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-icon-var-3-2.png">
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ ---
+ </td>
+ <td>
+ <span class="negative">-17.7%</span>
+ </td>
+ <td>
+ <span class="positive">+50.7%</span>
+ </td>
+ </tr>
+</table>
+
+<h4>
+ Description tests
+</h4>
+
+<p>
+ The following table compares install rates for three apps based on changes to
+ each app's description text.
+</p>
+
+<p class="table-caption">
+ <strong>Table 5</strong>. Description test results
+</p>
+
+<table>
+ <tr>
+ <th>
+ Game
+ </th>
+ <th>
+ Original
+ </th>
+ <th>
+ Variant
+ </th>
+ <th>
+ Variant results
+ </th>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-logic-pic.png">
+ <strong>Logic Pic</strong>
+ </td>
+ <td>
+ <em>"Use logic to solve fun puzzles and discover hidden pictures! Logic
+ Pic is free!"</em>
+ </td>
+ <td>
+ <strong><em>"Discover all the hidden pictures in this challenging classic
+ japanese puzzle!"</em></strong>
+ </td>
+ <td>
+ <span class="positive">+10.7%</span>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-candy-hills.png"
+ width="96"> <strong>Candy Hills</strong>
+ </td>
+ <td>
+ <em>"What will your candy park look like? Build it now in Candy
+ Hills!"</em>
+ </td>
+ <td>
+ <strong><em>"Build your own sweet candy park in Candy
+ Hills!"</em></strong>
+ </td>
+ <td>
+ <span class="positive">+8.2%</span>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <img src="{@docRoot}images/distribute/stories/tapps-villains-corp.png"
+ width="96"> <strong>Villains Corp.</strong>
+ </td>
+ <td>
+ <em>"Be a real villain and CONQUER THE WORLD!"</em>
+ </td>
+ <td>
+ <strong><em>"Mwahahaha! Be a real villain and CONQUER THE
+ WORLD!"</em></strong>
+ </td>
+ <td>
+ <span class="positive">+6.8%</span>
+ </td>
+ </tr>
+</table>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Find out more about <a href=
+ "{@docRoot}distribute/users/experiments.html">store listing experiments</a>.
+</p>
diff --git a/docs/html/distribute/stories/apps/upbeat-games.jd b/docs/html/distribute/stories/apps/upbeat-games.jd
new file mode 100644
index 0000000..02222d3
--- /dev/null
+++ b/docs/html/distribute/stories/apps/upbeat-games.jd
@@ -0,0 +1,69 @@
+page.title=Witch Puzzle Achieves 98% of International Installs on Android
+page.metaDescription=Witch Puzzle localized their app into 12 languages.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/witch-puzzle.png
+page.timestamp=1468270106
+
+@jd:body
+
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/witch-puzzle-icon.png"
+ width="113">
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ Located in São Paulo, Brazil, <a class="external-link" href=
+ "https://play.google.com/store/apps/dev?id=8995071809141037139">Upbeat
+ Games</a> is an indie game developer with a mission to build fun and easy
+ games that anyone can play. As a small team, the Upbeat crew reacted quickly
+ to their game’s growing installs in Asian countries, and is now seeing strong
+ international growth with their game <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=com.upbeatgames.witchpuzzle">Witch
+ Puzzle</a>.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ After noticing that Witch Puzzle was gaining traction throughout Asia, Upbeat
+ localized their game into 12 languages, prioritizing countries with an
+ existing user base and high gross national income (GNI). This led to a direct
+ increase in installs.
+</p>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/japanese-witch-puzzle.png"
+ width="214">
+ <p class="img-caption">
+ Japanese version of Witch Puzzle
+ </p>
+</div>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ “In the last three months, 98% of our international installs for Witch Puzzle
+ came from Android,” said Vinicius Sormani Heimbeck, Upbeat’s founder. Upbeat
+ applied these learnings across their portfolio of games. Now, <strong>75% of
+ their portfolio’s revenue is driven by Android</strong>.
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Use the <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">Localization
+ Checklist</a> to learn more about tailoring your app for different markets to
+ drive installs and revenue, and to create a better overall user experience.
+</p>
diff --git a/docs/html/images/cards/distribute/stories/aftenposten.png b/docs/html/images/cards/distribute/stories/aftenposten.png
new file mode 100644
index 0000000..60cb851
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/aftenposten.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/el-mundo.png b/docs/html/images/cards/distribute/stories/el-mundo.png
new file mode 100644
index 0000000..23db783
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/el-mundo.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/segundamano.png b/docs/html/images/cards/distribute/stories/segundamano.png
new file mode 100644
index 0000000..60e873c
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/segundamano.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/tapps.png b/docs/html/images/cards/distribute/stories/tapps.png
new file mode 100644
index 0000000..e01e3ad
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/tapps.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/witch-puzzle.png b/docs/html/images/cards/distribute/stories/witch-puzzle.png
new file mode 100644
index 0000000..c336f1b
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/witch-puzzle.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/aftenposten-icon.png b/docs/html/images/distribute/stories/aftenposten-icon.png
new file mode 100644
index 0000000..60cb851
--- /dev/null
+++ b/docs/html/images/distribute/stories/aftenposten-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/el-mundo-icon.png b/docs/html/images/distribute/stories/el-mundo-icon.png
new file mode 100644
index 0000000..23db783
--- /dev/null
+++ b/docs/html/images/distribute/stories/el-mundo-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/japanese-witch-puzzle.png b/docs/html/images/distribute/stories/japanese-witch-puzzle.png
new file mode 100644
index 0000000..6a7ef13
--- /dev/null
+++ b/docs/html/images/distribute/stories/japanese-witch-puzzle.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/segundamano-icon.png b/docs/html/images/distribute/stories/segundamano-icon.png
new file mode 100644
index 0000000..60e873c
--- /dev/null
+++ b/docs/html/images/distribute/stories/segundamano-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-candy-hills.png b/docs/html/images/distribute/stories/tapps-candy-hills.png
new file mode 100644
index 0000000..14dcb94
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-candy-hills.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-orig-1.png b/docs/html/images/distribute/stories/tapps-icon-orig-1.png
new file mode 100644
index 0000000..44af423
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-orig-1.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-orig-2.png b/docs/html/images/distribute/stories/tapps-icon-orig-2.png
new file mode 100644
index 0000000..1b36255
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-orig-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-orig-3.png b/docs/html/images/distribute/stories/tapps-icon-orig-3.png
new file mode 100644
index 0000000..2f393f8
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-orig-3.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-var-1-2.png b/docs/html/images/distribute/stories/tapps-icon-var-1-2.png
new file mode 100644
index 0000000..fecab6e
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-var-1-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-var-1.png b/docs/html/images/distribute/stories/tapps-icon-var-1.png
new file mode 100644
index 0000000..77bd02a
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-var-1.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-var-2-2.png b/docs/html/images/distribute/stories/tapps-icon-var-2-2.png
new file mode 100644
index 0000000..84166c4
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-var-2-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-var-2.png b/docs/html/images/distribute/stories/tapps-icon-var-2.png
new file mode 100644
index 0000000..939c2fd
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-var-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-var-3-2.png b/docs/html/images/distribute/stories/tapps-icon-var-3-2.png
new file mode 100644
index 0000000..4aa782d
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-var-3-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-icon-var-3.png b/docs/html/images/distribute/stories/tapps-icon-var-3.png
new file mode 100644
index 0000000..1e44fdf
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-icon-var-3.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-logic-pic.png b/docs/html/images/distribute/stories/tapps-logic-pic.png
new file mode 100644
index 0000000..5029f79
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-logic-pic.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-logo.png b/docs/html/images/distribute/stories/tapps-logo.png
new file mode 100644
index 0000000..e01e3ad
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-logo.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-screen-orig-1.png b/docs/html/images/distribute/stories/tapps-screen-orig-1.png
new file mode 100644
index 0000000..d54e75c
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-screen-orig-1.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-screen-orig-2.png b/docs/html/images/distribute/stories/tapps-screen-orig-2.png
new file mode 100644
index 0000000..a2d18e3
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-screen-orig-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-screen-orig-3.png b/docs/html/images/distribute/stories/tapps-screen-orig-3.png
new file mode 100644
index 0000000..e01fe20
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-screen-orig-3.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-screen-var-1.png b/docs/html/images/distribute/stories/tapps-screen-var-1.png
new file mode 100644
index 0000000..b930350
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-screen-var-1.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-screen-var-2.png b/docs/html/images/distribute/stories/tapps-screen-var-2.png
new file mode 100644
index 0000000..9ccb8a6
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-screen-var-2.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-screen-var-3.png b/docs/html/images/distribute/stories/tapps-screen-var-3.png
new file mode 100644
index 0000000..8eb58e1
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-screen-var-3.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/tapps-villains-corp.png b/docs/html/images/distribute/stories/tapps-villains-corp.png
new file mode 100644
index 0000000..6e037da
--- /dev/null
+++ b/docs/html/images/distribute/stories/tapps-villains-corp.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/witch-puzzle-icon.png b/docs/html/images/distribute/stories/witch-puzzle-icon.png
new file mode 100644
index 0000000..c336f1b
--- /dev/null
+++ b/docs/html/images/distribute/stories/witch-puzzle-icon.png
Binary files differ
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 3373fc4..c7ffb7a 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -27,6 +27,7 @@
<li><a href="#multi-locale_languages">Locales and Languages</a></li>
<li><a href="#emoji">New Emojis</a></li>
<li><a href="#icu4">ICU4J APIs in Android</a></li>
+ <li><a href="#webview">WebView</a></li>
<li><a href="#gles_32">OpenGL ES 3.2 API</a></li>
<li><a href="#android_tv_recording">Android TV Recording</a></li>
<li><a href="#android_for_work">Android for Work</a></li>
@@ -573,7 +574,85 @@
"{@docRoot}preview/features/icu4j-framework.html">ICU4J Support</a>.
</p>
+<h2 id="webview">WebView</h2>
+<h3>Chrome + WebView, Together</h3>
+
+<p>
+ Starting with Chrome version 51 on Android N and above, the Chrome APK on your device
+ is used to provide and render Android System WebViews. This approach improves memory
+ usage on the device itself and also reduces the bandwidth required to keep
+ WebView up to date (as the standalone WebView APK will no longer be updated
+ as long as Chrome remains enabled).
+</p>
+
+<p>
+ You can choose your WebView provider by enabling Developer Options and
+ selecting <strong>WebView implementation</strong>. You can use any compatible
+ Chrome version (Dev, Beta or Stable) that is installed on your device or the
+ standalone Webview APK to act as the WebView implementation.
+</p>
+
+<h3>Multiprocess</h3>
+
+<p>
+ Starting with Chrome version 51 in Android N, WebView will run web content in a
+ separate sandboxed process when the developer option "Multiprocess WebView"
+ is enabled.
+</p>
+
+<p>
+ We're looking for feedback on compatibility and runtime performance in N
+ before enabling multiprocess WebView in a future version of Android. In this
+ version, regressions in startup time, total memory usage and software
+ rendering performance are expected.
+</p>
+
+<p>
+ If you find unexpected issues in multiprocess mode we’d like to hear about
+ them. Please get in touch with the WebView team on the <a href=
+ "https://bugs.chromium.org/p/chromium/issues/entry?template=Webview%20Bugs"
+ >Chromium bug tracker</a>.
+</p>
+
+<h3>Javascript run before page load</h3>
+<p>
+ Starting with apps targeting Android N, the Javascript context will be reset
+ when a new page is loaded. Currently, the context is carried over for the
+ first page loaded in a new WebView instance.
+</p>
+
+<p>
+ Developers looking to inject Javascript into the WebView should execute the
+ script after the page has started to load.
+</p>
+
+<h3>Geolocation on insecure origins</h3>
+
+<p>
+ Starting with apps targeting Android N, the geolocation API will only be
+ allowed on secure origins (over HTTPS.) This policy is designed to protect
+ users’ private information when they’re using an insecure connection.
+</p>
+
+<h3>Testing with WebView Beta</h3>
+
+<p>
+ WebView is updated regularly, so we recommend that you test compatibility
+ with your app frequently using WebView’s beta channel. To get started testing
+ pre-release versions of WebView on Android N, download and install either
+ Chrome Dev or Chrome Beta, and select it as the WebView implementation under
+ developer options as described above. Please report issues via the <a href=
+ "https://bugs.chromium.org/p/chromium/issues/entry?template=Webview%20Bugs">Chromium
+ bug tracker</a> so that we can fix them before a new version of WebView is
+ released.
+</p>
+
+<p>
+ If you have any other questions or issues, feel free to reach out to the
+ WebView team via our <a href=
+ "https://plus.google.com/communities/105434725573080290360">G+ community</a>.
+</p>
<h2 id="gles_32">OpenGL™ ES 3.2 API</h2>
@@ -667,8 +746,9 @@
<p>
Users can also manually set Always on VPN clients that implement
- <code>VPNService</code> methods in the primary user using
- <strong>Settings>More>Vpn</strong>.
+ <code>VPNService</code> methods using
+ <strong>Settings>More>Vpn</strong>. The option to enable Always on VPN
+ from Settings is available only if VPN client targets API level 24.
</p>
<h3 id="custom_provisioning">Customized provisioning</h3>
@@ -755,6 +835,20 @@
on the device.
</p>
+<p class="note">
+ <strong>Note: </strong>Only a small number of devices running Android N
+ support hardware-level key attestation; all other devices running Android N
+ use software-level key attestation instead. Before you verify the properties
+ of a device's hardware-backed keys in a production-level environment, you
+ should make sure that the device supports hardware-level key attestation. To
+ do so, you should check that the attestation certificate chain contains a root
+ certificate that is signed by the Google attestation root key and that the
+ <code>attestationSecurityLevel</code> element within the <a
+ href="{@docRoot}preview/features/key-attestation.html#certificate_schema_keydescription">key
+ description</a> data structure is set to the TrustedEnvironment security
+ level.
+</p>
+
<p>
For more information, see the
<a href="{@docRoot}preview/features/key-attestation.html">Key Attestation</a>
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index 3a37295..48dc053 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -748,6 +748,23 @@
to the trusted credentials storage via Settings UI separately, with a
DER-encoded format under a .crt or .cer file extension.
</li>
+
+ <li>Starting in Android N, fingerprint enrollment and storage are managed per user.
+ If a profile owner’s Device Policy Client (DPC) targets pre-N on an N device,
+ the user is still able to set fingerprint on the device, but work
+ applications cannot access device fingerprint. When the DPC targets N and
+ above, the user can set fingerprint specifically for work profile by going to
+ <strong>Settings > Security > Work profile security</strong>.
+ </li>
+
+ <li>A new encryption status <code>ENCRYPTION_STATUS_ACTIVE_PER_USER</code> is
+ returned by <code>DevicePolicyManager.getStorageEncryptionStatus()</code>, to
+ indicate that encryption is active and the encryption key is tied to the
+ user. The new status is only returned if DPC targets API Level 24 and above.
+ For apps targeting earlier API levels, <code>ENCRYPTION_STATUS_ACTIVE</code>
+ is returned, even if the encryption key is specific to the user or profile.
+ </li>
+
</ul>
<p>
diff --git a/docs/html/preview/download-ota.jd b/docs/html/preview/download-ota.jd
index 18f3e8d..65f7f9f 100644
--- a/docs/html/preview/download-ota.jd
+++ b/docs/html/preview/download-ota.jd
@@ -203,72 +203,72 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
<td><a href="#top" onclick="onDownload(this)"
- >bullhead-ota-npd56n-dd5c12ee.zip</a><br>
- MD5: af9a82e9a78925ca9c1c7f5f6fb851ec<br>
- SHA-1: e4aabd5634b7ebdeffa877cd9e49244c0be326e4
+ >bullhead-ota-npd90g-0a874807.zip</a><br>
+ MD5: 4b83b803fac1a6eec13f66d0afc6f46e<br>
+ SHA-1: a9920bcc8d475ce322cada097d085448512635e2
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >shamu-ota-npd56n-2818fd62.zip</a><br>
- MD5: d8df396b187a8667889260e5464bd676<br>
- SHA-1: c03c8ef8be587a574565855d4faa526254794e03
+ >shamu-ota-npd90g-06f5d23d.zip</a><br>
+ MD5: 513570bb3a91878c2d1a5807d2340420<br>
+ SHA-1: 2d2f40636c95c132907e6ba0d10b395301e969ed
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
<td><a href="#top" onclick="onDownload(this)"
- >angler-ota-npd56n-d2f2611c.zip</a><br>
- MD5: c3c206892d414d4fc7da892ff840eada<br>
- SHA-1: 2bdc79409ace5e163ef014ae51977d0a71b83df5
+ >angler-ota-npd90g-5baa69c2.zip</a><br>
+ MD5: 096fe26c5d50606a424d2f3326c0477b<br>
+ SHA-1: 468d2e7aea444505513ddc183c85690c00fab0c1
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
<td><a href="#top" onclick="onDownload(this)"
- >volantis-ota-npd56n-42228a60.zip</a><br>
- MD5: c80cf483d8b3c014fc7b27f80957a158<br>
- SHA-1: f437829320f47ea3aa5f8b70ce2f0bb3d30b3f4f
+ >volantis-ota-npd90g-c04785e1.zip</a><br>
+ MD5: 6aecd3b0b3a839c5ce1ce4d12187b03e<br>
+ SHA-1: 31633180635b831e59271a7d904439f278586f49
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
<td><a href="#top" onclick="onDownload(this)"
- >volantisg-ota-npd56n-9b4dbaac.zip</a><br>
- MD5: 9e55ac1650e4f07a662bafa7f082e91c<br>
- SHA-1: b9982be56c2817d122664869a1fbe9b13e9c72f7
+ >volantisg-ota-npd90g-c56aa1b0.zip</a><br>
+ MD5: 0493fa79763d67bcdde8007299e1888d<br>
+ SHA-1: f709daf81968a1b27ed41fe40d42e0d106f3c494
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >fugu-ota-npd56n-b305968a.zip</a><br>
- MD5: dfc980acad6772d8473ccaa9cbbb681a<br>
- SHA-1: d7bf8192649dea970afda165d181b4eea07abd7d
+ >fugu-ota-npd90g-3a0643ae.zip</a><br>
+ MD5: 9c38b6647fe5a4f2965196b7c409f0f7<br>
+ SHA-1: 77c6fb05191f0c2ae0956bae18f1c80b2f922f05
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >ryu-ota-npd56n-5bf2fd66.zip</a><br>
- MD5: 1699e4bacfbef16a75ae6cf3f2e3d886<br>
- SHA-1: e20f3a8e43fcdd6acef21da80894afc8f9474e33
+ >ryu-ota-npd90g-ec931914.zip</a><br>
+ MD5: 4c6135498ca156a9cdaf443ddfdcb2ba<br>
+ SHA-1: 297cc9a204685ef5507ec087fc7edf5b34551ce6
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
<td><a href="#top" onclick="onDownload(this)"
- >seed_l8150-ota-npd56n-a322696c.zip</a><br>
- MD5: afc0e363ad2fd7418423e189a339a8e9<br>
- SHA-1: fc4d818878df51894eac29932dd0e9f6511329c6
+ >seed_l8150-ota-npd90g-dcb0662d.zip</a><br>
+ MD5: f40ea6314a13ea6dd30d0e68098532a2<br>
+ SHA-1: 11af10b621f4480ac63f4e99189d61e1686c0865
</td>
</tr>
diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd
index ad82211..a60cbfaa 100644
--- a/docs/html/preview/download.jd
+++ b/docs/html/preview/download.jd
@@ -219,14 +219,26 @@
</p>
<ul>
- <li><strong>Enroll the device in automatic OTA system updates</strong> through the
- <a href="https://g.co/androidbeta">Android Beta Program</a>. Once enrolled, your device will receive regular
- over-the-air (OTA) updates of all milestone builds in the N Developer Preview. This
- approach is recommended because it lets you seamlessly transition from your current
- environment through the various releases of the N Developer Preview.</li>
- <li><strong>Download a Developer Preview system image and flash the device</strong>.
- OTA updates are not provided automatically for devices that you flash manually, but
- you can enroll those devices in Android Beta Program to get OTA updates. </li>
+ <li>
+ <strong>Enroll the device in automatic OTA system updates</strong> through
+ the <a href="https://g.co/androidbeta">Android Beta Program</a>. Once
+ enrolled, your device will receive regular over-the-air (OTA) updates of
+ all milestone builds in the N Developer Preview. When the next version of
+ Android is released, your device will automatically update to the final
+ version. This approach is recommended because it lets you seamlessly
+ transition from your current environment, through the various releases of
+ the N Developer Preview, to the release version.
+ </li>
+
+ <li>
+ <strong>Download a Developer Preview system image and flash the
+ device</strong>. OTA updates are not provided automatically for devices
+ that you flash manually, but you can enroll those devices in Android Beta
+ Program to get OTA updates. When the next version of Android is released,
+ you can download the final device image from the <a href=
+ "https://developers.google.com/android/nexus/images" type=
+ "external-link">factory images</a> page.
+ </li>
</ul>
<h3 id="ota">Enroll the device in automatic OTA updates</h3>
@@ -234,9 +246,11 @@
<p>
If you have access to a supported device (see the list in the Downloads
table), you can receive over-the-air updates to preview versions of Android
- by enrolling that device in the <a href="https://g.co/androidbeta">Android Beta Program</a>. These updates are
- automatically downloaded and will update your device just like official
- system updates.
+ by enrolling that device in the <a href="https://g.co/androidbeta">Android
+ Beta Program</a>. These updates are automatically downloaded and will update
+ your device just like official system updates. When the next version of
+ Android is released, the device will automatically update to the production
+ version.
</p>
<p>
@@ -282,7 +296,8 @@
<p>
Manually flashed system images <strong>do not
automatically receive OTA updates</strong> to later Developer Preview
- milestone builds. Make sure to keep your environment up-to-date and flash a
+ milestone builds or the final, production version. Make sure to keep your
+ environment up-to-date and flash a
new system image at each Developer Preview milestone.
</p>
@@ -302,72 +317,72 @@
<tr id="bullhead">
<td>Nexus 5X <br>"bullhead"</td>
<td><a href="#top" onclick="onDownload(this)"
- >bullhead-npd56n-factory-996cac57.tgz</a><br>
- MD5: 5aadba91f60de00d58dc6198ef5cc3ba<br>
- SHA-1: 996cac575d83bde573315290da8f52cecc4127d2
+ >bullhead-npd90g-factory-7a0ca1bc.tgz</a><br>
+ MD5: e7a9a3061335c1e0c8be2588f13290af<br>
+ SHA-1: 7a0ca1bcfa51bbefde34243603bc79c7dec214a1
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >shamu-npd56n-factory-7936bf75.tgz</a><br>
- MD5: b7ed0db569f3bc2d6655fe8d8cea0e13<br>
- SHA-1: 7936bf75e6bfb771bd14485211a319b246311b96
+ >shamu-npd90g-factory-f7a4e3a9.tgz</a><br>
+ MD5: 2fb572ddcfca67bb1d741be97492a9ed<br>
+ SHA-1: f7a4e3a96c797827492998e855c8f9efbfc8559a
</td>
</tr>
<tr id="angler">
<td>Nexus 6P <br>"angler"</td>
<td><a href="#top" onclick="onDownload(this)"
- >angler-npd56n-factory-1ce5ccad.tgz</a><br>
- MD5: f296eccaed4e2526d6435df8cf0e8df1<br>
- SHA-1: 1ce5ccad8a3eae143e0ecd9c7afbb1be2f1d41cc
+ >angler-npd90g-factory-cd9ac81e.tgz</a><br>
+ MD5: 2370c30f3ef1d0684c1de5216a5d90fe<br>
+ SHA-1: cd9ac81ec7f4a646ac6054eecbf2ea4c4b89b054
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
<td><a href="#top" onclick="onDownload(this)"
- >volantis-npd56n-factory-8b9f997e.tgz</a><br>
- MD5: 111c2fe5777dd6aae71fb8ef35dda9d3<br>
- SHA-1: 8b9f997ea39fdaf505527536bd346948ae1bae30
+ >volantis-npd90g-factory-41b55406.tgz</a><br>
+ MD5: cefa78950141da2a7c75e887717e3c8f<br>
+ SHA-1: 41b554060263a7ef16e4be8422cbd6caca26e00f
</td>
</tr>
<tr id="volantisg">
<td>Nexus 9G <br>"volantisg"</td>
<td><a href="#top" onclick="onDownload(this)"
- >volantisg-npd56n-factory-ef05106a.tgz</a><br>
- MD5: 3a6f4d47b385966347bd26b7a922cd6e<br>
- SHA-1: ef05106a9e3becea5673ea67d6c0cc21a2ec09d4
+ >volantisg-npd90g-factory-610492be.tgz</a><br>
+ MD5: 2f36dc0d0fab02ab78be500677ec239f<br>
+ SHA-1: 610492bedfc4127023040ecb2c89239a78a900ad
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >fugu-npd56n-factory-a51674a1.tgz</a><br>
- MD5: b75dc745a64848ea24124db8fa9252ed<br>
- SHA-1: a51674a1303b17fec0405d513f9c0fe9f225780f
+ >fugu-npd90g-factory-0fe95694.tgz</a><br>
+ MD5: f4cb48f919e4c29c631de21416c612e2<br>
+ SHA-1: 0fe95694e7bc41e4c3ac0e4438cd77102a0aa8b4
</td>
</tr>
<tr id="ryu">
<td>Pixel C <br>"ryu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >ryu-npd56n-factory-e36c49b1.tgz</a><br>
- MD5: 0a2d660b09e19614a5b3573487b88066<br>
- SHA-1: e36c49b184843cdfe10278aebc04ce50b6d670b6
+ >ryu-npd90g-factory-f4da981c.tgz</a><br>
+ MD5: d9f0e40b6c20d274831e8a7d285fd887<br>
+ SHA-1: f4da981c70576133321e2858e52fe2c990e68a75
</td>
</tr>
<tr id="seed">
<td>General Mobile 4G (Android One) <br>"seed"</td>
<td><a href="#top" onclick="onDownload(this)"
- >seed_l8150-npd56n-factory-dd5d4fd2.tgz</a><br>
- MD5: 3420581b969af777753141dacc7f73b9<br>
- SHA-1: dd5d4fd203f9c5dad658434c0ff370c411b78835
+ >seed_l8150-npd90g-factory-48f59c99.tgz</a><br>
+ MD5: 0ed565c509594072822d71c65b48ec8e<br>
+ SHA-1: 48f59c99ac43d1cd2f5656a283bb9868581663a8
</td>
</tr>
diff --git a/docs/html/preview/features/direct-boot.jd b/docs/html/preview/features/direct-boot.jd
index 8351f4b..60f6141 100644
--- a/docs/html/preview/features/direct-boot.jd
+++ b/docs/html/preview/features/direct-boot.jd
@@ -14,6 +14,7 @@
<li><a href="#notification">Getting Notified of User Unlock</a></li>
<li><a href="#migrating">Migrating Existing Data</a></li>
<li><a href="#testing">Testing Your Encryption Aware App</a></li>
+ <li><a href="#dpm">Checking Device Policy Encryption Status</a></li>
</ol>
</div>
</div>
@@ -186,3 +187,34 @@
</pre>
<p>Using these commands causes the device to reboot.</p>
+
+<h2 id="dpm">Checking Device Policy Encryption Status</h2>
+
+<p>Device administration apps can use
+{@link android.app.admin.DevicePolicyManager#getStorageEncryptionStatus
+DevicePolicyManager.getStorageEncryptionStatus()} to check the current
+encryption status of the device. If your app is targeting an API level
+lower than Android N,
+{@link android.app.admin.DevicePolicyManager#getStorageEncryptionStatus
+getStorageEncryptionStatus()} will return
+{@link android.app.admin.DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE
+ENCRYPTION_STATUS_ACTIVE} if the device is either using full-disk encryption,
+or file-based encryption with Direct Boot. In both of these cases, data is
+always stored encrypted at rest. If your app is targeting an API level of
+Android N or higher,
+{@link android.app.admin.DevicePolicyManager#getStorageEncryptionStatus
+getStorageEncryptionStatus()} will return
+{@link android.app.admin.DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE
+ENCRYPTION_STATUS_ACTIVE} if the device is using full-disk encryption. It will
+return
+{@link android.app.admin.DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE_PER_USER
+ENCRYPTION_STATUS_ACTIVE_PER_USER} if the device is using file-based encryption
+with Direct Boot.</p>
+
+<p>If you build a device administration app
+that targets Android N, make sure to check for both
+{@link android.app.admin.DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE
+ENCRYPTION_STATUS_ACTIVE} and
+{@link android.app.admin.DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE_PER_USER
+ENCRYPTION_STATUS_ACTIVE_PER_USER} to determine if the device is
+encrypted.</p>
diff --git a/docs/html/preview/features/key-attestation.jd b/docs/html/preview/features/key-attestation.jd
index 98b8340..5be6dfa 100644
--- a/docs/html/preview/features/key-attestation.jd
+++ b/docs/html/preview/features/key-attestation.jd
@@ -21,6 +21,19 @@
interpret the schema of the attestation certificate's extension data.
</p>
+<p class="note">
+ <strong>Note: </strong>Only a small number of devices running Android N
+ support hardware-level key attestation; all other devices running Android N
+ use software-level key attestation instead. Before you verify the properties
+ of a device's hardware-backed keys in a production-level environment, you
+ should make sure that the device supports hardware-level key attestation. To
+ do so, you should check that the attestation certificate chain contains a root
+ certificate that is signed by the Google attestation root key and that the
+ <code>attestationSecurityLevel</code> element within the <a
+ href="#certificate_schema_keydescription">key description</a> data structure
+ is set to the TrustedEnvironment security level.
+</p>
+
<h2 id="verifying">
Retrieving and Verifying a Hardware-backed Key Pair
</h2>
@@ -227,8 +240,8 @@
level</a> of the attestation.
</p>
- <p class="note">
- <strong>Note:</strong> Although it is possible to attest keys that are
+ <p class="caution">
+ <strong>Warning:</strong> Although it is possible to attest keys that are
stored in the Android system—that is, if the
<code>attestationSecurity</code> value is set to Software—you
cannot trust these attestations if the Android system becomes compromised.
diff --git a/docs/html/preview/overview.jd b/docs/html/preview/overview.jd
index faf48b8..601442e 100644
--- a/docs/html/preview/overview.jd
+++ b/docs/html/preview/overview.jd
@@ -157,7 +157,7 @@
<li><strong><a href="{@docRoot}preview/support.html#dp2">Preview 2</a></strong> (incremental update, alpha)</li>
<li><strong><a href="{@docRoot}preview/support.html#dp3">Preview 3</a></strong> (incremental update, beta)</li>
<li><strong><a href="{@docRoot}preview/support.html#dp4">Preview 4</a></strong> (final APIs and official SDK, Play publishing)</li>
- <li><strong>Preview 5</strong> (near-final system images for final testing)</li>
+ <li><strong><a href="{@docRoot}preview/support.html#dp5">Preview 5</a></strong> (near-final system images for final testing)</li>
<li><strong>Final release</strong> to AOSP and ecosystem</li>
</ul>
@@ -433,8 +433,10 @@
<li> Set up your environment by following the instructions for <a
href="{@docRoot}preview/setup-sdk.html">Setting up the Preview SDK</a>
and configuring test devices.</li>
- <li> Follow the <a href="https://developers.google.com/android/nexus/images">flashing
- instructions</a> to flash the latest Android N system image for your device. </li>
+ <li> Follow the <a href="{@docRoot}preview/download.html">
+ instructions</a> to update your device to the latest build of the N Developer
+ Preview. The easiest way is to enroll your device in
+ <a href="https://www.google.com/android/beta">Android Beta</a> program. </li>
<li> Review the <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>
and <a href="{@docRoot}preview/samples.html">Android N samples</a> to gain more
insight into new API features and how to use them in your app.
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 3e95f3e..ff11e8e 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -77,32 +77,10 @@
<h3 id="docs-dl">Get the N Preview reference documentation</h3>
<p>Beginning with the Preview 4 release, the API reference for the
-N platform (API level 24) is now available online at <a href=
- "{@docRoot}reference/">developer.android.com/reference/</a>.
-</p>
-
-<p>If you'd like an offline copy of the API reference, you can download it
-from the following table. The download also includes an incremental diff report
-for API changes between the Preview 3 and Preview 4 release, which is not
-available online.</p>
-
-<table>
- <tr>
- <th scope="col">Documentation</th>
- <th scope="col">Checksums</th>
- </tr>
- <tr>
- <td style="white-space: nowrap">
- <a href="{@docRoot}shareables/preview/n-preview-4-docs.zip"
- >n-preview-4-docs.zip</a></td>
- <td width="100%">
- MD5: f853e3ba0707083336dfa780b8fed9a7<br>
- SHA-1: 36fcbc497cc2e63b1bc1d629c304b0ba43a88946
- </td>
- </tr>
-</table>
-
-
+ N platform (API level 24) is now available online at <a href=
+ "{@docRoot}reference/">developer.android.com/reference/</a>. There is also
+ an incremental diff report for <a href="{@docRoot}sdk/api_diff/24/changes.html"
+ >API changes between API levels 23 and 24</a>.</p>
<h2 id="java8">Get the Java 8 JDK</h2>
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index ef8a652..ed40914 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -12,14 +12,16 @@
<h2>In this document</h2>
<ul>
- <li><a href="#dp4">Developer Preview 4</a>
+ <li><a href="#dp5">Developer Preview 5</a>
<ul>
<li><a href="#general">General advisories</a></li>
- <li><a href="#new">New in DP4</a></li>
+ <li><a href="#new">New in DP5</a></li>
<li><a href="#ki">Known issues</a></li>
- <li><a href="#upgrade-notes">Notes on publishing apps that target API 24</a></li>
+ <li><a href="#upgrade-notes">Notes on publishing apps
+ that target API 24</a></li>
</ul>
</li>
+ <li><a href="#dp4">Developer Preview 4</a></li>
<li><a href="#dp3">Developer Preview 3</a></li>
<li><a href="#dp2">Developer Preview 2</a></li>
<li><a href="#dp1">Developer Preview 1</a></li>
@@ -50,6 +52,196 @@
community</a>.
</p>
+<h2 id="dp5">Developer Preview 5</h2>
+
+<div class="cols">
+ <div class="col-6of12">
+ <p>
+ <em>Date: July 2016<br>
+ Build: NPD90G<br>
+ Emulator support: x86 & ARM (32/64-bit)<br>
+ Google Play services: 8.4</em>
+ </p>
+ </div>
+</div>
+
+<h3 id="general">General advisories</h3>
+
+<p>
+ This Developer Preview release is for <strong>app developers and other early
+ adopters</strong> and is available for daily use, development, or
+ compatibility testing. Please be aware of these general notes about the
+ release:
+</p>
+
+<ul>
+ <li>This release may have various <strong>stability issues</strong> on
+ supported devices.
+ </li>
+
+ <li>Some apps <strong>may not function as expected</strong> on the new
+ platform version. This includes Google’s apps as well as other apps.
+ </li>
+
+ <li>Developer Preview 5 is <strong>Compatibility Test Suite (CTS)
+ approved</strong> on these devices: Nexus 5X, Nexus 6, Nexus 6P, Nexus 9,
+ and Pixel C. Apps that depend on CTS approved builds should work normally
+ on these devices (Android Pay for example).
+ </li>
+
+ <li>Developer Preview 5 is <strong>available</strong> on Nexus 5X, Nexus 6, Nexus 6P,
+ Nexus 9, Nexus Player, Pixel C, and General Mobile 4G (Android One).
+ </li>
+</ul>
+
+
+<h3 id="new">New in DP5</h3>
+
+<h4>Updated system images for supported devices and emulator</h4>
+
+<p>
+ Developer Preview 5 includes <a href=
+ "{@docRoot}preview/download.html"><strong>near-final system
+ images</strong></a> for supported devices and the Android emulator. The
+ images include the final APIs (API level 24) for the upcoming Android N
+ platform. When you are done testing, you can publish apps using API
+ level 24 to Google Play, in alpha, beta, and production release channels.
+</p>
+
+
+<!--
+
+<h4 id="api-changes">Feature and API changes</h4>
+
+<ul>
+ <li>TODO</li>
+</ul>
+
+-->
+
+<h3 id="ki">Known Issues</h3>
+
+<h4>Stability</h4>
+
+<ul>
+ <li>Users may encounter system instability (such as kernel panics and
+ crashes).
+ </li>
+</ul>
+
+<h4>Multi-window</h4>
+<ul>
+ <li>MapView may be blank when resized in multi-window mode and not focused.
+ </li>
+</ul>
+
+<h4>Camera</h4>
+<ul>
+ <li>Apps may encounter Intermittent issues recording and playing back
+ video at 240fps.
+ </li>
+</ul>
+
+<h4>Do Not Disturb</h4>
+<ul>
+ <li>Do Not Disturb mode may be set at device reboot. To work around
+ the issue, delete the existing rule for VR as follows: go to
+ <strong>Settings > Sound > Do not disturb > Automatic Rules</strong>
+ and tap the trash icon next to the VR rule.
+ </li>
+</ul>
+
+<h4>Screen zoom and multiple APKs in Google Play</h4>
+<ul>
+ <li>On devices running Developer Preview 5, Google Play services 9.0.83
+ incorrectly reports the current screen density rather than the stable screen
+ density. When screen zoom is enabled on these devices, this can cause Google
+ Play to select a version of a multi-APK app that’s designed for smaller
+ screens. This issue is fixed in the next version of Google Play services.
+ </li>
+</ul>
+
+<h4>Vulkan support and multiple APKs in Google Play</h4>
+<ul>
+ <li>On devices running Developer Preview 5, Google Play services 9.0.83
+ currently reports Vulkan support but not Vulkan version. This can cause
+ Google Play to select a version of a multi-APK app that’s designed for lower
+ Vulkan support on devices with higher version support. Currently, the Google
+ Play Store does not accept uploads of Apps which use Vulkan version
+ targeting. This support will be added to the Google Play Store in the
+ future any Android N devices using the Google Play services 9.0.83 will
+ continue to receive versions of Apps targeting basic Vulkan support.
+ </li>
+</ul>
+
+<h4>Android Auto</h4>
+<ul>
+ <li>The version of Google Maps included in Developer Preview 5 (9.30)
+ crashes when used with Android Auto. This issue will be fixed in the
+ next update to Google Maps (9.31), expected in the coming weeks.
+ </li>
+</ul>
+
+
+
+<!-- TBA, if any
+<h4>Device-specific issues</h4>
+
+<dl>
+ <dt>
+ <strong>Device Name</strong>
+ </dt>
+
+ <dd>
+ Issue 1
+ </dd>
+
+ <dd>
+ Issue 2
+ </dd>
+</dl>
+
+-->
+<!-- TBA, if any
+
+<h4 id="dp5-fixes">Fixes for issues reported by developers</h4>
+
+<p>
+ A number of issues reported by developers have been fixed, including:
+</p>
+
+<ul>
+ <li>TODO</li>
+</ul>
+
+-->
+
+<h3 id="upgrade-notes">Notes on publishing apps that target API 24</h3>
+
+<p>
+ Before publishing apps that target API 24 in Google Play, keep these points
+ in mind:
+</p>
+
+<ul>
+ <li>If your app’s current <code>targetSdkVersion</code> is 22 or lower and
+ you want to target API 24, you’ll need to support <a href=
+ "{@docRoot}about/versions/marshmallow/android-6.0-changes.html">behaviors
+ introduced with Android 6.0 (Marshmallow)</a>, such as <a href=
+ "{@docRoot}training/permissions/requesting.html">runtime permissions</a>, in
+ addition to Android N behaviors.
+ </li>
+
+ <li>Once you publish an app with <code>targetSdkVersion</code> set to 23 or
+ higher, you can't later publish a version of the app with a higher
+ <code>versionCode</code> that targets 22 or lower. This restriction applies
+ in alpha and beta channels as well as production channel.
+ </li>
+</ul>
+
+
+<!-- DP4 Release Notes Archive -->
+
<h2 id="dp4">Developer Preview 4</h2>
<div class="wrap">
@@ -65,7 +257,7 @@
</div>
</div>
-<h3 id="general">General advisories</h3>
+<h3 id="dp4-general">General advisories</h3>
<p>
This Developer Preview release is for <strong>app developers and other early
@@ -97,7 +289,7 @@
</ul>
-<h3 id="new">New in DP4</h3>
+<h3 id="dp4-new">New in DP4</h3>
<h4>Android N final APIs</h4>
@@ -129,7 +321,7 @@
your app ready for an update in the Play store.
</p>
-<h4 id="api-changes">Feature and API changes</h4>
+<h4 id="dp4-api-changes">Feature and API changes</h4>
<ul>
<li>In previous versions of Android, an app activates with all of its locale
@@ -156,7 +348,7 @@
</li>
</ul>
-<h3 id="ki">Known Issues</h3>
+<h3 id="dp4-ki">Known Issues</h3>
<h4>Stability</h4>
@@ -280,7 +472,7 @@
</li>
</ul>
-<h4 id="">Android Auto</h4>
+<h4>Android Auto</h4>
<p>
The version of Google Maps included in Developer Preview 4 (9.30) crashes
@@ -344,7 +536,7 @@
<p>For the full list of fixed issues, see <a href="https://goo.gl/6uCKtf">the
issue tracker</a>.</p>
-<h3 id="upgrade-notes">Notes on publishing apps that target API 24</h3>
+<h3 id="dp4-upgrade-notes">Notes on publishing apps that target API 24</h3>
<p>
Before publishing apps that target API 24 in Google Play, keep these points
diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
index 47d2ac1..7e78925 100644
--- a/docs/html/topic/libraries/support-library/revisions.jd
+++ b/docs/html/topic/libraries/support-library/revisions.jd
@@ -6,9 +6,129 @@
<p>This page provides details about the Support Library package releases.</p>
<div class="toggle-content opened">
- <p id="rev24-0-0">
+ <p id="rev24-1-0">
<a href="#" onclick="return toggleContent(this)"><img src=
"{@docRoot}assets/images/styles/disclosure_up.png" class=
+ "toggle-content-img" alt="">Android Support Library, revision 24.1.0</a>
+ <em>(July 2016)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+ <dl>
+ <dt>
+ Changes for <a href=
+ "{@docRoot}tools/support-library/features.html#v4">v4 Support
+ Library</a>:
+ </dt>
+
+ <dd>
+ <ul>
+ <li>{@link android.support.v4.app.NotificationCompat.Action.WearableExtender}
+ has new <code>getHintDisplayActionInline()</code> and
+ <code>setHintDisplayActionInline()</code> methods for compatibility with
+ <a href="{@docRoot}wear/preview/index.html">Android Wear 2.0 Preview</a>.
+ These methods allow an application to specify that an action should be
+ displayed inline with the notification.
+ </li>
+
+ <li>Calling {@link android.support.v4.app.Fragment#setUserVisibleHint
+ Fragment.setUserVisbileHint()} will no longer cause a fragment to become
+ <strong>started</strong> if the hint has been added to a {@link
+ android.support.v4.app.FragmentTransaction} that is not yet committed. This
+ affects users of {@link android.support.v4.app.FragmentPagerAdapter} that
+ override {@link android.support.v4.app.Fragment#setUserVisibleHint
+ setUserVisbileHint()} and assume a specific lifecycle state of the fragment
+ after calling <code>super.setUserVisibleHint()</code>. For more information,
+ see the reference page for docs for {@link
+ android.support.v4.app.Fragment#setUserVisibleHint
+ Fragment.setUserVisbileHint()}.
+ </li>
+ </ul>
+
+ </dl>
+ <p>Fixed issues:</p>
+
+ <ul>
+ <li>TabLayout.setCustomView(null) results in NullPointerException
+ (<a href="https://code.google.com/p/android/issues/detail?id=214753">AOSP
+ issue</a>)
+ </li>
+
+ <li>TabLayout incorrectly highlights custom tabs (<a href=
+ "https://code.google.com/p/android/issues/detail?id=214316">AOSP issue 214316</a>)
+ </li>
+
+ <li>AppCompatTextHelper uses incorrectly sorted attribute array (<a href=
+ "https://code.google.com/p/android/issues/detail?id=214366">AOSP issue 214366</a>)
+ </li>
+
+ <li>Unable to reference VectorDrawable from drawable container XML when using
+ custom ContextWrapper (<a href=
+ "https://code.google.com/p/android/issues/detail?id=214055">AOSP issue 214055</a>)
+ </li>
+
+ <li>ViewDragHelper.saveLastMotion() throws ArrayIndexOutOfBoundsException
+ (<a href="https://code.google.com/p/android/issues/detail?id=212945">AOSP
+ issue 212945</a>)
+ </li>
+
+ <li>BottomSheetBehavior expands to old content height when using
+ setState(STATE_EXPANDED) (<a href=
+ "https://code.google.com/p/android/issues/detail?id=213660">AOSP issue
+ 213660</a>)
+ </li>
+
+ <li>CollapsingToolbarLayout doesn’t handle pinnable children with top or
+ bottom margins (<a href=
+ "https://code.google.com/p/android/issues/detail?id=213001">AOSP issue
+ 213001</a>)
+ </li>
+
+ <li>Leanback browse title does not support RTL alignment (<a href=
+ "https://code.google.com/p/android/issues/detail?id=213461">AOSP issue
+ 213461</a>)
+ </li>
+
+ <li>PagerTabStrip disappears due to missing inherited annotation (<a href=
+ "https://code.google.com/p/android/issues/detail?id=213359">AOSP issue
+ 213359</a>)
+ </li>
+
+ <li>Data binding throws NullPointerException when using Boolean to set
+ conditional flags (<a href=
+ "https://code.google.com/p/android/issues/detail?id=191841">AOSP issue
+ 191841</a>)
+ </li>
+
+ <li>CoordinatorLayout does not respond to setFitsSystemWindows() (<a href=
+ "https://code.google.com/p/android/issues/detail?id=212720">AOSP issue
+ 212720</a>)
+ </li>
+
+ <li>BottomSheetBehavior crashes when setting initial state (<a href=
+ "https://code.google.com/p/android/issues/detail?id=203114">AOSP issue
+ 203114</a>)
+ </li>
+
+ <li>ViewPager skips pages if the page index is a large value (<a href=
+ "https://code.google.com/p/android/issues/detail?id=211734">AOSP issue
+ 211734</a>)
+ </li>
+
+ <li>BottomSheetBehavior does not work with dynamic layouts (<a href=
+ "https://code.google.com/p/android/issues/detail?id=205226">AOSP issue
+ 205226</a>)
+ </li>
+ </ul>
+ </div>
+</div>
+
+<!-- end of collapsible section: 24.1.0 -->
+
+<div class="toggle-content closed">
+ <p id="rev24-0-0">
+ <a href="#" onclick="return toggleContent(this)"><img src=
+ "{@docRoot}assets/images/styles/disclosure_down.png" class=
"toggle-content-img" alt="">Android Support Library, revision 24.0.0</a>
<em>(June 2016)</em>
</p>
@@ -120,7 +240,7 @@
<div class="toggle-content closed">
<p id="rev23-4-0">
<a href="#" onclick="return toggleContent(this)"><img src=
- "{@docRoot}assets/images/styles/disclosure_up.png" class=
+ "{@docRoot}assets/images/styles/disclosure_down.png" class=
"toggle-content-img" alt="">Android Support Library, revision 23.4.0</a>
<em>(May 2016)</em>
</p>
diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd
index 08c610f..e08db15 100644
--- a/docs/html/topic/performance/index.jd
+++ b/docs/html/topic/performance/index.jd
@@ -1,6 +1,6 @@
page.title=Performance
page.article=true
-page.metaDescription=Android Performance does nice things. Details to come.
+page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance.
meta.tags="performance"
page.tags="performance"
diff --git a/docs/html/topic/performance/launch-time.jd b/docs/html/topic/performance/launch-time.jd
index c9ce1d5..84d5fab 100644
--- a/docs/html/topic/performance/launch-time.jd
+++ b/docs/html/topic/performance/launch-time.jd
@@ -112,7 +112,7 @@
</p>
<br/>
- <img src="{@docRoot}performance/images/cold-launch.png">
+ <img src="{@docRoot}topic/performance/images/cold-launch.png">
<p class="img-caption">
<strong>Figure 1.</strong> A visual representation of the important parts of
a cold application launch.
@@ -262,7 +262,7 @@
</p>
<br/>
- <img src="{@docRoot}performance/images/displayed-logcat.png">
+ <img src="{@docRoot}topic/performance/images/displayed-logcat.png">
<p class="img-caption">
<strong>Figure 2.</strong> Disabling filters, and
finding the {@code Displayed} value in logcat.
diff --git a/docs/html/wear/preview/_book.yaml b/docs/html/wear/preview/_book.yaml
index 3bea2fd..a231fb5 100644
--- a/docs/html/wear/preview/_book.yaml
+++ b/docs/html/wear/preview/_book.yaml
@@ -30,5 +30,8 @@
- title: License Agreement
path: /wear/preview/license.html
+- title: Behavior Changes
+ path: /wear/preview/behavior-changes.html
+
- title: Support and Release Notes
path: /wear/preview/support.html
diff --git a/docs/html/wear/preview/behavior-changes.jd b/docs/html/wear/preview/behavior-changes.jd
new file mode 100644
index 0000000..0214622
--- /dev/null
+++ b/docs/html/wear/preview/behavior-changes.jd
@@ -0,0 +1,63 @@
+page.title=Behavior Changes
+meta.keywords="preview", "wear"
+page.tags="preview", "developer preview"
+
+@jd:body
+
+<p>
+ Along with new features, Android Wear 2.0 includes a variety of behavior
+ changes. This document highlights some of the key changes to
+ account for in your apps.
+</p>
+
+<p>
+ If you have previously published an app for Android Wear, be aware that
+ your app might be affected by these changes in the platform.
+</p>
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+<ul>
+ <li><a href="#activity-dismissal">Activity Dismissal</a></li>
+</ul>
+
+</div>
+</div>
+
+<h2 id="activity-dismissal">Activity Dismissal</h2>
+
+<p>
+ Starting in <a href="{@docRoot}wear/preview/index.html">Android Wear 2.0</a>,
+ users dismiss apps and activities by using
+ the power (stem) button on the watch.
+ Long-pressing to dismiss an app is no longer suggested.
+ Additionally, developers should not implement the
+ long-press for dismissing
+ <a href="{@docRoot}training/wearables/ui/exit.html">full screen</a>
+ activities (panning or immersive activities such as Google Maps).
+</p>
+
+<p>
+ In Android Wear 2.0, the power button of the watch is used
+ to navigate back in the
+ <a href="{@docRoot}guide/components/tasks-and-back-stack.html">back stack</a>,
+ including for full-screen panning activities.
+ Before Android Wear 2.0, the <code>DismissOverlayView</code> class was
+ used to implement the long-press for a user to dismiss an app.
+ (The <code>DismissOverlayView</code> class was added to a layout
+ for full-screen drawing and to draw over the other views.)
+ Developers should test the power button for going back
+ between an app's activities and for exiting an app.
+</p>
+
+<p>
+ Additionally, swipe for exiting an app or activity is not available.
+ Developers can consider how their user interfaces
+ can be enhanced with swipe-left and swipe-right,
+ in a way similar to the functionality described for
+ <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">navigation
+ drawers</a>.
+</p>
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 4f6368c..dc1d18f 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -235,7 +235,7 @@
private final Rect mTmpBounds = new Rect();
public VectorDrawable() {
- this(new VectorDrawableState(), null);
+ this(new VectorDrawableState(null), null);
}
/**
@@ -830,7 +830,8 @@
private static final int NATIVE_ALLOCATION_SIZE = 316;
- // Deep copy for mutate() or implicitly mutate.
+ // If copy is not null, deep copy the given VectorDrawableState. Otherwise, create a
+ // native vector drawable tree with an empty root group.
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
mThemeAttrs = copy.mThemeAttrs;
@@ -851,8 +852,11 @@
if (copy.mRootName != null) {
mVGTargetsMap.put(copy.mRootName, this);
}
- onTreeConstructionFinished();
+ } else {
+ mRootGroup = new VGroup();
+ createNativeTree(mRootGroup);
}
+ onTreeConstructionFinished();
}
private void createNativeTree(VGroup rootGroup) {
@@ -870,7 +874,8 @@
VMRuntime.getRuntime().registerNativeAllocation(NATIVE_ALLOCATION_SIZE);
}
-
+ // This should be called every time after a new RootGroup and all its subtrees are created
+ // (i.e. in constructors of VectorDrawableState and in inflate).
void onTreeConstructionFinished() {
mRootGroup.setTree(mNativeTree);
mAllocationOfAllNodes = mRootGroup.getNativeSize();
@@ -918,11 +923,6 @@
|| super.canApplyTheme();
}
- public VectorDrawableState() {
- mRootGroup = new VGroup();
- createNativeTree(mRootGroup);
- }
-
@Override
public Drawable newDrawable() {
return new VectorDrawable(this, null);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 9481c46..f413184 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
+import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
@@ -192,7 +193,8 @@
* </ul>
*
* @deprecated Use {@link #ACTION_KEYCHAIN_CHANGED}, {@link #ACTION_STORAGE_CHANGED} or
- * {@link #ACTION_KEY_ACCESS_CHANGED}.
+ * {@link #ACTION_KEY_ACCESS_CHANGED}. Apps that target a version higher than
+ * {@link Build.VERSION_CODES#N_MR1} will not receive this broadcast.
*/
public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4e0504f..bf2648a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -804,8 +804,14 @@
if (off < (mStringPoolSize-1)) {
const uint8_t* strings = (uint8_t*)mStrings;
const uint8_t* str = strings+off;
- *outLen = decodeLength(&str);
- size_t encLen = decodeLength(&str);
+
+ // Decode the UTF-16 length. This is not used if we're not
+ // converting to UTF-16 from UTF-8.
+ decodeLength(&str);
+
+ const size_t encLen = decodeLength(&str);
+ *outLen = encLen;
+
if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
return (const char*)str;
} else {
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 95b28d3..3cce353 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -24,6 +24,7 @@
renderstate/Stencil.cpp \
renderstate/TextureState.cpp \
renderthread/CanvasContext.cpp \
+ renderthread/OpenGLPipeline.cpp \
renderthread/DrawFrameTask.cpp \
renderthread/EglManager.cpp \
renderthread/RenderProxy.cpp \
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 39b8d3d..84451ba 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -530,14 +530,14 @@
}
void ClipArea::applyTransformToRegion(const Matrix4& transform, SkRegion* region) {
- if (transform.isSimple() && !transform.isPureTranslate()) {
+ if (transform.rectToRect() && !transform.isPureTranslate()) {
// handle matrices with scale manually by mapping each rect
SkRegion other;
SkRegion::Iterator it(*region);
while (!it.done()) {
Rect rect(it.rect());
transform.mapRect(rect);
- rect.roundOut();
+ rect.snapGeometryToPixelBoundaries(true);
other.op(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kUnion_Op);
it.next();
}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index d0ae1d4..93b2e15 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -214,8 +214,8 @@
property_get(PROPERTY_DEFAULT_RENDERER, prop, "opengl");
if (!strcmp(prop, "skiagl") ) {
sRenderPipelineType = RenderPipelineType::SkiaGL;
- } else if (!strcmp(prop, "vulkan") ) {
- sRenderPipelineType = RenderPipelineType::Vulkan;
+ } else if (!strcmp(prop, "skiavulkan") ) {
+ sRenderPipelineType = RenderPipelineType::SkiaVulkan;
} else { //"opengl"
sRenderPipelineType = RenderPipelineType::OpenGL;
}
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 5d892fd..133ae80 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -253,7 +253,7 @@
enum class RenderPipelineType {
OpenGL = 0,
SkiaGL,
- Vulkan,
+ SkiaVulkan,
NotInitialized = 128
};
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index 49021bc..f9274e1 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -60,7 +60,7 @@
virtual uint32_t dirtyMask();
bool isInfinite() { return mIsInfinite; }
void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
- VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable; }
+ VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable.get(); }
AnimationListener* getOneShotListener() { return mOneShotListener.get(); }
void clearOneShotListener() { mOneShotListener = nullptr; }
uint32_t getRequestId() const { return mRequestId; }
@@ -78,7 +78,7 @@
std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
float mLastFraction = 0.0f;
bool mInitialized = false;
- VectorDrawableRoot* mVectorDrawable = nullptr;
+ sp<VectorDrawableRoot> mVectorDrawable;
bool mIsInfinite = false;
// This request id gets incremented (on UI thread only) when a new request to modfiy the
// lifecycle of an animation happens, namely when start/end/reset/reverse is called.
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 9df32b28..f264a35 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -23,6 +23,7 @@
#include <SkPixelRef.h>
#include <SkRect.h>
#include <SkRRect.h>
+#include <SkSurface.h>
#include <memory>
@@ -153,7 +154,7 @@
mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
}
-SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
+sk_sp<SkSurface> SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
return NULL;
}
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 973c55f..d1c9c6b 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -44,7 +44,7 @@
protected:
- virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
+ virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
virtual void willSave() override;
virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h
index 0642d59..073d59b 100644
--- a/libs/hwui/font/CachedGlyphInfo.h
+++ b/libs/hwui/font/CachedGlyphInfo.h
@@ -17,8 +17,6 @@
#ifndef ANDROID_HWUI_CACHED_GLYPH_INFO_H
#define ANDROID_HWUI_CACHED_GLYPH_INFO_H
-#include <SkFixed.h>
-
namespace android {
namespace uirenderer {
@@ -41,14 +39,14 @@
float mBitmapMaxV;
// Minimize how much we call freetype
uint32_t mGlyphIndex;
- uint32_t mAdvanceX;
- uint32_t mAdvanceY;
+ float mAdvanceX;
+ float mAdvanceY;
// Values below contain a glyph's origin in the bitmap
int32_t mBitmapLeft;
int32_t mBitmapTop;
- // Auto-kerning
- SkFixed mLsbDelta;
- SkFixed mRsbDelta;
+ // Auto-kerning; represents a 2.6 fixed-point value with range [-1, 1].
+ int8_t mLsbDelta;
+ int8_t mRsbDelta;
CacheTexture* mCacheTexture;
};
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 8e04c87..9c812bc 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -304,7 +304,7 @@
}
int glyphsCount = 0;
- SkFixed prevRsbDelta = 0;
+ int prevRsbDelta = 0;
float penX = 0.0f;
@@ -332,14 +332,14 @@
}
CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
- penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
+ penX += AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta);
prevRsbDelta = cachedGlyph->mRsbDelta;
if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
}
- penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
+ penX += cachedGlyph->mAdvanceX;
glyphsCount++;
}
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index aa77d98..07e8b34 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -44,6 +44,8 @@
#define GET_METRICS(cache, glyph) cache->getGlyphIDMetrics(glyph)
#define IS_END_OF_STRING(glyph) false
-#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16)
+// prev, next are assumed to be signed x.6 fixed-point numbers with range
+// [-1, 1]. Result is an integral float.
+#define AUTO_KERN(prev, next) static_cast<float>(((next) - (prev) + 32) >> 6)
#endif // ANDROID_HWUI_FONT_UTIL_H
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d36ebc7..2eccca9 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -30,6 +30,7 @@
#include "renderstate/RenderState.h"
#include "renderstate/Stencil.h"
#include "protos/hwui.pb.h"
+#include "OpenGLPipeline.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
@@ -65,14 +66,16 @@
bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) {
auto renderType = Properties::getRenderPipelineType();
+
switch (renderType) {
case RenderPipelineType::OpenGL:
- return new CanvasContext(thread, translucent, rootRenderNode, contextFactory);
+ return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
+ std::make_unique<OpenGLPipeline>(thread));
case RenderPipelineType::SkiaGL:
//TODO: implement SKIA GL
LOG_ALWAYS_FATAL("skiaGL canvas type not implemented.");
break;
- case RenderPipelineType::Vulkan:
+ case RenderPipelineType::SkiaVulkan:
//TODO: implement Vulkan
LOG_ALWAYS_FATAL("Vulkan canvas type not implemented.");
break;
@@ -84,14 +87,15 @@
}
CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
- RenderNode* rootRenderNode, IContextFactory* contextFactory)
+ RenderNode* rootRenderNode, IContextFactory* contextFactory,
+ std::unique_ptr<IRenderPipeline> renderPipeline)
: mRenderThread(thread)
- , mEglManager(thread.eglManager())
, mOpaque(!translucent)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
, mJankTracker(thread.timeLord().frameIntervalNanos())
, mProfiler(mFrames)
- , mContentDrawBounds(0, 0, 0, 0) {
+ , mContentDrawBounds(0, 0, 0, 0)
+ , mRenderPipeline(std::move(renderPipeline)) {
mRenderNodes.emplace_back(rootRenderNode);
mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
@@ -115,24 +119,15 @@
mNativeSurface = surface;
- if (mEglSurface != EGL_NO_SURFACE) {
- mEglManager.destroySurface(mEglSurface);
- mEglSurface = EGL_NO_SURFACE;
- }
-
- if (surface) {
- mEglSurface = mEglManager.createSurface(surface);
- }
+ bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior);
mFrameNumber = -1;
- if (mEglSurface != EGL_NO_SURFACE) {
- const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer);
- mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
- mHaveNewSurface = true;
- mSwapHistory.clear();
+ if (hasSurface) {
+ mHaveNewSurface = true;
+ mSwapHistory.clear();
} else {
- mRenderThread.removeFrameCallback(this);
+ mRenderThread.removeFrameCallback(this);
}
}
@@ -157,9 +152,7 @@
mStopped = stopped;
if (mStopped) {
mRenderThread.removeFrameCallback(this);
- if (mEglManager.isCurrent(mEglSurface)) {
- mEglManager.makeCurrent(EGL_NO_SURFACE);
- }
+ mRenderPipeline->onStop();
} else if (mIsDirty && hasSurface()) {
mRenderThread.postFrameCallback(this);
}
@@ -184,14 +177,23 @@
bool CanvasContext::makeCurrent() {
if (mStopped) return false;
- // TODO: Figure out why this workaround is needed, see b/13913604
- // In the meantime this matches the behavior of GLRenderer, so it is not a regression
- EGLint error = 0;
- mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error);
- if (error) {
- setSurface(nullptr);
+ auto result = mRenderPipeline->makeCurrent();
+ switch (result) {
+ case MakeCurrentResult::AlreadyCurrent:
+ return true;
+ case MakeCurrentResult::Failed:
+ mHaveNewSurface = true;
+ setSurface(nullptr);
+ return false;
+ case MakeCurrentResult::Succeeded:
+ mHaveNewSurface = true;
+ return true;
+ default:
+ LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent",
+ (int32_t) result);
}
- return !error;
+
+ return true;
}
static bool wasSkipped(FrameInfo* info) {
@@ -328,9 +330,6 @@
}
void CanvasContext::draw() {
- LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "drawRenderNode called on a context with no surface!");
-
SkRect dirty;
mDamageAccumulator.finish(&dirty);
@@ -342,98 +341,27 @@
mCurrentFrameInfo->markIssueDrawCommandsStart();
- Frame frame = mEglManager.beginFrame(mEglSurface);
+ Frame frame = mRenderPipeline->getFrame();
- if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
- // can't rely on prior content of window if viewport size changes
- dirty.setEmpty();
- mLastFrameWidth = frame.width();
- mLastFrameHeight = frame.height();
- } else if (mHaveNewSurface || frame.bufferAge() == 0) {
- // New surface needs a full draw
- dirty.setEmpty();
- } else {
- if (!dirty.isEmpty() && !dirty.intersect(0, 0, frame.width(), frame.height())) {
- ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
- SK_RECT_ARGS(dirty), frame.width(), frame.height());
- dirty.setEmpty();
- }
- profiler().unionDirty(&dirty);
- }
+ SkRect windowDirty = computeDirtyRect(frame, &dirty);
- if (dirty.isEmpty()) {
- dirty.set(0, 0, frame.width(), frame.height());
- }
-
- // At this point dirty is the area of the screen to update. However,
- // the area of the frame we need to repaint is potentially different, so
- // stash the screen area for later
- SkRect screenDirty(dirty);
-
- // If the buffer age is 0 we do a full-screen repaint (handled above)
- // If the buffer age is 1 the buffer contents are the same as they were
- // last frame so there's nothing to union() against
- // Therefore we only care about the > 1 case.
- if (frame.bufferAge() > 1) {
- if (frame.bufferAge() > (int) mSwapHistory.size()) {
- // We don't have enough history to handle this old of a buffer
- // Just do a full-draw
- dirty.set(0, 0, frame.width(), frame.height());
- } else {
- // At this point we haven't yet added the latest frame
- // to the damage history (happens below)
- // So we need to damage
- for (int i = mSwapHistory.size() - 1;
- i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
- dirty.join(mSwapHistory[i].damage);
- }
- }
- }
-
- mEglManager.damageFrame(frame, dirty);
-
- auto& caches = Caches::getInstance();
- FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), mLightGeometry, caches);
-
- frameBuilder.deferLayers(mLayerUpdateQueue);
- mLayerUpdateQueue.clear();
-
- frameBuilder.deferRenderNodeScene(mRenderNodes, mContentDrawBounds);
-
- BakedOpRenderer renderer(caches, mRenderThread.renderState(),
- mOpaque, mLightInfo);
- frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
- profiler().draw(&renderer);
- bool drew = renderer.didDraw();
-
- // post frame cleanup
- caches.clearGarbage();
- caches.pathCache.trim();
- caches.tessellationCache.trim();
-
-#if DEBUG_MEMORY_USAGE
- mCaches.dumpMemoryUsage();
-#else
- if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
- caches.dumpMemoryUsage();
- }
-#endif
+ bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
+ mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler()));
waitOnFences();
- GL_CHECKPOINT(LOW);
+ bool requireSwap = false;
+ bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo,
+ &requireSwap);
- // Even if we decided to cancel the frame, from the perspective of jank
- // metrics the frame was swapped at this point
- mCurrentFrameInfo->markSwapBuffers();
mIsDirty = false;
- if (drew || mEglManager.damageRequiresSwap()) {
- if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
+ if (requireSwap) {
+ if (!didSwap) { //some error happened
setSurface(nullptr);
}
SwapHistory& swap = mSwapHistory.next();
- swap.damage = screenDirty;
+ swap.damage = windowDirty;
swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC);
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
mHaveNewSurface = false;
@@ -469,7 +397,7 @@
// Called by choreographer to do an RT-driven animation
void CanvasContext::doFrame() {
- if (CC_UNLIKELY(mEglSurface == EGL_NO_SURFACE)) return;
+ if (!mRenderPipeline->isSurfaceReady()) return;
prepareAndDraw(nullptr);
}
@@ -519,7 +447,7 @@
void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
ATRACE_CALL();
- if (!mEglManager.hasEglContext()) return;
+ if (!mRenderPipeline->isContextReady()) return;
// buildLayer() will leave the tree in an unknown state, so we must stop drawing
stopDrawing();
@@ -536,37 +464,24 @@
// purposes when the frame is actually drawn
node->setPropertyFieldsDirty(RenderNode::GENERIC);
- static const std::vector< sp<RenderNode> > emptyNodeList;
- auto& caches = Caches::getInstance();
- FrameBuilder frameBuilder(mLayerUpdateQueue, mLightGeometry, caches);
- mLayerUpdateQueue.clear();
- BakedOpRenderer renderer(caches, mRenderThread.renderState(),
- mOpaque, mLightInfo);
- LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
- frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+ mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
node->incStrong(nullptr);
mPrefetchedLayers.insert(node);
}
bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
- layer->apply();
- return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
- == CopyResult::Success;
+ return mRenderPipeline->copyLayerInto(layer, bitmap);
}
void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
stopDrawing();
- if (mEglManager.hasEglContext()) {
+ if (mRenderPipeline->isContextReady()) {
freePrefetchedLayers(observer);
for (const sp<RenderNode>& node : mRenderNodes) {
node->destroyHardwareResources(observer);
}
- Caches& caches = Caches::getInstance();
- // Make sure to release all the textures we were owning as there won't
- // be another draw
- caches.textureCache.resetMarkInUse(this);
- mRenderThread.renderState().flush(Caches::FlushMode::Layers);
+ mRenderPipeline->onDestroyHardwareResources();
}
}
@@ -584,8 +499,7 @@
}
Layer* CanvasContext::createTextureLayer() {
- mEglManager.initialize();
- return LayerRenderer::createTextureLayer(mRenderThread.renderState());
+ return mRenderPipeline->createTextureLayer();
}
void CanvasContext::setTextureAtlas(RenderThread& thread,
@@ -665,8 +579,8 @@
class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
public:
- explicit FuncTaskProcessor(Caches& caches)
- : TaskProcessor<bool>(&caches.tasks) {}
+ explicit FuncTaskProcessor(TaskManager* taskManager)
+ : TaskProcessor<bool>(taskManager) {}
virtual void onProcess(const sp<Task<bool> >& task) override {
FuncTask* t = static_cast<FuncTask*>(task.get());
@@ -677,7 +591,7 @@
void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
if (!mFrameWorkProcessor.get()) {
- mFrameWorkProcessor = new FuncTaskProcessor(Caches::getInstance());
+ mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager());
}
sp<FuncTask> task(new FuncTask());
task->func = func;
@@ -693,9 +607,54 @@
return mFrameNumber;
}
-bool CanvasContext::isSkiaEnabled() {
- auto renderType = Properties::getRenderPipelineType();
- return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::Vulkan == renderType;
+SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
+ if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
+ // can't rely on prior content of window if viewport size changes
+ dirty->setEmpty();
+ mLastFrameWidth = frame.width();
+ mLastFrameHeight = frame.height();
+ } else if (mHaveNewSurface || frame.bufferAge() == 0) {
+ // New surface needs a full draw
+ dirty->setEmpty();
+ } else {
+ if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) {
+ ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
+ SK_RECT_ARGS(*dirty), frame.width(), frame.height());
+ dirty->setEmpty();
+ }
+ profiler().unionDirty(dirty);
+ }
+
+ if (dirty->isEmpty()) {
+ dirty->set(0, 0, frame.width(), frame.height());
+ }
+
+ // At this point dirty is the area of the window to update. However,
+ // the area of the frame we need to repaint is potentially different, so
+ // stash the screen area for later
+ SkRect windowDirty(*dirty);
+
+ // If the buffer age is 0 we do a full-screen repaint (handled above)
+ // If the buffer age is 1 the buffer contents are the same as they were
+ // last frame so there's nothing to union() against
+ // Therefore we only care about the > 1 case.
+ if (frame.bufferAge() > 1) {
+ if (frame.bufferAge() > (int) mSwapHistory.size()) {
+ // We don't have enough history to handle this old of a buffer
+ // Just do a full-draw
+ dirty->set(0, 0, frame.width(), frame.height());
+ } else {
+ // At this point we haven't yet added the latest frame
+ // to the damage history (happens below)
+ // So we need to damage
+ for (int i = mSwapHistory.size() - 1;
+ i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
+ dirty->join(mSwapHistory[i].damage);
+ }
+ }
+ }
+
+ return windowDirty;
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 72f1268..42e9be3 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -24,6 +24,7 @@
#include "FrameInfoVisualizer.h"
#include "FrameMetricsReporter.h"
#include "IContextFactory.h"
+#include "IRenderPipeline.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
#include "thread/Task.h"
@@ -56,11 +57,7 @@
namespace renderthread {
class EglManager;
-
-enum SwapBehavior {
- kSwap_default,
- kSwap_discardBuffer,
-};
+class Frame;
// This per-renderer class manages the bridge between the global EGL context
// and the render surface.
@@ -102,7 +99,6 @@
static void trimMemory(RenderThread& thread, int level);
static void invokeFunctor(RenderThread& thread, Functor* functor);
- static bool isSkiaEnabled();
Layer* createTextureLayer();
@@ -164,7 +160,7 @@
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
- IContextFactory* contextFactory);
+ IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -179,21 +175,20 @@
bool isSwapChainStuffed();
+ SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
+
EGLint mLastFrameWidth = 0;
EGLint mLastFrameHeight = 0;
RenderThread& mRenderThread;
- EglManager& mEglManager;
sp<Surface> mNativeSurface;
- EGLSurface mEglSurface = EGL_NO_SURFACE;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
// CanvasContext is dirty if it has received an update that it has not
// painted onto its surface.
bool mIsDirty = false;
- bool mBufferPreserved = false;
- SwapBehavior mSwapBehavior = kSwap_default;
+ SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default;
struct SwapHistory {
SkRect damage;
nsecs_t vsyncTime;
@@ -238,6 +233,7 @@
std::vector< sp<FuncTask> > mFrameFences;
sp<TaskProcessor<bool> > mFrameWorkProcessor;
+ std::unique_ptr<IRenderPipeline> mRenderPipeline;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
new file mode 100644
index 0000000..0c0fbe9
--- /dev/null
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include "FrameInfoVisualizer.h"
+#include "EglManager.h"
+
+#include <SkRect.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class Surface;
+
+namespace uirenderer {
+
+class DeferredLayerUpdater;
+
+namespace renderthread {
+
+enum class SwapBehavior {
+ kSwap_default,
+ kSwap_discardBuffer,
+};
+
+enum class MakeCurrentResult {
+ AlreadyCurrent,
+ Failed,
+ Succeeded
+};
+
+class IRenderPipeline {
+public:
+ virtual MakeCurrentResult makeCurrent() = 0;
+ virtual Frame getFrame() = 0;
+ virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector< sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) = 0;
+ virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
+ virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0;
+ virtual Layer* createTextureLayer() = 0;
+ virtual bool setSurface(Surface* window, SwapBehavior swapBehavior) = 0;
+ virtual void onStop() = 0;
+ virtual bool isSurfaceReady() = 0;
+ virtual bool isContextReady() = 0;
+ virtual void onDestroyHardwareResources() = 0;
+ virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ const BakedOpRenderer::LightInfo& lightInfo) = 0;
+ virtual TaskManager* getTaskManager() = 0;
+
+ virtual ~IRenderPipeline() {}
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
new file mode 100644
index 0000000..3a2b155
--- /dev/null
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "OpenGLPipeline.h"
+
+#include "DeferredLayerUpdater.h"
+#include "EglManager.h"
+#include "LayerRenderer.h"
+#include "renderstate/RenderState.h"
+#include "Readback.h"
+
+#include <android/native_window.h>
+#include <cutils/properties.h>
+#include <strings.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
+ : mEglManager(thread.eglManager()), mRenderThread(thread) {
+}
+
+MakeCurrentResult OpenGLPipeline::makeCurrent() {
+ // TODO: Figure out why this workaround is needed, see b/13913604
+ // In the meantime this matches the behavior of GLRenderer, so it is not a regression
+ EGLint error = 0;
+ bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error);
+
+ Caches::getInstance().textureCache.resetMarkInUse(this);
+ if (!haveNewSurface) {
+ return MakeCurrentResult::AlreadyCurrent;
+ }
+ return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
+}
+
+Frame OpenGLPipeline::getFrame() {
+ LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+ "drawRenderNode called on a context with no surface!");
+ return mEglManager.beginFrame(mEglSurface);
+}
+
+bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector< sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) {
+
+ mEglManager.damageFrame(frame, dirty);
+
+ bool drew = false;
+
+
+ auto& caches = Caches::getInstance();
+ FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
+
+ frameBuilder.deferLayers(*layerUpdateQueue);
+ layerUpdateQueue->clear();
+
+ frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
+
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(),
+ opaque, lightInfo);
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+ profiler->draw(&renderer);
+ drew = renderer.didDraw();
+
+ // post frame cleanup
+ caches.clearGarbage();
+ caches.pathCache.trim();
+ caches.tessellationCache.trim();
+
+#if DEBUG_MEMORY_USAGE
+ mCaches.dumpMemoryUsage();
+#else
+ if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
+ caches.dumpMemoryUsage();
+ }
+#endif
+
+ return drew;
+}
+
+bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
+
+ GL_CHECKPOINT(LOW);
+
+ // Even if we decided to cancel the frame, from the perspective of jank
+ // metrics the frame was swapped at this point
+ currentFrameInfo->markSwapBuffers();
+
+ *requireSwap = drew || mEglManager.damageRequiresSwap();
+
+ if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
+ return false;
+ }
+
+ return *requireSwap;
+}
+
+bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+ layer->apply();
+ return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
+ == CopyResult::Success;
+}
+
+Layer* OpenGLPipeline::createTextureLayer() {
+ mEglManager.initialize();
+ return LayerRenderer::createTextureLayer(mRenderThread.renderState());
+}
+
+void OpenGLPipeline::onStop() {
+ if (mEglManager.isCurrent(mEglSurface)) {
+ mEglManager.makeCurrent(EGL_NO_SURFACE);
+ }
+}
+
+bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
+
+ if (mEglSurface != EGL_NO_SURFACE) {
+ mEglManager.destroySurface(mEglSurface);
+ mEglSurface = EGL_NO_SURFACE;
+ }
+
+ if (surface) {
+ mEglSurface = mEglManager.createSurface(surface);
+ }
+
+ if (mEglSurface != EGL_NO_SURFACE) {
+ const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
+ mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+ return true;
+ }
+
+ return false;
+}
+
+bool OpenGLPipeline::isSurfaceReady() {
+ return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
+}
+
+bool OpenGLPipeline::isContextReady() {
+ return CC_LIKELY(mEglManager.hasEglContext());
+}
+
+void OpenGLPipeline::onDestroyHardwareResources() {
+ Caches& caches = Caches::getInstance();
+ // Make sure to release all the textures we were owning as there won't
+ // be another draw
+ caches.textureCache.resetMarkInUse(this);
+ mRenderThread.renderState().flush(Caches::FlushMode::Layers);
+}
+
+void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ const BakedOpRenderer::LightInfo& lightInfo) {
+ static const std::vector< sp<RenderNode> > emptyNodeList;
+ auto& caches = Caches::getInstance();
+ FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
+ layerUpdateQueue->clear();
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(),
+ opaque, lightInfo);
+ LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+}
+
+TaskManager* OpenGLPipeline::getTaskManager() {
+ return &Caches::getInstance().tasks;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
new file mode 100644
index 0000000..a6d22ee
--- /dev/null
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include "CanvasContext.h"
+#include "BakedOpDispatcher.h"
+#include "BakedOpRenderer.h"
+#include "FrameBuilder.h"
+#include "IRenderPipeline.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class Frame;
+
+
+class OpenGLPipeline : public IRenderPipeline {
+public:
+ OpenGLPipeline(RenderThread& thread);
+ virtual ~OpenGLPipeline() {}
+
+ MakeCurrentResult makeCurrent() override;
+ Frame getFrame() override;
+ bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector< sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
+ bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
+ Layer* createTextureLayer() override;
+ bool setSurface(Surface* window, SwapBehavior swapBehavior) override;
+ void onStop() override;
+ bool isSurfaceReady() override;
+ bool isContextReady() override;
+ void onDestroyHardwareResources() override;
+ void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ const BakedOpRenderer::LightInfo& lightInfo) override;
+ TaskManager* getTaskManager() override;
+
+private:
+ EglManager& mEglManager;
+ EGLSurface mEglSurface = EGL_NO_SURFACE;
+ bool mBufferPreserved = false;
+ RenderThread& mRenderThread;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index afabd35..d4d7919 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -334,5 +334,14 @@
EXPECT_EQ(SkIRect::MakeLTRB(12, 26, 16, 32), region.getBounds());
}
+TEST(ClipArea, applyTransformToRegion_rotate90) {
+ SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
+ Matrix4 transform;
+ transform.loadRotate(90);
+ ClipArea::applyTransformToRegion(transform, ®ion);
+ EXPECT_TRUE(region.isRect());
+ EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds());
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java
index 3151694..7db0466 100644
--- a/location/java/android/location/GnssMeasurementsEvent.java
+++ b/location/java/android/location/GnssMeasurementsEvent.java
@@ -98,13 +98,13 @@
throw new InvalidParameterException("Parameter 'clock' must not be null.");
}
if (measurements == null || measurements.length == 0) {
- throw new InvalidParameterException(
- "Parameter 'measurements' must not be null or empty.");
+ mReadOnlyMeasurements = Collections.emptyList();
+ } else {
+ Collection<GnssMeasurement> measurementCollection = Arrays.asList(measurements);
+ mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection);
}
mClock = clock;
- Collection<GnssMeasurement> measurementCollection = Arrays.asList(measurements);
- mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection);
}
/**
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 7d5939c..81cc93d 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -264,7 +264,6 @@
*/
public static final int ENCODING_IEC61937 = 13;
/** Audio data format: DOLBY TRUEHD compressed
- * @hide
**/
public static final int ENCODING_DOLBY_TRUEHD = 14;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 2ea2e86..2c98e98 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -42,6 +42,7 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -384,8 +385,16 @@
public static final int WHITEBALANCE_AUTO = 0;
public static final int WHITEBALANCE_MANUAL = 1;
+ // Maximum size for checking file type signature (see image_type_recognition_lite.cc)
+ private static final int SIGNATURE_CHECK_SIZE = 5000;
+
private static final byte[] JPEG_SIGNATURE = new byte[] {(byte) 0xff, (byte) 0xd8, (byte) 0xff};
private static final int JPEG_SIGNATURE_SIZE = 3;
+ private static final String RAF_SIGNATURE = "FUJIFILMCCD-RAW";
+ private static final int RAF_SIGNATURE_SIZE = 15;
+ private static final int RAF_OFFSET_TO_JPEG_IMAGE_OFFSET = 84;
+ private static final int RAF_INFO_SIZE = 160;
+ private int mRafJpegOffset, mRafJpegLength, mRafCfaHeaderOffset, mRafCfaHeaderLength;
private static SimpleDateFormat sFormatter;
@@ -1034,6 +1043,9 @@
new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG)
};
+ // RAF file tag (See piex.cc line 372)
+ private static final ExifTag TAG_RAF_IMAGE_SIZE =
+ new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT);
// See JEITA CP-3451C Section 4.6.3: Exif-specific IFD.
// The following values are used for indicating pointers to the other Image File Directories.
@@ -1106,6 +1118,20 @@
private static final byte MARKER_COM = (byte) 0xfe;
private static final byte MARKER_EOI = (byte) 0xd9;
+ // Supported Image File Types
+ private static final int IMAGE_TYPE_UNKNOWN = 0;
+ private static final int IMAGE_TYPE_ARW = 1;
+ private static final int IMAGE_TYPE_CR2 = 2;
+ private static final int IMAGE_TYPE_DNG = 3;
+ private static final int IMAGE_TYPE_JPEG = 4;
+ private static final int IMAGE_TYPE_NEF = 5;
+ private static final int IMAGE_TYPE_NRW = 6;
+ private static final int IMAGE_TYPE_ORF = 7;
+ private static final int IMAGE_TYPE_PEF = 8;
+ private static final int IMAGE_TYPE_RAF = 9;
+ private static final int IMAGE_TYPE_RW2 = 10;
+ private static final int IMAGE_TYPE_SRW = 11;
+
static {
System.loadLibrary("media_jni");
nativeInitRaw();
@@ -1128,7 +1154,7 @@
private final AssetManager.AssetInputStream mAssetInputStream;
private final boolean mIsInputStream;
private boolean mIsRaw;
- private int mRawType;
+ private int mMimeType;
private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
private boolean mHasThumbnail;
@@ -1323,26 +1349,6 @@
}
/**
- * Returns the long array value of the specified tag. If there is no such tag
- * in the image file or the value cannot be parsed as an array of long, return null.
- *
- * @param tag the name of the tag.
- */
- public long[] getAttributeLongArray(String tag) {
- ExifAttribute exifAttribute = getExifAttribute(tag);
- if (exifAttribute == null) {
- return null;
- }
-
- try {
- return (long[]) exifAttribute.getValue(mExifByteOrder);
- } catch (NumberFormatException e) {
- Log.w(TAG, "Invalid value for " + tag, e);
- return null;
- }
- }
-
- /**
* Set the value of the specified tag.
*
* @param tag the name of the tag.
@@ -1524,13 +1530,24 @@
mAttributes[i] = new HashMap();
}
- // Process RAW input stream
if (HANDLE_RAW) {
- in = new BufferedInputStream(in, JPEG_SIGNATURE_SIZE);
+ // Check file type
+ in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE);
+ mMimeType = getMimeType((BufferedInputStream) in);
- if (!isJpegInputStream((BufferedInputStream) in)) {
- getRawAttributes(in);
- return;
+ switch (mMimeType) {
+ case IMAGE_TYPE_JPEG: {
+ getJpegAttributes(in, IFD_TIFF_HINT);
+ break;
+ }
+ case IMAGE_TYPE_RAF: {
+ getRafAttributes(in);
+ break;
+ }
+ default: {
+ getRawAttributes(in);
+ break;
+ }
}
} else {
if (mAssetInputStream != null) {
@@ -1544,16 +1561,20 @@
return;
}
} else {
- in = new BufferedInputStream(in, JPEG_SIGNATURE_SIZE);
- if (!isJpegInputStream((BufferedInputStream) in) && handleRawResult(
+ in.mark(JPEG_SIGNATURE_SIZE);
+ byte[] signatureBytes = new byte[JPEG_SIGNATURE_SIZE];
+ if (in.read(signatureBytes) != JPEG_SIGNATURE_SIZE) {
+ throw new EOFException();
+ }
+ in.reset();
+ if (!isJpegInputStream(signatureBytes) && handleRawResult(
nativeGetRawAttributesFromInputStream(in))) {
return;
}
}
+ // Process JPEG input stream
+ getJpegAttributes(in, IFD_TIFF_HINT);
}
-
- // Process JPEG input stream
- getJpegAttributes(in);
} catch (IOException e) {
// Ignore exceptions in order to keep the compatibility with the old versions of
// ExifInterface.
@@ -1569,15 +1590,13 @@
}
}
- private static boolean isJpegInputStream(BufferedInputStream in) throws IOException {
- in.mark(JPEG_SIGNATURE_SIZE);
- byte[] signatureBytes = new byte[JPEG_SIGNATURE_SIZE];
- if (in.read(signatureBytes) != JPEG_SIGNATURE_SIZE) {
- throw new EOFException();
+ private static boolean isJpegInputStream(byte[] signatureBytes) throws IOException {
+ for (int i = 0; i < JPEG_SIGNATURE_SIZE; i++) {
+ if (signatureBytes[i] != JPEG_SIGNATURE[i]) {
+ return false;
+ }
}
- boolean isJpeg = Arrays.equals(JPEG_SIGNATURE, signatureBytes);
- in.reset();
- return isJpeg;
+ return true;
}
private boolean handleRawResult(HashMap map) {
@@ -1899,8 +1918,32 @@
}
}
- // Loads EXIF attributes from a JPEG input stream.
- private void getJpegAttributes(InputStream inputStream) throws IOException {
+ // Checks the type of image file
+ private int getMimeType(BufferedInputStream in) throws IOException {
+ in.mark(SIGNATURE_CHECK_SIZE);
+ byte[] signatureBytes = new byte[SIGNATURE_CHECK_SIZE];
+ if (in.read(signatureBytes) != SIGNATURE_CHECK_SIZE) {
+ throw new EOFException();
+ }
+ in.reset();
+ if (isJpegInputStream(signatureBytes)) {
+ return IMAGE_TYPE_JPEG;
+ } else if (isRafInputStream(signatureBytes)) {
+ return IMAGE_TYPE_RAF;
+ }
+ return IMAGE_TYPE_UNKNOWN;
+ }
+
+ /**
+ * Loads EXIF attributes from a JPEG input stream.
+ *
+ * @param inputStream The input stream that starts with the JPEG data.
+ * @param imageTypes The image type from which to retrieve metadata. Use IFD_TIFF_HINT for
+ * primary image, IFD_PREVIEW_HINT for preview image, and
+ * IFD_THUMBNAIL_HINT for thumbnail image.
+ * @throws IOException If the data contains invalid JPEG markers, offsets, or length values.
+ */
+ private void getJpegAttributes(InputStream inputStream, int imageType) throws IOException {
// See JPEG File Interchange Format Specification, "JFIF Specification"
if (DEBUG) {
Log.d(TAG, "getJpegAttributes starting with: " + inputStream);
@@ -1971,7 +2014,7 @@
if (dataInputStream.read(bytes) != length) {
throw new IOException("Invalid exif");
}
- readExifSegment(bytes, bytesRead);
+ readExifSegment(bytes, bytesRead, imageType);
bytesRead += length;
length = 0;
break;
@@ -2006,9 +2049,9 @@
if (dataInputStream.skipBytes(1) != 1) {
throw new IOException("Invalid SOFx");
}
- mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong(
+ mAttributes[imageType].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong(
dataInputStream.readUnsignedShort(), mExifByteOrder));
- mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong(
+ mAttributes[imageType].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong(
dataInputStream.readUnsignedShort(), mExifByteOrder));
length -= 5;
break;
@@ -2030,7 +2073,9 @@
private void getRawAttributes(InputStream in) throws IOException {
int bytesRead = 0;
- byte[] exifBytes = new byte[in.available()];
+ int totalBytes = in.available();
+ byte[] exifBytes = new byte[totalBytes];
+ in.mark(in.available());
in.read(exifBytes);
ByteOrderAwarenessDataInputStream dataInputStream =
@@ -2042,23 +2087,126 @@
// Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
readImageFileDirectory(dataInputStream, IFD_PREVIEW_HINT);
+ // Check if the preview image data should be a primary image data.
+ // The 0th IFD (first to be parsed) is presumed to be a preview image data, with a SubIFD
+ // that is a primary image data.
+ // But if the 0th IFD does not have a SubIFD, then it must be a primary image data since
+ // a primary image data must exist, but a preview image data does not have to.
+ if (mAttributes[IFD_TIFF_HINT].isEmpty() && !mAttributes[IFD_PREVIEW_HINT].isEmpty()) {
+ mAttributes[IFD_TIFF_HINT] = mAttributes[IFD_PREVIEW_HINT];
+ mAttributes[IFD_PREVIEW_HINT] = new HashMap();
+ }
+
+ // Update TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH for primary image.
+ updatePrimaryImageSizeValues(in);
+
// Check if the preview image data should be a thumbnail image data.
- // In a RAW file, there may be a Preview image, which is smaller than a Primary image but
- // larger than a Thumbnail image. Normally, the Preview image can be considered a thumbnail
- // image if its size meets the requirements. Therefore, when a Thumbnail image has not yet
- // been found, we should check if the Preview image can be one.
+ // In a RAW file, there may be a preview image, which is smaller than a primary image but
+ // larger than a thumbnail image. Normally, the preview image can be considered a thumbnail
+ // image if its size meets the requirements. Therefore, when a thumbnail image has not yet
+ // been found, we should check if the preview image can be one.
if (!mAttributes[IFD_PREVIEW_HINT].isEmpty() && mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) {
+ // Update preview image size if necessary
+ retrieveJpegImageSize(in, IFD_PREVIEW_HINT);
+
if (isThumbnail(mAttributes[IFD_PREVIEW_HINT])) {
mAttributes[IFD_THUMBNAIL_HINT] = mAttributes[IFD_PREVIEW_HINT];
mAttributes[IFD_PREVIEW_HINT] = new HashMap();
}
}
-
// Process thumbnail.
- processThumbnail(dataInputStream, bytesRead, exifBytes.length);
+ processThumbnail(dataInputStream, 0, exifBytes.length);
+ }
- // Update TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH.
- updateImageSizeValues();
+ /**
+ * RAF files contains a JPEG and a CFA data.
+ * The JPEG contains two images, a preview and a thumbnail, while the CFA contains a RAW image.
+ * This method looks at the first 160 bytes to determine if this file is a RAF file.
+ * There is no official specification for RAF files from Fuji, but there is an online archive of
+ * image file specifications:
+ * http://fileformats.archiveteam.org/wiki/Fujifilm_RAF
+ */
+ private boolean isRafInputStream(byte[] signatureBytes) throws IOException {
+ byte[] rafSignatureBytes = RAF_SIGNATURE.getBytes();
+ for (int i = 0; i < RAF_SIGNATURE_SIZE; i++) {
+ if (signatureBytes[i] != rafSignatureBytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This method looks at the first 160 bytes of a RAF file to retrieve the offset and length
+ * values for the JPEG and CFA data.
+ * Using that data, it parses the JPEG data to retrieve the preview and thumbnail image data,
+ * then parses the CFA metadata to retrieve the primary image length/width values.
+ * For data format details, see http://fileformats.archiveteam.org/wiki/Fujifilm_RAF
+ */
+ private void getRafAttributes(InputStream in) throws IOException {
+ // Retrieve offset & length values
+ in.mark(RAF_INFO_SIZE);
+ in.skip(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET);
+ byte[] jpegOffsetBytes = new byte[4];
+ byte[] jpegLengthBytes = new byte[4];
+ byte[] cfaHeaderOffsetBytes = new byte[4];
+ byte[] cfaHeaderLengthBytes = new byte[4];
+ in.read(jpegOffsetBytes);
+ in.read(jpegLengthBytes);
+ in.read(cfaHeaderOffsetBytes);
+ in.read(cfaHeaderLengthBytes);
+ mRafJpegOffset = ByteBuffer.wrap(jpegOffsetBytes).getInt();
+ mRafJpegLength = ByteBuffer.wrap(jpegLengthBytes).getInt();
+ mRafCfaHeaderOffset = ByteBuffer.wrap(cfaHeaderOffsetBytes).getInt();
+ mRafCfaHeaderLength = ByteBuffer.wrap(cfaHeaderLengthBytes).getInt();
+ in.reset();
+
+ // Retrieve JPEG image metadata
+ in.mark(mRafJpegOffset + mRafJpegLength);
+ in.skip(mRafJpegOffset);
+ getJpegAttributes(in, IFD_PREVIEW_HINT);
+ in.reset();
+
+ // Skip to CFA header offset.
+ // A while loop is used because the skip method may not be able to skip the requested amount
+ // at once because the size of the buffer may be restricted.
+ int totalSkip = mRafCfaHeaderOffset;
+ while (totalSkip > 0) {
+ long skipped = in.skip(totalSkip);
+ totalSkip -= skipped;
+ }
+
+ // Retrieve primary image length/width values, if TAG_RAF_IMAGE_SIZE exists
+ byte[] exifBytes = new byte[mRafCfaHeaderLength];
+ int read = in.read(exifBytes);
+ ByteOrderAwarenessDataInputStream dataInputStream =
+ new ByteOrderAwarenessDataInputStream(exifBytes);
+ int numberOfDirectoryEntry = dataInputStream.readInt();
+ if (DEBUG) {
+ Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
+ }
+ // CFA stores some metadata about the RAW image. Since CFA uses proprietary tags, can only
+ // find and retrieve image size information tags, while skipping others.
+ // See piex.cc RafGetDimension()
+ for (int i = 0; i < numberOfDirectoryEntry; ++i) {
+ int tagNumber = dataInputStream.readUnsignedShort();
+ int numberOfBytes = dataInputStream.readUnsignedShort();
+ if (tagNumber == TAG_RAF_IMAGE_SIZE.number) {
+ int imageLength = dataInputStream.readShort();
+ int imageWidth = dataInputStream.readShort();
+ ExifAttribute imageLengthAttribute =
+ ExifAttribute.createUShort(imageLength, mExifByteOrder);
+ ExifAttribute imageWidthAttribute =
+ ExifAttribute.createUShort(imageWidth, mExifByteOrder);
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, imageLengthAttribute);
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, imageWidthAttribute);
+ if (DEBUG) {
+ Log.d(TAG, "Updated to length: " + imageLength + ", width: " + imageWidth);
+ }
+ return;
+ }
+ dataInputStream.skip(numberOfBytes);
+ }
}
// Stores a new JPEG image with EXIF attributes into a given output stream.
@@ -2160,7 +2308,8 @@
}
// Reads the given EXIF byte area and save its tag data into attributes.
- private void readExifSegment(byte[] exifBytes, int exifOffsetFromBeginning) throws IOException {
+ private void readExifSegment(byte[] exifBytes, int exifOffsetFromBeginning, int imageType)
+ throws IOException {
ByteOrderAwarenessDataInputStream dataInputStream =
new ByteOrderAwarenessDataInputStream(exifBytes);
@@ -2168,7 +2317,7 @@
parseTiffHeaders(dataInputStream, exifBytes.length);
// Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
- readImageFileDirectory(dataInputStream, IFD_TIFF_HINT);
+ readImageFileDirectory(dataInputStream, imageType);
// Process thumbnail.
processThumbnail(dataInputStream, exifOffsetFromBeginning, exifBytes.length);
@@ -2375,49 +2524,85 @@
}
}
- // Processes Thumbnail based on Compression Value
+ /**
+ * JPEG compressed images do not contain IMAGE_LENGTH & IMAGE_WIDTH tags.
+ * This value uses JpegInterchangeFormat(JPEG data offset) value, and calls getJpegAttributes()
+ * to locate SOF(Start of Frame) marker and update the image length & width values.
+ * See JEITA CP-3451C Table 5 and Section 4.8.1. B.
+ */
+ private void retrieveJpegImageSize(InputStream in, int imageType) throws IOException {
+ // Check if image already has IMAGE_LENGTH & IMAGE_WIDTH values
+ ExifAttribute imageLengthAttribute =
+ (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_LENGTH);
+ ExifAttribute imageWidthAttribute =
+ (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_WIDTH);
+
+ if (imageLengthAttribute == null || imageWidthAttribute == null) {
+ // Find if offset for JPEG data exists
+ ExifAttribute jpegInterchangeFormatAttribute =
+ (ExifAttribute) mAttributes[imageType].get(TAG_JPEG_INTERCHANGE_FORMAT);
+ if (jpegInterchangeFormatAttribute != null) {
+ int jpegInterchangeFormat =
+ jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
+
+ // Skip to the JPEG data offset
+ in.reset();
+ in.mark(in.available());
+ if (in.skip(jpegInterchangeFormat) != jpegInterchangeFormat) {
+ Log.d(TAG, "Invalid JPEG offset");
+ }
+
+ // Searches for SOF marker in JPEG data and updates IMAGE_LENGTH & IMAGE_WIDTH tags
+ getJpegAttributes(in, imageType);
+ }
+ }
+ }
+
+ // Processes thumbnail based on Compression Value
private void processThumbnail(ByteOrderAwarenessDataInputStream dataInputStream,
int exifOffsetFromBeginning, int exifBytesLength) throws IOException {
- if (mAttributes[IFD_THUMBNAIL_HINT].containsKey(TAG_COMPRESSION)) {
- ExifAttribute compressionAttribute =
- (ExifAttribute) mAttributes[IFD_THUMBNAIL_HINT].get(TAG_COMPRESSION);
+ HashMap thumbnailData = mAttributes[IFD_THUMBNAIL_HINT];
+ ExifAttribute compressionAttribute = (ExifAttribute) thumbnailData.get(TAG_COMPRESSION);
+ if (compressionAttribute != null) {
int compressionValue = compressionAttribute.getIntValue(mExifByteOrder);
switch (compressionValue) {
case DATA_UNCOMPRESSED: {
- // TODO: add implementation for reading Uncompressed Thumbnail Data (b/28156704)
+ // TODO: add implementation for reading uncompressed thumbnail data (b/28156704)
Log.d(TAG, "Uncompressed thumbnail data cannot be processed");
break;
}
case DATA_JPEG: {
- String jpegInterchangeFormatString =
- getAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
- String jpegInterchangeFormatLengthString =
- getAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
- if (jpegInterchangeFormatString != null
- && jpegInterchangeFormatLengthString != null) {
- try {
- int jpegInterchangeFormat =
- Integer.parseInt(jpegInterchangeFormatString);
- int jpegInterchangeFormatLength =
- Integer.parseInt(jpegInterchangeFormatLengthString);
- retrieveJPEGThumbnail(dataInputStream, jpegInterchangeFormat,
- jpegInterchangeFormatLength, exifOffsetFromBeginning,
- exifBytesLength);
- } catch (NumberFormatException e) {
- // Ignore corrupted format/formatLength values
- }
+ ExifAttribute jpegInterchangeFormatAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT);
+ ExifAttribute jpegInterchangeFormatLengthAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ if (jpegInterchangeFormatAttribute != null
+ && jpegInterchangeFormatLengthAttribute != null) {
+ int jpegInterchangeFormat =
+ jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
+ int jpegInterchangeFormatLength =
+ jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
+ retrieveJPEGThumbnail(dataInputStream, jpegInterchangeFormat,
+ jpegInterchangeFormatLength, exifOffsetFromBeginning,
+ exifBytesLength);
}
break;
}
case DATA_JPEG_COMPRESSED: {
- long[] stripOffsetsArray = getAttributeLongArray(TAG_STRIP_OFFSETS);
- long[] stripByteCountsArray = getAttributeLongArray(TAG_STRIP_BYTE_COUNTS);
- if (stripOffsetsArray != null && stripByteCountsArray != null) {
+ ExifAttribute stripOffsetsAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS);
+ ExifAttribute stripByteCountsAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_STRIP_BYTE_COUNTS);
+ if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) {
+ long[] stripOffsetsArray =
+ (long[]) stripOffsetsAttribute.getValue(mExifByteOrder);
+ long[] stripByteCountsArray =
+ (long[]) stripByteCountsAttribute.getValue(mExifByteOrder);
if (stripOffsetsArray.length == 1) {
int stripOffsetsSum = (int) Arrays.stream(stripOffsetsArray).sum();
- int stripByteCountSum = (int) Arrays.stream(stripByteCountsArray).sum();
+ int stripByteCountsSum = (int) Arrays.stream(stripByteCountsArray).sum();
retrieveJPEGThumbnail(dataInputStream, stripOffsetsSum,
- stripByteCountSum, exifOffsetFromBeginning,
+ stripByteCountsSum, exifOffsetFromBeginning,
exifBytesLength);
} else {
// TODO: implement method to read multiple strips (b/29737797)
@@ -2433,7 +2618,7 @@
}
}
- // Retrieves Thumbnail for JPEG Compression
+ // Retrieves thumbnail for JPEG Compression
private void retrieveJPEGThumbnail(ByteOrderAwarenessDataInputStream dataInputStream,
int thumbnailOffset, int thumbnailLength, int exifOffsetFromBeginning,
int exifBytesLength) throws IOException {
@@ -2442,18 +2627,20 @@
}
// The following code limits the size of thumbnail size not to overflow EXIF data area.
thumbnailLength = Math.min(thumbnailLength, exifBytesLength - thumbnailOffset);
+ // The following code changes the offset value for RAF files.
+ if (mMimeType == IMAGE_TYPE_RAF) {
+ exifOffsetFromBeginning += mRafJpegOffset;
+ }
if (thumbnailOffset > 0 && thumbnailLength > 0) {
mHasThumbnail = true;
mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
mThumbnailLength = thumbnailLength;
-
if (mFilename == null && mAssetInputStream == null && mSeekableFileDescriptor == null) {
// Save the thumbnail in memory if the input doesn't support reading again.
byte[] thumbnailBytes = new byte[thumbnailLength];
dataInputStream.seek(thumbnailOffset);
dataInputStream.readFully(thumbnailBytes);
mThumbnailBytes = thumbnailBytes;
-
if (DEBUG) {
Bitmap bitmap = BitmapFactory.decodeByteArray(
thumbnailBytes, 0, thumbnailBytes.length);
@@ -2483,14 +2670,22 @@
}
/**
- * Raw images often store extra pixels around the edges of the final image, which results in
- * larger values for TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH tags.
+ * If image is uncompressed, ImageWidth/Length tags are used to store size info.
+ * However, uncompressed images often store extra pixels around the edges of the final image,
+ * which results in larger values for TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH tags.
* This method corrects those tag values by checking first the values of TAG_DEFAULT_CROP_SIZE
- * and then TAG_PIXEL_X_DIMENSION & TAG_PIXEL_Y_DIMENSION.
- * See DNG Specification 1.4.0.0. Section 4 (DefaultCropSize) & JEITA CP-3451 p26.
+ * See DNG Specification 1.4.0.0. Section 4. (DefaultCropSize)
+ *
+ * If image is JPEG compressed, PixelXDimension/PixelYDimension tags are used for size info.
+ * However, an image may have padding at the right end or bottom end of the image to make sure
+ * that the values are multiples of 64. If so, the increased value will be saved in the
+ * SOF(Start of Frame). In order to assure that valid image size values are stored, this method
+ * checks TAG_PIXEL_X_DIMENSION & TAG_PIXEL_Y_DIMENSION and updates values if necessary.
+ * See JEITA CP-3451C Table 5 and Section 4.8.1. B.
* */
- private void updateImageSizeValues() throws IOException {
- // Checks for the NewSubfileType tag and returns if the image is not original resolution.
+ private void updatePrimaryImageSizeValues(InputStream in) throws IOException {
+ // Checks for the NewSubfileType tag and returns if the image is not original resolution,
+ // which means that it is not the primary imiage
ExifAttribute newSubfileTypeAttribute =
(ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_NEW_SUBFILE_TYPE);
if (newSubfileTypeAttribute != null) {
@@ -2501,13 +2696,17 @@
}
}
+ // Uncompressed image valid image size values
ExifAttribute defaultCropSizeAttribute =
(ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_DEFAULT_CROP_SIZE);
+ // Compressed image valid image size values
ExifAttribute pixelXDimAttribute =
(ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_X_DIMENSION);
ExifAttribute pixelYDimAttribute =
(ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_Y_DIMENSION);
+
if (defaultCropSizeAttribute != null) {
+ // Update for uncompressed image
ExifAttribute defaultCropSizeXAttribute, defaultCropSizeYAttribute;
if (defaultCropSizeAttribute.format == IFD_FORMAT_URATIONAL) {
Rational[] defaultCropSizeValue =
@@ -2526,9 +2725,15 @@
}
mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute);
mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute);
- } else if (pixelXDimAttribute != null && pixelYDimAttribute != null) {
- mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, pixelXDimAttribute);
- mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, pixelYDimAttribute);
+ } else {
+ // Update for JPEG image
+ if (pixelXDimAttribute != null && pixelYDimAttribute != null) {
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, pixelXDimAttribute);
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, pixelYDimAttribute);
+ } else {
+ // Update image size values from SOF marker if necessary
+ retrieveJpegImageSize(in, IFD_TIFF_HINT);
+ }
}
}
@@ -2582,9 +2787,9 @@
ExifAttribute.createULong(0, mExifByteOrder));
}
if (mHasThumbnail) {
- mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
+ mAttributes[IFD_THUMBNAIL_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
ExifAttribute.createULong(0, mExifByteOrder));
- mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
+ mAttributes[IFD_THUMBNAIL_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
ExifAttribute.createULong(mThumbnailLength, mExifByteOrder));
}
@@ -2612,7 +2817,7 @@
}
if (mHasThumbnail) {
int thumbnailOffset = position;
- mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
+ mAttributes[IFD_THUMBNAIL_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
position += mThumbnailLength;
@@ -2818,8 +3023,12 @@
}
public void seek(long byteCount) throws IOException {
- mPosition = 0L;
- reset();
+ if (mPosition > byteCount) {
+ mPosition = 0L;
+ reset();
+ } else {
+ byteCount -= mPosition;
+ }
if (skip(byteCount) != byteCount) {
throw new IOException("Couldn't seek up to the byteCount");
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 542dced..264944f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -133,9 +133,10 @@
<p class=note>
Note that on some devices the slice-height is advertised as 0. This could mean either that the
slice-height is the same as the frame height, or that the slice-height is the frame height
- aligned to some value (usually a power of 2). Unfortunately, there is no way to tell the actual
- slice height in this case. Furthermore, the vertical stride of the {@code U} plane in planar
- formats is also not specified or defined, though usually it is half of the slice height.
+ aligned to some value (usually a power of 2). Unfortunately, there is no standard and simple way
+ to tell the actual slice height in this case. Furthermore, the vertical stride of the {@code U}
+ plane in planar formats is also not specified or defined, though usually it is half of the slice
+ height.
<p>
The {@link MediaFormat#KEY_WIDTH} and {@link MediaFormat#KEY_HEIGHT} keys specify the size of the
video frames; however, for most encondings the video (picture) only occupies a portion of the
@@ -620,8 +621,9 @@
mode} will be automatically applied with one exception:
<p class=note>
Prior to the {@link android.os.Build.VERSION_CODES#M} release, software decoders may not
- have applied the rotation when being rendered onto a Surface. Unfortunately, there is no way to
- identify software decoders, or if they apply the rotation other than by trying it out.
+ have applied the rotation when being rendered onto a Surface. Unfortunately, there is no standard
+ and simple way to identify software decoders, or if they apply the rotation other than by trying
+ it out.
<p>
There are also some caveats.
<p class=note>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index d7a18d9..d74aa81 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -49,12 +49,18 @@
* <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td>required for <b>encoders</b>,
* optional for <b>decoders</b></td></tr>
* <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr>
- * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer (or Float)</td><td><b>encoder-only</b>,
+ * time-interval between key frames.
+ * Float support added in {@link android.os.Build.VERSION_CODES#N_MR1}</td></tr>
* <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
* <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
* <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
- * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
- * <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>video decoder rendering to a surface only</b></td></tr>
+ * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>encoder in surface-mode
+ * only</b>, optional</td></tr>
+ * <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>decoder rendering
+ * to a surface only</b>, optional</td></tr>
+ * <tr><td>{@link #KEY_TEMPORAL_LAYERING}</td><td>String</td><td><b>encoder only</b>, optional,
+ * temporal-layering schema</td></tr>
* </table>
* Specify both {@link #KEY_MAX_WIDTH} and {@link #KEY_MAX_HEIGHT} to enable
* adaptive playback (seamless resolution change) for a video decoder that
@@ -258,9 +264,20 @@
public static final String KEY_CAPTURE_RATE = "capture-rate";
/**
- * A key describing the frequency of I frames expressed in secs
- * between I frames.
- * The associated value is an integer.
+ * A key describing the frequency of key frames expressed in seconds between key frames.
+ * <p>
+ * This key is used by video encoders.
+ * A negative value means no key frames are requested after the first frame.
+ * A zero value means a stream containing all key frames is requested.
+ * <p class=note>
+ * Most video encoders will convert this value of the number of non-key-frames between
+ * key-frames, using the {@linkplain #KEY_FRAME_RATE frame rate} information; therefore,
+ * if the actual frame rate differs (e.g. input frames are dropped or the frame rate
+ * changes), the <strong>time interval</strong> between key frames will not be the
+ * configured value.
+ * <p>
+ * The associated value is an integer (or float since
+ * {@link android.os.Build.VERSION_CODES#N_MR1}).
*/
public static final String KEY_I_FRAME_INTERVAL = "i-frame-interval";
@@ -280,12 +297,18 @@
/**
* A key describing the temporal layering schema. This is an optional parameter
- * that applies only to video encoders. Use {@link MediaCodec#getInputFormat}
+ * that applies only to video encoders. Use {@link MediaCodec#getOutputFormat}
* after {@link MediaCodec#configure configure} to query if the encoder supports
- * the desired schema. Supported values are {@code webrtc.vp8.1-layer},
- * {@code webrtc.vp8.2-layer}, {@code webrtc.vp8.3-layer}, and {@code none}.
- * If the encoder does not support temporal layering, the input format will
- * not have an entry with this key.
+ * the desired schema. Supported values are {@code webrtc.vp8.N-layer},
+ * {@code android.generic.N}, {@code android.generic.N+M} and {@code none}, where
+ * {@code N} denotes the total number of non-bidirectional layers (which must be at least 1)
+ * and {@code M} denotes the total number of bidirectional layers (which must be non-negative).
+ * <p class=note>{@code android.generic.*} schemas have been added in {@link
+ * android.os.Build.VERSION_CODES#N_MR1}.
+ * <p>
+ * The encoder may support fewer temporal layers, in which case the output format
+ * will contain the configured schema. If the encoder does not support temporal
+ * layering, the output format will not have an entry with this key.
* The associated value is a string.
*/
public static final String KEY_TEMPORAL_LAYERING = "ts-schema";
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 92adfd9..30395b8 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -3494,7 +3494,7 @@
* @param extra an extra code, specific to the info. Typically
* implementation dependent.
* @return True if the method handled the info, false if it didn't.
- * Returning false, or not having an OnErrorListener at all, will
+ * Returning false, or not having an OnInfoListener at all, will
* cause the info to be discarded.
*/
boolean onInfo(MediaPlayer mp, int what, int extra);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 73485af..8971ac5 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -952,7 +952,7 @@
/* Do not change these values without updating their counterparts
* in include/media/mediarecorder.h!
*/
- /** Unspecified media recorder error.
+ /** Unspecified media recorder info.
* @see android.media.MediaRecorder.OnInfoListener
*/
public static final int MEDIA_RECORDER_INFO_UNKNOWN = 1;
@@ -1035,22 +1035,22 @@
/**
- * Interface definition for a callback to be invoked when an error
- * occurs while recording.
+ * Interface definition of a callback to be invoked to communicate some
+ * info and/or warning about the recording.
*/
public interface OnInfoListener
{
/**
- * Called when an error occurs while recording.
+ * Called to indicate an info or a warning during recording.
*
- * @param mr the MediaRecorder that encountered the error
- * @param what the type of error that has occurred:
+ * @param mr the MediaRecorder the info pertains to
+ * @param what the type of info or warning that has occurred
* <ul>
* <li>{@link #MEDIA_RECORDER_INFO_UNKNOWN}
* <li>{@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
* <li>{@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
* </ul>
- * @param extra an extra code, specific to the error type
+ * @param extra an extra code, specific to the info type
*/
void onInfo(MediaRecorder mr, int what, int extra);
}
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 0f7dc9a..b262d97 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -181,10 +181,15 @@
* @return
*/
boolean isRestricted_sync() {
+ // check app ops
+ if (mHasAppOpsPlayAudio) {
+ return false;
+ }
+ // check bypass flag
if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
return false;
}
- return !mHasAppOpsPlayAudio;
+ return true;
}
// Abstract methods a subclass needs to implement
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 5ede1d5..9fafda4 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -505,27 +505,31 @@
}
private boolean isRestricted() {
- IAudioService service = getService();
- boolean cameraSoundForced = false;
-
- try {
- cameraSoundForced = service.isCameraSoundForced();
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot access AudioService in isRestricted()");
- }
-
- if (cameraSoundForced &&
- ((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0)
-// FIXME: should also check usage when set properly by camera app
-// && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- ) {
+ // check app ops
+ if (mHasAppOpsPlayAudio) {
return false;
}
-
+ // check bypass flag
if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
return false;
}
- return !mHasAppOpsPlayAudio;
+ // check force audibility flag and camera restriction
+ if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0) {
+// FIXME: should also check usage when set properly by camera app
+// && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ boolean cameraSoundForced = false;
+ try {
+ cameraSoundForced = getService().isCameraSoundForced();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot access AudioService in isRestricted()");
+ } catch (NullPointerException e) {
+ Log.e(TAG, "Null AudioService in isRestricted()");
+ }
+ if (cameraSoundForced) {
+ return false;
+ }
+ }
+ return true;
}
private void updateAppOpsPlayAudio() {
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index df0961b..d5296ae 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -15,6 +15,7 @@
*/
package android.media.soundtrigger;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -243,27 +244,29 @@
boolean allowMultipleTriggers =
(recognitionFlags & RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0;
+ int status = STATUS_OK;
try {
- mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId),
+ status = mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId),
mRecognitionCallback, new RecognitionConfig(captureTriggerAudio,
allowMultipleTriggers, null, null));
} catch (RemoteException e) {
return false;
}
- return true;
+ return status == STATUS_OK;
}
/**
* Stops recognition for the associated model.
*/
public boolean stopRecognition() {
+ int status = STATUS_OK;
try {
- mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId),
+ status = mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId),
mRecognitionCallback);
} catch (RemoteException e) {
return false;
}
- return true;
+ return status == STATUS_OK;
}
/**
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index ecc4a0d..aee9d38e 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -776,8 +776,8 @@
mSurface = null;
mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
@Override
- protected void updateWindow(boolean force, boolean redrawNeeded) {
- super.updateWindow(force, redrawNeeded);
+ protected void updateWindow() {
+ super.updateWindow();
relayoutSessionOverlayView();
}};
// The surface view's content should be treated as secure all the time.
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index d07942b..2ab7e39 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -26,6 +26,7 @@
#include "JNIHelp.h"
#include <binder/MemoryDealer.h>
+#include <drm/drm_framework_common.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -159,4 +160,8 @@
return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid());
}
+sp<DecryptHandle> JMediaDataSource::DrmInitialization(const char * /* mime */) {
+ return NULL;
+}
+
} // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 378baf4..39405d2 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -47,6 +47,7 @@
virtual void close();
virtual uint32_t getFlags();
virtual String8 toString();
+ virtual sp<DecryptHandle> DrmInitialization(const char *mime);
private:
// Protect all member variables with mLock because this object will be
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 69bcbc2..b224510 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -11,6 +11,7 @@
<application
android:name=".DocumentsApplication"
android:label="@string/app_label"
+ android:icon="@mipmap/ic_app_icon"
android:supportsRtl="true">
<activity
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index 9671813..114fd09 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -77,7 +77,7 @@
android:duplicateParentState="true">
<ImageView
- android:id="@+id/unmount_icon"
+ android:id="@+id/eject_icon"
android:layout_width="@dimen/root_icon_size"
android:layout_height="match_parent"
android:scaleType="centerInside"
diff --git a/packages/DocumentsUI/res/mipmap-hdpi/ic_app_icon.png b/packages/DocumentsUI/res/mipmap-hdpi/ic_app_icon.png
new file mode 100644
index 0000000..cd3a037
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-hdpi/ic_app_icon.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-mdpi/ic_app_icon.png b/packages/DocumentsUI/res/mipmap-mdpi/ic_app_icon.png
new file mode 100644
index 0000000..8d08e9b
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-mdpi/ic_app_icon.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-xhdpi/ic_app_icon.png b/packages/DocumentsUI/res/mipmap-xhdpi/ic_app_icon.png
new file mode 100644
index 0000000..f3bacb7
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-xhdpi/ic_app_icon.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-xxhdpi/ic_app_icon.png b/packages/DocumentsUI/res/mipmap-xxhdpi/ic_app_icon.png
new file mode 100644
index 0000000..5156171
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-xxhdpi/ic_app_icon.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_app_icon.png b/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_app_icon.png
new file mode 100644
index 0000000..6dc2f76
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_app_icon.png
Binary files differ
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index c1a5b39..bc00af7 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Kan nie die geselekteerde lêers in hierdie ligging plak nie."</string>
<string name="menu_rename" msgid="7678802479104285353">"Hernoem"</string>
<string name="rename_error" msgid="4203041674883412606">"Kon nie dokument hernoem nie"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Maak los"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids?"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index ad4c747..c1689fb 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"የተመረጡትን ፋይሎች ወደዚህ አካባቢ መለጠፍ አይቻልም።"</string>
<string name="menu_rename" msgid="7678802479104285353">"እንደገና ሰይም"</string>
<string name="rename_error" msgid="4203041674883412606">"ሰነዱን ዳግም መሰየም አልተሳካም"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"አስወጣ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> በ<xliff:g id="STORAGE"><i>^3</i></xliff:g> ላይ የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መደረሻ ይሰጠው?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጠው?"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 7a7485a..620143b 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -139,8 +139,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"يتعذر لصق الملفات المحددة في هذا الموقع."</string>
<string name="menu_rename" msgid="7678802479104285353">"إعادة تسمية"</string>
<string name="rename_error" msgid="4203041674883412606">"أخفقت إعادة تسمية المستند."</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"إخراج"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"تم تحويل بعض الملفات"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"هل تريد منح التطبيق <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى الدليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> على <xliff:g id="STORAGE"><i>^3</i></xliff:g>؟"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"هل تريد تمكين <xliff:g id="APPNAME"><b>^1</b></xliff:g> من الدخول إلى دليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>؟"</string>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index d2ff87b..988697c 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Seçilmiş faylları bu məkana yerləşdirmək olmaz."</string>
<string name="menu_rename" msgid="7678802479104285353">"Adını dəyişdirin"</string>
<string name="rename_error" msgid="4203041674883412606">"Sənəd adını dəyişmək uğursuz oldu"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Çıxarın"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bəzi fayllar konvertasiya edilib"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> yaddaşında <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 18e2a49..d38a431 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -118,8 +118,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Izabrane datoteke ne mogu da se nalepe na ovoj lokaciji."</string>
<string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
<string name="rename_error" msgid="4203041674883412606">"Preimenovanje dokumenta nije uspelo"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Izbaci"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li da aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobrite pristup direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na memorijskom prostoru <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite da dozvolite da <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-be-rBY/strings.xml b/packages/DocumentsUI/res/values-be-rBY/strings.xml
index 08bd4b1..be6988f 100644
--- a/packages/DocumentsUI/res/values-be-rBY/strings.xml
+++ b/packages/DocumentsUI/res/values-be-rBY/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Немагчыма ўставіць выбраныя файлы ў гэта месца."</string>
<string name="menu_rename" msgid="7678802479104285353">"Перайменаваць"</string>
<string name="rename_error" msgid="4203041674883412606">"Не атрымалася перайменаваць дакумент"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Выняць"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некаторыя файлы былі сканвертаваныя"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> у <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да каталога <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 940642d..c35075e 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Избраните файлове не могат да се поставят на това място."</string>
<string name="menu_rename" msgid="7678802479104285353">"Преименуване"</string>
<string name="rename_error" msgid="4203041674883412606">"Преименуването на документа не бе успешно"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Изваждане"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ в/ъв <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index e7e44ba..334a7ef7 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"এই স্থানে নির্বাচিত ফাইলগুলি আটকানো যাবে না।"</string>
<string name="menu_rename" msgid="7678802479104285353">"পুনঃনামকরণ"</string>
<string name="rename_error" msgid="4203041674883412606">"দস্তাবেজের পুনঃনামকরণ ব্যর্থ হয়েছে৷"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"সরিয়ে দিন"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"কিছু ফাইল রূপান্তরিত হয়েছে"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="STORAGE"><i>^3</i></xliff:g> এ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার মঞ্জুরি দিতে চান?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার অনুমতি দেবেন?"</string>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 7a99445..7bdb458 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -118,8 +118,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Odabrani fajlovi se ne mogu zalijepiti na ovu lokaciju."</string>
<string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
<string name="rename_error" msgid="4203041674883412606">"Nije uspjelo preimenovanje dokumenta"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Izbaci"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Omogućiti <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index d95ad7c..01a037f 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"No s\'han pogut enganxar els fitxers seleccionats en aquesta ubicació."</string>
<string name="menu_rename" msgid="7678802479104285353">"Canvia el nom"</string>
<string name="rename_error" msgid="4203041674883412606">"No s\'ha pogut canviar el nom del document"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Expulsa"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de l\'emmagatzematge <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index ce5e4ed2..8a0d0bf 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Vybrané soubory nelze vložit do tohoto umístění."</string>
<string name="menu_rename" msgid="7678802479104285353">"Přejmenovat"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokument se nepodařilo přejmenovat."</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Odpojit"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložišti <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index d3120f8..98117cb 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"De valgte filer kan ikke indsættes på denne placering."</string>
<string name="menu_rename" msgid="7678802479104285353">"Omdøb"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokumentet kunne ikke omdøbes"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Skub ud"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til mappen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til indekset <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index bd3cc77..9a7cd85 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Die ausgewählten Dateien können an diesem Ort nicht eingefügt werden."</string>
<string name="menu_rename" msgid="7678802479104285353">"Umbenennen"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokument konnte nicht umbenannt werden"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Auswerfen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> auf <xliff:g id="STORAGE"><i>^3</i></xliff:g> geben?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> geben?"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index e435a9e..39f0f47 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Δεν είναι δυνατή η επικόλληση των επιλεγμένων αρχείων σε αυτήν την τοποθεσία."</string>
<string name="menu_rename" msgid="7678802479104285353">"Μετονομασία"</string>
<string name="rename_error" msgid="4203041674883412606">"Αποτυχία μετονομασίας εγγράφου"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Εξαγωγή"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Να εκχωρηθεί στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> πρόσβαση στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^3</i></xliff:g>;"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Εκχώρηση πρόσβασης στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>;"</string>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 2a53a11..a871ac0 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Cannot paste the selected files in this location."</string>
<string name="menu_rename" msgid="7678802479104285353">"rename"</string>
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Eject"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 2a53a11..a871ac0 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Cannot paste the selected files in this location."</string>
<string name="menu_rename" msgid="7678802479104285353">"rename"</string>
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Eject"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 2a53a11..a871ac0 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Cannot paste the selected files in this location."</string>
<string name="menu_rename" msgid="7678802479104285353">"rename"</string>
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Eject"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 02dbe6b..fb4d13c 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"No se pueden pegar los archivos seleccionados en esta ubicación."</string>
<string name="menu_rename" msgid="7678802479104285353">"Cambiar nombre"</string>
<string name="rename_error" msgid="4203041674883412606">"No se pudo cambiar el nombre del documento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Expulsar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"¿Otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> en <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Quieres otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 42aaf88..41ace13 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Los archivos seleccionados no se pueden pegar en esta ubicación."</string>
<string name="menu_rename" msgid="7678802479104285353">"Cambiar nombre"</string>
<string name="rename_error" msgid="4203041674883412606">"Error al cambiar el nombre del documento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Expulsar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> (<xliff:g id="STORAGE"><i>^3</i></xliff:g>)?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 7c28d2d..31a6726 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Valitud faile ei saa sellesse asukohta kleepida."</string>
<string name="menu_rename" msgid="7678802479104285353">"Nimeta ümber"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokumendi ümbernimetamine ebaõnnestus"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Eemalda"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Mõned failid teisendati"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> salvestusruumis <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index e824aab..8810f99 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Ezin dira itsatsi hautatutako fitxategiak kokapen honetan."</string>
<string name="menu_rename" msgid="7678802479104285353">"Aldatu izena"</string>
<string name="rename_error" msgid="4203041674883412606">"Ezin izan zaio aldatu izena dokumentuari"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Atera"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="STORAGE"><i>^3</i></xliff:g> unitateko <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktorioa atzitzeko baimena eman nahi diozu?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktoriorako sarbidea eman nahi diozu?"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 82db43b..39074e0 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"نمیتوان فایلهای انتخابی را در این مکان جایگذاری کرد."</string>
<string name="menu_rename" msgid="7678802479104285353">"تغییر نام"</string>
<string name="rename_error" msgid="4203041674883412606">"نام سند تغییر نکرد"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"بیرون راندن"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"بعضی از فایلها تبدیل شدند"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه داده شود به فهرست راهنمای <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> در <xliff:g id="STORAGE"><i>^3</i></xliff:g> دسترسی داشته باشد؟"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه دسترسی به دایرکتوری <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> داده شود؟"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 4fe09e7..cc87026 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Valittuja tiedostoja ei voi liittää tähän sijaintiin."</string>
<string name="menu_rename" msgid="7678802479104285353">"Nimeä uudelleen"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokumentin nimen muuttaminen epäonnistui."</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Poista"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^3</i></xliff:g> olevan hakemiston <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> käyttöoikeus?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Saako <xliff:g id="APPNAME"><b>^1</b></xliff:g> käyttää hakemistoa <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 529276d..acac67a2 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Impossible de coller les fichiers sélectionnés à cet endroit."</string>
<string name="menu_rename" msgid="7678802479104285353">"Renommer"</string>
<string name="rename_error" msgid="4203041674883412606">"Impossible de renommer le document"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Éjecter"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sur <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 2fbf03b..9a11333 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Impossible de coller les fichiers sélectionnés à cet endroit."</string>
<string name="menu_rename" msgid="7678802479104285353">"Renommer"</string>
<string name="rename_error" msgid="4203041674883412606">"Échec du changement de nom du document."</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Éjecter"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" sur <xliff:g id="STORAGE"><i>^3</i></xliff:g> ?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" ?"</string>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 80e1789..645de56 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Non se poden pegar os ficheiros seleccionados nesta localización."</string>
<string name="menu_rename" msgid="7678802479104285353">"Cambiar nome"</string>
<string name="rename_error" msgid="4203041674883412606">"Non se puido cambiar o nome do documento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Expulsar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Queres outorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no almacenamento de <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index dd14d1d..7fa1b24 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"આ સ્થાનમાં પસંદ કરેલ ફાઇલો પેસ્ટ કરી શકાતી નથી."</string>
<string name="menu_rename" msgid="7678802479104285353">"નામ બદલો"</string>
<string name="rename_error" msgid="4203041674883412606">"દસ્તાવેજનું નામ બદલવામાં નિષ્ફળ થયાં"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"બહાર કાઢો"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"કેટલીક ફાઇલો રૂપાંતરિત કરી હતી"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^3</i></xliff:g> પર <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index ca3d377..da69875 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"चयनित फ़ाइलों को इस स्थान में नहीं चिपकाया जा सकता."</string>
<string name="menu_rename" msgid="7678802479104285353">"नाम बदलें"</string>
<string name="rename_error" msgid="4203041674883412606">"दस्तावेज़ का नाम बदलना विफल रहा"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"निकालें"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"कुछ फ़ाइलें रूपांतरित हो गई थीं"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^3</i></xliff:g> पर <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस दें?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस प्रदान करें?"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 2e589f1..030fedb 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -118,8 +118,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Nije moguće zalijepiti odabrane datoteke na ovu lokaciju."</string>
<string name="menu_rename" msgid="7678802479104285353">"Promijeni naziv"</string>
<string name="rename_error" msgid="4203041674883412606">"Naziv dokumenta nije promijenjen"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Izbaci"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke su datoteke konvertirane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na pohrani <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti da pristupa direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 85236b1..2224592 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"A kijelölt fájlokat nem lehet beilleszteni erre a helyre."</string>
<string name="menu_rename" msgid="7678802479104285353">"Átnevezés"</string>
<string name="rename_error" msgid="4203041674883412606">"Nem sikerült átnevezni a dokumentumot"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Kiadás"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Egyes fájlokat konvertált a rendszer"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz itt: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> alkalmazásnak a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz?"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 6aea267..5d63784 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Հնարավոր չէ տեղադրել ընտրված ֆայլերը այս տեղադրությունում:"</string>
<string name="menu_rename" msgid="7678802479104285353">"Վերանվանել"</string>
<string name="rename_error" msgid="4203041674883412606">"Չհաջողվեց վերանվանել փաստաթուղթը"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Անջատել"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ի <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index df699d3..2e8b0ea 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Tidak dapat menempel file yang dipilih di lokasi ini."</string>
<string name="menu_rename" msgid="7678802479104285353">"Ganti nama"</string>
<string name="rename_error" msgid="4203041674883412606">"Gagal mengganti nama dokumen"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Keluarkan"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index e891c41..0cb8387 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Ekki er hægt að vista valdar skrár á þessum stað."</string>
<string name="menu_rename" msgid="7678802479104285353">"Endurnefna"</string>
<string name="rename_error" msgid="4203041674883412606">"Ekki tókst að endurnefna skjalið"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Fjarlægja"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> á <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Viltu veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index dcd332a..eb06d5f 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Impossibile incollare i file selezionati in questa posizione."</string>
<string name="menu_rename" msgid="7678802479104285353">"Rinomina"</string>
<string name="rename_error" msgid="4203041674883412606">"Ridenominazione documento non riuscita"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Espelli"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> su <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 9115413..2d81be7 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"לא ניתן להדביק את הקבצים הנבחרים במיקום הזה."</string>
<string name="menu_rename" msgid="7678802479104285353">"שנה שם"</string>
<string name="rename_error" msgid="4203041674883412606">"ניסיון שינוי שם המסמך נכשל"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"הוצא"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לספריה <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> באחסון <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה אל ספריית <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 5e1831a2..200202f 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"選択したファイルをこの場所に貼り付けることはできません。"</string>
<string name="menu_rename" msgid="7678802479104285353">"名前を変更"</string>
<string name="rename_error" msgid="4203041674883412606">"ドキュメントの名前を変更できませんでした"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"取り外し"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"「<xliff:g id="STORAGE"><i>^3</i></xliff:g>」の「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリに「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」へのアクセスを許可しますか?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」アプリに「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリへのアクセスを許可しますか?"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index a2ec157..c2e6e22 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ამ მდებარეობაში შერჩეული ფაილების ჩასმა შეუძლებელია."</string>
<string name="menu_rename" msgid="7678802479104285353">"გადარქმევა"</string>
<string name="rename_error" msgid="4203041674883412606">"დოკუმენტის გადარქმევა ვერ მოხერხდა"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"გამოღება"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ის დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 08bf2d6..d2b89ea 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Таңдалған файлдарды бұл орынға қою мүмкін емес."</string>
<string name="menu_rename" msgid="7678802479104285353">"Атын өзгерту"</string>
<string name="rename_error" msgid="4203041674883412606">"Құжат қайта аталмады"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Шығару"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="STORAGE"><i>^3</i></xliff:g> қоймасындағы <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына өтуге рұқсат беру керек пе?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына кіруге рұқсат беру керек пе?"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 86a9c57..f618c1a 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"មិនអាចបិទភ្ជាប់ឯកសារដែលបានជ្រើសនៅក្នុងទីតាំងនេះបានទេ។"</string>
<string name="menu_rename" msgid="7678802479104285353">"ប្ដូរឈ្មោះ"</string>
<string name="rename_error" msgid="4203041674883412606">"បានបរាជ័យក្នុងការប្តូរឈ្មោះឯកសារ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"ដកចេញ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ឯកសារមួយចំនួនត្រូវបានបម្លែង"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> នៅលើ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ឬ?"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 0ae7558..0679776 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ಈ ಸ್ಥಳದಲ್ಲಿ ಆಯ್ಕೆಮಾಡಿದ ಫೈಲ್ಗಳನ್ನು ಅಂಟಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="menu_rename" msgid="7678802479104285353">"ಮರುಹೆಸರಿಸು"</string>
<string name="rename_error" msgid="4203041674883412606">"ಡಾಕ್ಯುಮೆಂಟ್ ಮರುಹೆಸರಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"ಎಜೆಕ್ಟ್"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ಕೆಲವು ಫೈಲ್ಗಳನ್ನು ಪರಿವರ್ತಿಸಲಾಗಿದೆ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> ರಲ್ಲಿ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿಗೆ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಪ್ರವೇಶ ನೀಡುವುದೇ?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g><xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿ ಪ್ರವೇಶಿಸಲು ಅನುಮತಿಸುವುದೇ?"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index ada80f4..ffb1363 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"선택한 파일을 이 위치에 붙여넣을 수 없습니다."</string>
<string name="menu_rename" msgid="7678802479104285353">"이름 바꾸기"</string>
<string name="rename_error" msgid="4203041674883412606">"문서 이름을 변경하지 못했습니다."</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"꺼내기"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"일부 파일이 변환되었습니다."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="STORAGE"><i>^3</i></xliff:g>에서 <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index 339183b50..9d5d475 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Тандалган файлдарды бул жерге чаптоого мүмкүн эмес."</string>
<string name="menu_rename" msgid="7678802479104285353">"Аталышын өзгөртүү"</string>
<string name="rename_error" msgid="4203041674883412606">"Документтин аталышы өзгөртүлбөй калды"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Чыгаруу"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^3</i></xliff:g> түзмөгүндөгү <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> папканы пайдалануу мүмкүнчүлүгү берилсинби?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогун пайдалануу мүмкүнчүлүгү берилсинби?"</string>
diff --git a/packages/DocumentsUI/res/values-ldrtl/config.xml b/packages/DocumentsUI/res/values-ldrtl/config.xml
deleted file mode 100644
index 22f8131..0000000
--- a/packages/DocumentsUI/res/values-ldrtl/config.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<resources>
- <bool name="list_divider_inset_left">false</bool>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 732bf2e..0f66f55 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ບໍ່ສາມາດແປະໄຟລ໌ເລືອກໄວ້ຢູ່ໃນທີ່ຕັ້ງນີ້ໄດ້."</string>
<string name="menu_rename" msgid="7678802479104285353">"ປ່ຽນຊື່"</string>
<string name="rename_error" msgid="4203041674883412606">"ປ່ຽນຊື່ເອກະສານບໍ່ສຳເລັດ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"ຖອດອອກ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ປ່ຽນແປງບາງໄຟລ໌ແລ້ວ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ອະນຸຍາດສິດເຂົ້າເຖິງໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເພື່ອເຂົ້າໄດເຣກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ຢູ່ <xliff:g id="STORAGE"><i>^3</i></xliff:g> ບໍ?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ອະນຸມັດ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ໃຫ້ເຂົ້າຫາໄດເຣັກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ບໍ?"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index e3fe8a1..02ee8f6 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Nepavyko įklijuoti pasirinktų failų šioje vietoje."</string>
<string name="menu_rename" msgid="7678802479104285353">"Pervardyti"</string>
<string name="rename_error" msgid="4203041674883412606">"Nepavyko pervardyti dokumento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Pašalinti"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 587224d..b4ae3fc 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -118,8 +118,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Atlasītos failus šeit nevar ielīmēt."</string>
<string name="menu_rename" msgid="7678802479104285353">"Pārdēvēt"</string>
<string name="rename_error" msgid="4203041674883412606">"Neizdevās pārdēvēt dokumentu"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Noņemt"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> šajā krātuvē: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vai piešķirt lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļuvi direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 277aaf1..9df2aad 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Не може да ги залепи избраните датотеки на локацијава."</string>
<string name="menu_rename" msgid="7678802479104285353">"Преименувај"</string>
<string name="rename_error" msgid="4203041674883412606">"Не успеа да се преименува документот"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Извади"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некои датотеки беа конвертирани"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index cd62d97..8c3b885 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"തിരഞ്ഞെടുത്ത ഫയലുകൾ ഈ ലൊക്കേഷനിൽ ഒട്ടിക്കാനാകുന്നില്ല."</string>
<string name="menu_rename" msgid="7678802479104285353">"പേരുമാറ്റുക"</string>
<string name="rename_error" msgid="4203041674883412606">"ഡോക്യുമെന്റിന്റെ പേരുമാറ്റുന്നത് പരാജയപ്പെട്ടു"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"ഒഴിവാക്കുക"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ചില ഫയലുകൾ പരിവർത്തനം ചെയ്യപ്പെട്ടു"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> സ്റ്റോറേജിലെ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്റ്ററിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്ടറിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 115b140..234e1a9 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Энэ байршилд сонгосон файлыг байршуулах боломжгүй байна."</string>
<string name="menu_rename" msgid="7678802479104285353">"Нэр өөрчлөх"</string>
<string name="rename_error" msgid="4203041674883412606">"Баримт бичгийн нэрийн өөрчилж чадсангүй"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Салгах"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g>-д байгаа <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандахыг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д зөвшөөрөх үү?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандах эрхийг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д олгох уу?"</string>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index f386ea8..e204c46 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"या स्थानामध्ये निवडलेल्या फायली पेस्ट करू शकत नाही."</string>
<string name="menu_rename" msgid="7678802479104285353">"पुनर्नामित करा"</string>
<string name="rename_error" msgid="4203041674883412606">"दस्तऐवज पुनर्नामित करण्यात अयशस्वी झाले"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"बाहेर काढा"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> वर <xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकेवर प्रवेशाची मंजूरी द्यायची?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकमध्ये प्रवेश मंजूर करायचा?"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index e5f161f..a16fa4c 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Tidak boleh menampalkan fail yang dipilih dalam lokasi ini."</string>
<string name="menu_rename" msgid="7678802479104285353">"Namakan semula"</string>
<string name="rename_error" msgid="4203041674883412606">"Gagal menamakan semula dokumen"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Keluarkan"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index e7fa24a..fef5e87 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ဤနေရာတွင် ရွေးချယ်ထားသည့် ဖိုင်များကို ကူးထည့်၍မရပါ။"</string>
<string name="menu_rename" msgid="7678802479104285353">"အမည်ပြောင်းရန်"</string>
<string name="rename_error" msgid="4203041674883412606">"စာရွက်စာတမ်းကို အမည်ပြောင်းခြင်း မအောင်မြင်ပါ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"ထုတ်မည်"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"အချို့ဖိုင်များကို ပြောင်းလဲထားသည်"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ကို <xliff:g id="STORAGE"><i>^3</i></xliff:g> ရှိ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> လမ်းညွှန်အား အသုံးပြုခွင့်ပေးမလား။"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> အား <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> စာရင်းကို အသုံးပြုခွင့်ပေးမလား။"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 867e41f..d3b1996 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Kan ikke lime inn de valgte filene her."</string>
<string name="menu_rename" msgid="7678802479104285353">"Gi nytt navn"</string>
<string name="rename_error" msgid="4203041674883412606">"Kunne ikke gi dokumentet nytt navn"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Løs ut"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen?"</string>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 2c45b70..ab8f8b1 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"यो स्थानमा चयन गरिएका फाइलहरू टाँस्न सकिँदैन।"</string>
<string name="menu_rename" msgid="7678802479104285353">"पुन: नामाकरण गर्नुहोस्"</string>
<string name="rename_error" msgid="4203041674883412606">"कागजात पुन: नामाकरण गर्न असफल भयो"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"निकाल्नुहोस्"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"केही फाइलहरू परिवर्तन गरिएका थिए"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^3</i></xliff:g> मा भएको <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामा पहुँच गर्न अनुमति दिने हो?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामाथि पहुँच गर्न अनुमति प्रदान गर्ने हो?"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 9d4176a..6eb9aac 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Kan de geselecteerde bestanden niet plakken op deze locatie."</string>
<string name="menu_rename" msgid="7678802479104285353">"Naam wijzigen"</string>
<string name="rename_error" msgid="4203041674883412606">"Kan naam van document niet wijzigen"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Uitwerpen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige bestanden zijn geconverteerd"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 2dcd605..f53cccf 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ਇਸ ਸਥਾਨ ਵਿੱਚ ਚੁਣੀਆਂ ਗਈਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਪੇਸਟ ਨਹੀਂ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="menu_rename" msgid="7678802479104285353">"ਮੁੜ-ਨਾਮਕਰਨ ਕਰੋ"</string>
<string name="rename_error" msgid="4203041674883412606">"ਦਸਤਾਵੇਜ਼ ਦਾ ਮੁੜ-ਨਾਮਕਰਨ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"ਬਾਹਰ ਕੱਢੋ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ਕੁਝ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^3</i></xliff:g> \'ਤੇ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 08f8ea0..33baba9 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Nie można wkleić wybranych plików w tej lokalizacji."</string>
<string name="menu_rename" msgid="7678802479104285353">"Zmień nazwę"</string>
<string name="rename_error" msgid="4203041674883412606">"Nie udało się zmienić nazwy dokumentu"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Odłącz"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> w pamięci masowej <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Przyznać aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index d60e5f5..718d70f 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Não é possível colar os arquivos selecionados neste local."</string>
<string name="menu_rename" msgid="7678802479104285353">"Renomear"</string>
<string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Ejetar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> para <xliff:g id="APPNAME"><b>^1</b></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 32f2079..e382def 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Não é possível colar os ficheiros selecionados nesta localização."</string>
<string name="menu_rename" msgid="7678802479104285353">"Mudar o nome"</string>
<string name="rename_error" msgid="4203041674883412606">"Falha ao mudar o nome do documento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Ejetar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no(a) <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index d60e5f5..718d70f 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Não é possível colar os arquivos selecionados neste local."</string>
<string name="menu_rename" msgid="7678802479104285353">"Renomear"</string>
<string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Ejetar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> para <xliff:g id="APPNAME"><b>^1</b></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 6bcbdee..8bf3880 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -118,8 +118,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Fișierele selectate nu au putut fi inserate în această locație."</string>
<string name="menu_rename" msgid="7678802479104285353">"Redenumiți"</string>
<string name="rename_error" msgid="4203041674883412606">"Documentul nu a putut fi redenumit"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Scoateți"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> accesul la directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de pe <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să acceseze directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index c4e8ae4..eb7278e 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Не удается вставить сюда выбранные файлы"</string>
<string name="menu_rename" msgid="7678802479104285353">"Переименовать"</string>
<string name="rename_error" msgid="4203041674883412606">"Не удалось переименовать документ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Извлечь"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" на устройстве \"<xliff:g id="STORAGE"><i>^3</i></xliff:g>\"?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index a3c033e..956a59c 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"මෙම ස්ථානය තුළ තෝරාගත් ගොනු ඇලවිය නොහැක."</string>
<string name="menu_rename" msgid="7678802479104285353">"යළි නම් කරන්න"</string>
<string name="rename_error" msgid="4203041674883412606">"ලේඛනය යළි නම් කිරීම අසාර්ථක විය"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"පිටතට ගන්න"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"සමහර ගොනු පරිවර්තනය කරන ලදී"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> හට <xliff:g id="STORAGE"><i>^3</i></xliff:g> මත <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ප්රවේශය දෙන්නද?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ප්රවේශය <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ලබා දෙන්නද?"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 50c98e5..c760868 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Do tohto umiestnenia nie je možné prilepiť vybrané súbory"</string>
<string name="menu_rename" msgid="7678802479104285353">"Premenovať"</string>
<string name="rename_error" msgid="4203041674883412606">"Premenovanie dokumentu zlyhalo"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Odpojiť"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložisku <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index b27505a..5a46141 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Izbranih datotek ni mogoče prilepiti sem."</string>
<string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokumenta ni bilo mogoče preimenovati"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Izvrzi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nekatere datoteke so bile pretvorjene"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v shrambi <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index bae983d..732996a 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Skedarët e zgjedhur nuk mund të ngjiten në këtë vendndodhje."</string>
<string name="menu_rename" msgid="7678802479104285353">"Riemërto"</string>
<string name="rename_error" msgid="4203041674883412606">"Riemërtimi i dokumentit dështoi"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Nxirr"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Disa skedarë u konvertuan"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Jepi aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> në <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index f896ee4..21aadee 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -118,8 +118,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Изабране датотеке не могу да се налепе на овој локацији."</string>
<string name="menu_rename" msgid="7678802479104285353">"Преименуј"</string>
<string name="rename_error" msgid="4203041674883412606">"Преименовање документа није успело"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Избаци"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Желите ли да апликацији <xliff:g id="APPNAME"><b>^1</b></xliff:g> одобрите приступ директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на меморијском простору <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Желите да дозволите да <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 7c60398..5ef9ab2 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Det går inte att klistra in den valda filen på den här platsen."</string>
<string name="menu_rename" msgid="7678802479104285353">"Byt namn"</string>
<string name="rename_error" msgid="4203041674883412606">"Det gick inte att byta namn på dokumentet"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Mata ut"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index bdf53bb..82bc4bb 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Haiwezi kubandika faili zilizochaguliwa katika eneo hili."</string>
<string name="menu_rename" msgid="7678802479104285353">"Badilisha jina"</string>
<string name="rename_error" msgid="4203041674883412606">"Imeshindwa kubadilisha jina la hati"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Ondoa"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Baadhi ya faili zimebadilishwa muundo"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kwenye <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 5c5db98..1573299 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"தேர்ந்தெடுத்த கோப்புகளை இங்கு ஒட்ட முடியாது."</string>
<string name="menu_rename" msgid="7678802479104285353">"மறுபெயரிடு"</string>
<string name="rename_error" msgid="4203041674883412606">"ஆவணத்திற்கு மறுபெயரிடுவதில் தோல்வி"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"வெளியேற்று"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"சில கோப்புகள் மாற்றப்பட்டன"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> இல் உள்ள <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index d28edf2..3bb9720 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ఎంచుకున్న ఫైల్లను ఈ స్థానంలోకి తీసుకురావడం సాధ్యపడదు."</string>
<string name="menu_rename" msgid="7678802479104285353">"పేరు మార్చు"</string>
<string name="rename_error" msgid="4203041674883412606">"పత్రం పేరు మార్చడంలో విఫలమైంది"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"తొలగించు"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"కొన్ని పైల్లు మార్చబడ్డాయి"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="STORAGE"><i>^3</i></xliff:g>లో <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index a3b8c2e..7c587c3 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"ไม่สามารถวางไฟล์ที่เลือกในตำแหน่งนี้"</string>
<string name="menu_rename" msgid="7678802479104285353">"เปลี่ยนชื่อ"</string>
<string name="rename_error" msgid="4203041674883412606">"ไม่สามารถเปลี่ยนชื่อเอกสาร"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"นำอุปกรณ์ออก"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ในการเข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ใน <xliff:g id="STORAGE"><i>^3</i></xliff:g> ไหม"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ไหม"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 791b4e8..63c2334 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Hindi mai-paste sa lokasyong ito ang mga piniling file."</string>
<string name="menu_rename" msgid="7678802479104285353">"Palitan ang pangalan"</string>
<string name="rename_error" msgid="4203041674883412606">"Hindi napalitan ang pangalan ng dokumento"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"I-eject"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa directory ng <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Bibigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa direktoryong <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 18cad9f..402d320 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Seçili dosyalar bu konuma yapıştırılamıyor."</string>
<string name="menu_rename" msgid="7678802479104285353">"Yeniden adlandır"</string>
<string name="rename_error" msgid="4203041674883412606">"Dokümanın adı değiştirilemedi"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Çıkar"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına <xliff:g id="STORAGE"><i>^3</i></xliff:g> depolama alanındaki <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişim izni verilsin mi?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişmek için <xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına izin verilsin mi?"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index fd88cce..e95539f 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -125,8 +125,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Не вдається вставити вибрані файли в цю папку."</string>
<string name="menu_rename" msgid="7678802479104285353">"Перейменувати"</string>
<string name="rename_error" msgid="4203041674883412606">"Не вдалося перейменувати документ"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Вийняти"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на пристрої пам’яті <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 6f2bc89..7c81eba 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"منتخب کردہ فائلز کو اس مقام پر پیسٹ نہیں کیا جا سکتا۔"</string>
<string name="menu_rename" msgid="7678802479104285353">"نام تبدیل کریں"</string>
<string name="rename_error" msgid="4203041674883412606">"دستاویز کا نام تبدیل کرنے میں ناکام"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"خارج کریں"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="STORAGE"><i>^3</i></xliff:g> پر <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی عطا کریں؟"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی دیں؟"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 119ce5f..5090409 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Tanlangan fayllarni bu yerga joylab bo‘lmadi."</string>
<string name="menu_rename" msgid="7678802479104285353">"Qayta nomlash"</string>
<string name="rename_error" msgid="4203041674883412606">"Hujjatni qayta nomlab bo‘lmadi"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Chiqarish"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 0e245ca..b9c99b6 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Không thể dán các tệp đã chọn vào vị trí này."</string>
<string name="menu_rename" msgid="7678802479104285353">"Đổi tên"</string>
<string name="rename_error" msgid="4203041674883412606">"Không đổi được tên tài liệu"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Đẩy ra"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Đã chuyển đổi một số tệp"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> trong <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 54918f6..718ce0d 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"无法将所选文件粘贴到此位置。"</string>
<string name="menu_rename" msgid="7678802479104285353">"重命名"</string>
<string name="rename_error" msgid="4203041674883412606">"无法重命名文档"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"弹出"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的“<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>”目录吗?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问“<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>”目录吗?"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 004145e..552c858 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"無法在此位置貼上選取檔案。"</string>
<string name="menu_rename" msgid="7678802479104285353">"重新命名"</string>
<string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"逐出"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄存取權嗎?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄的存取權嗎?"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index b261d04..1a6a883 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"無法將所選檔案貼到這個位置。"</string>
<string name="menu_rename" msgid="7678802479104285353">"重新命名"</string>
<string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"退出"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 73db563..285047e 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -111,8 +111,7 @@
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Ayikwazi ukunamathisela amafayela akhethiwe kule ndawo."</string>
<string name="menu_rename" msgid="7678802479104285353">"Qamba kabusha"</string>
<string name="rename_error" msgid="4203041674883412606">"Yehlulekile ukuqamba kabusha idokhumenti"</string>
- <!-- no translation found for menu_eject_root (2768224615494227325) -->
- <skip />
+ <string name="menu_eject_root" msgid="2768224615494227325">"Khipha"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Nika i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela ekuqondiseni kwe-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ku-<xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
<string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Nika ukufinyelela kwe-<xliff:g id="APPNAME"><b>^1</b></xliff:g> kwinkomba ye-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index f0cab08..f883164 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -21,9 +21,6 @@
<!-- Intentionally unset. Vendors should set this in an overlay. -->
<string name="trusted_quick_viewer_package" translatable="false"></string>
- <!-- overridden for RTL langs -->
- <bool name="list_divider_inset_left">true</bool>
-
<!-- Flags setup as productivity oriented in which case Downloads app will be presented
as Files app. Including showing of the Documents and "advanced" roots. -->
<bool name="productivity_device">false</bool>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index f40e771..d8d8d3e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -60,6 +60,8 @@
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperations;
import java.io.FileNotFoundException;
import java.util.ArrayList;
@@ -71,6 +73,32 @@
public abstract class BaseActivity extends Activity
implements SearchManagerListener, NavigationViewManager.Environment {
+ public final FileOperations.Callback fileOpCallback = (status, opType, docCount) -> {
+ if (status == FileOperations.Callback.STATUS_REJECTED) {
+ Snackbars.showPasteFailed(this);
+ return;
+ }
+
+ if (docCount == 0) {
+ // Nothing has been pasted, so there is no need to show a snackbar.
+ return;
+ }
+
+ switch (opType) {
+ case FileOperationService.OPERATION_MOVE:
+ Snackbars.showMove(this, docCount);
+ break;
+ case FileOperationService.OPERATION_COPY:
+ Snackbars.showCopy(this, docCount);
+ break;
+ case FileOperationService.OPERATION_DELETE:
+ // We don't show anything for deletion.
+ break;
+ default:
+ throw new UnsupportedOperationException("Unsupported Operation: " + opType);
+ }
+ };
+
private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests";
State mState;
@@ -103,7 +131,6 @@
abstract void onTaskFinished(Uri... uris);
abstract void refreshDirectory(int anim);
- abstract void openRootSettings(RootInfo root);
/** Allows sub-classes to include information in a newly created State instance. */
abstract void includeState(State initialState);
@@ -707,17 +734,6 @@
mNavDrawerHasFocus = !mNavDrawerHasFocus;
}
- DocumentInfo getRootDocumentBlocking(RootInfo root) {
- try {
- final Uri uri = DocumentsContract.buildDocumentUri(
- root.authority, root.documentId);
- return DocumentInfo.fromUri(getContentResolver(), uri);
- } catch (FileNotFoundException e) {
- Log.w(mTag, "Failed to find root", e);
- return null;
- }
- }
-
/**
* Pops the top entry off the directory stack, and returns the user to the previous directory.
* If the directory stack only contains one item, this method does nothing.
@@ -781,7 +797,7 @@
@Override
protected DocumentInfo run(Void... params) {
- return mOwner.getRootDocumentBlocking(mRoot);
+ return mRoot.getRootDocumentBlocking(mOwner);
}
@Override
@@ -817,7 +833,7 @@
final RootInfo defaultRoot = mOwner.mRoots.getDefaultRootBlocking(mOwner.mState);
assert(defaultRoot != null);
if (!defaultRoot.isRecents()) {
- mDefaultRootDocument = mOwner.getRootDocumentBlocking(defaultRoot);
+ mDefaultRootDocument = defaultRoot.getRootDocumentBlocking(mOwner);
}
return defaultRoot;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CheckedTask.java b/packages/DocumentsUI/src/com/android/documentsui/CheckedTask.java
index ae15902..747eb9c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CheckedTask.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CheckedTask.java
@@ -34,7 +34,7 @@
abstract class CheckedTask<Input, Output>
extends AsyncTask<Input, Void, Output> {
- private Check mCheck ;
+ private Check mCheck;
public CheckedTask(Check check) {
mCheck = check;
@@ -73,6 +73,7 @@
finish(result);
}
+ @FunctionalInterface
interface Check {
boolean stop();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8041a1b..05f36e8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -97,7 +97,7 @@
mState.action == ACTION_CREATE ||
mState.action == ACTION_OPEN_TREE ||
mState.action == ACTION_PICK_COPY_DESTINATION) {
- RootsFragment.show(getFragmentManager(), null);
+ RootsFragment.show(getFragmentManager(), (Intent) null);
}
if (mState.restored) {
@@ -233,11 +233,6 @@
}
@Override
- void openRootSettings(RootInfo root) {
- throw new UnsupportedOperationException();
- }
-
- @Override
void refreshDirectory(int anim) {
final FragmentManager fm = getFragmentManager();
final RootInfo root = getCurrentRoot();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
index 93eb527..3b2529f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
@@ -28,6 +28,9 @@
import android.os.RemoteException;
import android.text.format.DateUtils;
+import com.android.documentsui.clipping.ClipStorage;
+import com.android.documentsui.clipping.DocumentClipper;
+
public class DocumentsApplication extends Application {
private static final long PROVIDER_ANR_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/EjectRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/EjectRootTask.java
index fcee472..e47a262 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/EjectRootTask.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/EjectRootTask.java
@@ -23,25 +23,30 @@
import android.provider.DocumentsContract;
import android.util.Log;
+import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
-final class EjectRootTask
- extends CheckedTask<Void, Boolean> {
+final class EjectRootTask extends CheckedTask<Void, Boolean> {
private final String mAuthority;
private final String mRootId;
- private final Consumer<Boolean> mListener;
+ private final Consumer<Boolean> mCallback;
private Context mContext;
- public EjectRootTask(Check check,
+ /**
+ * @param ejectCanceledCheck The method reference we use to see whether eject should be stopped
+ * at any point
+ * @param finishCallback The end callback necessary when the eject task finishes
+ */
+ public EjectRootTask(Context context,
String authority,
String rootId,
- Context context,
- Consumer<Boolean> listener) {
- super(check);
+ BooleanSupplier ejectCanceledCheck,
+ Consumer<Boolean> finishCallback) {
+ super(ejectCanceledCheck::getAsBoolean);
mAuthority = authority;
mRootId = rootId;
mContext = context;
- mListener = listener;
+ mCallback = finishCallback;
}
@Override
@@ -65,6 +70,6 @@
@Override
protected void finish(Boolean ejected) {
- mListener.accept(ejected);
+ mCallback.accept(ejected);
}
}
\ No newline at end of file
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c7c53ba..54f3e61 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -39,6 +39,7 @@
import com.android.documentsui.MenuManager.DirectoryDetails;
import com.android.documentsui.OperationDialogFragment.DialogType;
import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.dirlist.FragmentTuner;
@@ -90,7 +91,7 @@
}
};
- RootsFragment.show(getFragmentManager(), null);
+ RootsFragment.show(getFragmentManager(), this::openRootSettings);
final Intent intent = getIntent();
final Uri uri = intent.getData();
@@ -240,7 +241,6 @@
return true;
}
- @Override
void openRootSettings(RootInfo root) {
Metrics.logUserAction(this, Metrics.USER_ACTION_SETTINGS);
final Intent intent = new Intent(DocumentsContract.ACTION_DOCUMENT_ROOT_SETTINGS);
@@ -519,7 +519,7 @@
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to resolve DocumentInfo from Uri: " + uri);
}
- mState.stack.add(mOwner.getRootDocumentBlocking(root));
+ mState.stack.add(root.getRootDocumentBlocking(mOwner));
return null;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java b/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java
index e1da944..a7e4905 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java
@@ -16,7 +16,6 @@
package com.android.documentsui;
-import android.provider.DocumentsContract.Root;
import android.view.Menu;
import android.view.MenuItem;
@@ -45,7 +44,7 @@
@Override
void updateEject(MenuItem eject, RootInfo root) {
eject.setVisible(true);
- eject.setEnabled(((root.flags & Root.FLAG_SUPPORTS_EJECT) > 0) && !root.ejecting);
+ eject.setEnabled(root.supportsEject() && !root.ejecting);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ItemDragListener.java b/packages/DocumentsUI/src/com/android/documentsui/ItemDragListener.java
index 66b94fc..152d3a0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ItemDragListener.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ItemDragListener.java
@@ -22,7 +22,6 @@
import android.view.DragEvent;
import android.view.View;
import android.view.View.OnDragListener;
-import android.view.ViewConfiguration;
import com.android.documentsui.ItemDragListener.DragHost;
import com.android.internal.annotations.VisibleForTesting;
@@ -39,7 +38,7 @@
private static final String TAG = "ItemDragListener";
@VisibleForTesting
- static final int SPRING_TIMEOUT = ViewConfiguration.getLongPressTimeout();
+ static final int SPRING_TIMEOUT = 1000;
protected final H mDragHost;
private final Timer mHoverTimer;
@@ -82,7 +81,7 @@
TimerTask task = createOpenTask(v);
assert (task != null);
v.setTag(R.id.drag_hovering_tag, task);
- mHoverTimer.schedule(task, ViewConfiguration.getLongPressTimeout());
+ mHoverTimer.schedule(task, SPRING_TIMEOUT);
}
private void handleLocationEvent(View v, float x, float y) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index a33b35b..ca28622 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -24,6 +24,7 @@
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
+import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
@@ -33,16 +34,14 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
-import android.provider.DocumentsContract.Root;
-import android.provider.DocumentsContract;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.Log;
import android.view.ContextMenu;
+import android.view.DragEvent;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -60,7 +59,11 @@
import android.widget.ListView;
import android.widget.TextView;
+import com.android.documentsui.CheckedTask.Check;
+import com.android.documentsui.clipping.DocumentClipper;
+import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperations;
import java.util.ArrayList;
import java.util.Collection;
@@ -81,11 +84,33 @@
private static final String TAG = "RootsFragment";
private static final String EXTRA_INCLUDE_APPS = "includeApps";
+ private final OnDragListener mDragListener = new ItemDragListener<RootsFragment>(this) {
+ @Override
+ public boolean handleDropEventChecked(View v, DragEvent event) {
+ final int position = (Integer) v.getTag(R.id.item_position_tag);
+ final Item item = mAdapter.getItem(position);
+
+ assert(item.isDropTarget());
+
+ BaseActivity activity = getBaseActivity();
+ return item.dropOn(event.getClipData(), activity, RootsFragment.this::isDetached,
+ activity.fileOpCallback);
+ }
+ };
+
private ListView mList;
private RootsAdapter mAdapter;
private LoaderCallbacks<Collection<RootInfo>> mCallbacks;
+ private Consumer<RootInfo> mOpenSettings = (RootInfo) -> {
+ throw new UnsupportedOperationException("Can't open settings.");
+ };
- public static void show(FragmentManager fm, Intent includeApps) {
+ public static void show(FragmentManager fm, Consumer<RootInfo> openSettings) {
+ RootsFragment fragment = show(fm, (Intent) null);
+ fragment.mOpenSettings = openSettings;
+ }
+
+ public static RootsFragment show(FragmentManager fm, Intent includeApps) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
@@ -95,6 +120,8 @@
final FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container_roots, fragment);
ft.commitAllowingStateLoss();
+
+ return fragment;
}
public static RootsFragment get(FragmentManager fm) {
@@ -108,8 +135,12 @@
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
mList = (ListView) view.findViewById(R.id.roots_list);
mList.setOnItemClickListener(mItemListener);
- // For right-clicks, we want to trap the click and not pass it to OnClickListener
- // For all other clicks, we will pass the events down
+ // ListView does not have right-click specific listeners, so we will have a
+ // GenericMotionListener to listen for it.
+ // Currently, right click is viewed the same as long press, so we will have to quickly
+ // register for context menu when we receive a right click event, and quickly unregister
+ // it afterwards to prevent context menus popping up upon long presses.
+ // All other motion events will then get passed to OnItemClickListener.
mList.setOnGenericMotionListener(
new OnGenericMotionListener() {
@Override
@@ -151,8 +182,8 @@
Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
- mAdapter = new RootsAdapter(context, result, handlerAppIntent, state,
- new ItemDragListener<>(RootsFragment.this));
+ mAdapter =
+ new RootsAdapter(context, result, handlerAppIntent, state, mDragListener);
mList.setAdapter(mAdapter);
onCurrentRootChanged();
@@ -233,12 +264,12 @@
* In RootsFragment we open the hovered root.
*/
@Override
- public void onViewHovered(View view) {
+ public void onViewHovered(View v) {
// SpacerView doesn't have DragListener so this view is guaranteed to be a RootItemView.
- RootItemView itemView = (RootItemView) view;
+ RootItemView itemView = (RootItemView) v;
itemView.drawRipple();
- final int position = (Integer) view.getTag(R.id.item_position_tag);
+ final int position = (Integer) v.getTag(R.id.item_position_tag);
final Item item = mAdapter.getItem(position);
item.open(this);
}
@@ -267,15 +298,21 @@
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
+ // There is a possibility that this is called from DirectoryFragment since
+ // all fragments' onContextItemSelected gets called when any menu item is selected
+ // This is to guard against it since DirectoryFragment's RecylerView does not have a
+ // menuInfo
+ if (adapterMenuInfo == null) {
+ return false;
+ }
final RootItem rootItem = (RootItem) mAdapter.getItem(adapterMenuInfo.position);
- switch(item.getItemId()) {
+ switch (item.getItemId()) {
case R.id.menu_eject_root:
- final View unmountIcon = adapterMenuInfo.targetView.findViewById(R.id.unmount_icon);
- ejectClicked(unmountIcon, rootItem.root);
+ final View ejectIcon = adapterMenuInfo.targetView.findViewById(R.id.eject_icon);
+ ejectClicked(ejectIcon, rootItem.root);
return true;
case R.id.menu_settings:
- final RootInfo root = rootItem.root;
- getBaseActivity().openRootSettings(root);
+ mOpenSettings.accept(rootItem.root);
return true;
default:
if (DEBUG) Log.d(TAG, "Unhandled menu item selected: " + item);
@@ -286,6 +323,7 @@
private static void ejectClicked(View ejectIcon, RootInfo root) {
assert(ejectIcon != null);
assert(ejectIcon.getContext() instanceof BaseActivity);
+ assert (!root.ejecting);
ejectIcon.setEnabled(false);
root.ejecting = true;
ejectRoot(
@@ -306,10 +344,10 @@
BooleanSupplier predicate = () -> {
return !(ejectIcon.getVisibility() == View.VISIBLE);
};
- new EjectRootTask(predicate::getAsBoolean,
+ new EjectRootTask(ejectIcon.getContext(),
authority,
rootId,
- ejectIcon.getContext(),
+ predicate,
listener).executeOnExecutor(ProviderExecutor.forAuthority(authority));
}
@@ -360,6 +398,11 @@
abstract boolean isDropTarget();
abstract void open(RootsFragment fragment);
+
+ boolean dropOn(ClipData data, Context context, Check check,
+ FileOperations.Callback callback) {
+ return false;
+ }
}
private static class RootItem extends Item {
@@ -385,24 +428,24 @@
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
- final ImageView unmountIcon = (ImageView) convertView.findViewById(R.id.unmount_icon);
+ final ImageView ejectIcon = (ImageView) convertView.findViewById(R.id.eject_icon);
final Context context = convertView.getContext();
icon.setImageDrawable(root.loadDrawerIcon(context));
title.setText(root.title);
if (root.supportsEject()) {
- unmountIcon.setVisibility(View.VISIBLE);
- unmountIcon.setImageDrawable(root.loadEjectIcon(context));
- unmountIcon.setOnClickListener(new OnClickListener() {
+ ejectIcon.setVisibility(View.VISIBLE);
+ ejectIcon.setImageDrawable(root.loadEjectIcon(context));
+ ejectIcon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View unmountIcon) {
RootsFragment.ejectClicked(unmountIcon, root);
}
});
} else {
- unmountIcon.setVisibility(View.GONE);
- unmountIcon.setOnClickListener(null);
+ ejectIcon.setVisibility(View.GONE);
+ ejectIcon.setOnClickListener(null);
}
// Show available space if no summary
String summaryText = root.summary;
@@ -426,6 +469,14 @@
Metrics.logRootVisited(fragment.getActivity(), root);
activity.onRootPicked(root);
}
+
+ @Override
+ boolean dropOn(
+ ClipData data, Context context, Check check, FileOperations.Callback callback) {
+ ProviderExecutor executor = ProviderExecutor.forAuthority(root.authority);
+ new DropOnRootTask(data, root, context, check, callback).executeOnExecutor(executor);
+ return true;
+ }
}
private static class SpacerItem extends Item {
@@ -504,6 +555,38 @@
}
}
+ private static class DropOnRootTask extends CheckedTask<Void, DocumentInfo> {
+ private ClipData mData;
+ private RootInfo mDstRoot;
+ private Context mContext;
+ private FileOperations.Callback mCallback;
+
+ private DropOnRootTask(ClipData data, RootInfo dstRoot, Context context, Check check,
+ FileOperations.Callback callback) {
+ super(check);
+ mData = data;
+ mDstRoot = dstRoot;
+ mContext = context;
+ mCallback = callback;
+ }
+
+ @Override
+ public DocumentInfo run(Void... args) {
+ return mDstRoot.getRootDocumentBlocking(mContext);
+ }
+
+ @Override
+ public void finish(DocumentInfo doc) {
+ if (doc != null) {
+ DocumentClipper clipper =
+ DocumentsApplication.getDocumentClipper(mContext);
+ clipper.copyFromClipData(mDstRoot, doc, mData, mCallback);
+ } else {
+ Log.e(TAG, "Failed to get doc.");
+ }
+ }
+ }
+
private static class RootsAdapter extends ArrayAdapter<Item> {
private static final Map<String, Long> sIdMap = new HashMap<String, Long>();
// the next available id to associate with a new string id
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index d830c61..a37590d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
+import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -91,6 +92,14 @@
return false;
}
+ // Returning false in this method will bubble the event up to
+ // {@link BaseActivity#onKeyDown}. In order to prevent backspace popping
+ // documents once the textView is empty, we are going to trap it here.
+ if (keyCode == KeyEvent.KEYCODE_DEL
+ && TextUtils.isEmpty(mDisplayName.getText())) {
+ return true;
+ }
+
if (keyCode == KeyEvent.KEYCODE_ENTER && mSave.isEnabled()) {
performSave();
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index c1db87d..0cd568a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.net.Uri;
import android.os.Looper;
import android.provider.DocumentsContract;
import android.text.TextUtils;
@@ -29,6 +30,10 @@
import android.util.Log;
import android.view.WindowManager;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.RootInfo;
+
+import java.io.FileNotFoundException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ClipStorage.java b/packages/DocumentsUI/src/com/android/documentsui/clipping/ClipStorage.java
similarity index 67%
rename from packages/DocumentsUI/src/com/android/documentsui/ClipStorage.java
rename to packages/DocumentsUI/src/com/android/documentsui/clipping/ClipStorage.java
index 3f0427f..49edbcf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ClipStorage.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/clipping/ClipStorage.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.documentsui;
+package com.android.documentsui.clipping;
import android.content.SharedPreferences;
import android.net.Uri;
@@ -24,28 +24,36 @@
import android.system.Os;
import android.util.Log;
+import com.android.documentsui.Files;
+
import java.io.Closeable;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Scanner;
import java.util.concurrent.TimeUnit;
/**
* Provides support for storing lists of documents identified by Uri.
*
* This class uses a ring buffer to recycle clip file slots, to mitigate the issue of clip file
- * deletions.
+ * deletions. Below is the directory layout:
+ * [cache dir]
+ * - [dir] 1
+ * - [dir] 2
+ * - ... to {@link #NUM_OF_SLOTS}
+ * When a clip data is actively being used:
+ * [cache dir]
+ * - [dir] 1
+ * - [file] primary
+ * - [symlink] 1 > primary # copying to location X
+ * - [symlink] 2 > primary # copying to location Y
*/
public final class ClipStorage {
public static final int NO_SELECTION_TAG = -1;
- static final String PREF_NAME = "ClipStoragePref";
+ public static final String PREF_NAME = "ClipStoragePref";
@VisibleForTesting
static final int NUM_OF_SLOTS = 20;
@@ -90,10 +98,10 @@
* file may be overwritten.</li>
* </ul>
*/
- public synchronized int claimStorageSlot() {
+ synchronized int claimStorageSlot() {
int curPos = mNextPos;
for (int i = 0; i < NUM_OF_SLOTS; ++i, curPos = (curPos + 1) % NUM_OF_SLOTS) {
- createSlotFile(curPos);
+ createSlotFileObject(curPos);
if (!mSlots[curPos].exists()) {
break;
@@ -105,7 +113,7 @@
}
// This slot doesn't seem available, but still need to check if it's a legacy of
// service being killed or a service crash etc. If it's stale, it's available.
- else if(checkStaleFiles(curPos)) {
+ else if (checkStaleFiles(curPos)) {
break;
}
}
@@ -148,8 +156,8 @@
* counting method. When someone is done using this symlink, it's responsible to delete it.
* Therefore we can have a neat way to track how many things are still using this slot.
*/
- public File getFile(int tag) throws IOException {
- createSlotFile(tag);
+ public synchronized File getFile(int tag) throws IOException {
+ createSlotFileObject(tag);
File primary = toSlotDataFile(tag);
@@ -167,9 +175,9 @@
/**
* Returns a Reader. Callers must close the reader when finished.
*/
- public Reader createReader(File file) throws IOException {
+ ClipStorageReader createReader(File file) throws IOException {
assert(file.getParentFile().getParentFile().equals(mOutDir));
- return new Reader(file);
+ return new ClipStorageReader(file);
}
private File toSlotDataFile(int pos) {
@@ -177,7 +185,7 @@
return new File(mSlots[pos], PRIMARY_DATA_FILE_NAME);
}
- private void createSlotFile(int pos) {
+ private void createSlotFileObject(int pos) {
if (mSlots[pos] == null) {
mSlots[pos] = new File(mOutDir, Integer.toString(pos));
}
@@ -186,7 +194,7 @@
/**
* Provides initialization of the clip data storage directory.
*/
- static File prepareStorage(File cacheDir) {
+ public static File prepareStorage(File cacheDir) {
File clipDir = getClipDir(cacheDir);
clipDir.mkdir();
@@ -198,96 +206,6 @@
return new File(cacheDir, "clippings");
}
- static final class Reader implements Iterable<Uri>, Closeable {
-
- /**
- * FileLock can't be held multiple times in a single JVM, but it's possible to have multiple
- * readers reading the same clip file. Share the FileLock here so that it can be released
- * when it's not needed.
- */
- private static final Map<String, FileLockEntry> sLocks = new HashMap<>();
-
- private final String mCanonicalPath;
- private final Scanner mScanner;
-
- private Reader(File file) throws IOException {
- FileInputStream inStream = new FileInputStream(file);
- mScanner = new Scanner(inStream);
-
- mCanonicalPath = file.getCanonicalPath(); // Resolve symlink
- synchronized (sLocks) {
- if (sLocks.containsKey(mCanonicalPath)) {
- // Read lock is already held by someone in this JVM, just increment the ref
- // count.
- sLocks.get(mCanonicalPath).mCount++;
- } else {
- // No map entry, need to lock the file so it won't pass this line until the
- // corresponding writer is done writing.
- FileLock lock = inStream.getChannel().lock(0L, Long.MAX_VALUE, true);
- sLocks.put(mCanonicalPath, new FileLockEntry(1, lock, mScanner));
- }
- }
- }
-
- @Override
- public Iterator iterator() {
- return new Iterator(mScanner);
- }
-
- @Override
- public void close() throws IOException {
- synchronized (sLocks) {
- FileLockEntry ref = sLocks.get(mCanonicalPath);
-
- assert(ref.mCount > 0);
- if (--ref.mCount == 0) {
- // If ref count is 0 now, then there is no one who needs to hold the read lock.
- // Release the lock, and remove the entry.
- ref.mLock.release();
- ref.mScanner.close();
- sLocks.remove(mCanonicalPath);
- }
-
- if (mScanner != ref.mScanner) {
- mScanner.close();
- }
- }
- }
- }
-
- private static final class Iterator implements java.util.Iterator {
- private final Scanner mScanner;
-
- private Iterator(Scanner scanner) {
- mScanner = scanner;
- }
-
- @Override
- public boolean hasNext() {
- return mScanner.hasNextLine();
- }
-
- @Override
- public Uri next() {
- String line = mScanner.nextLine();
- return Uri.parse(line);
- }
- }
-
- private static final class FileLockEntry {
- private int mCount;
- private FileLock mLock;
- // We need to keep this scanner here because if the scanner is closed, the file lock is
- // closed too.
- private Scanner mScanner;
-
- private FileLockEntry(int count, FileLock lock, Scanner scanner) {
- mCount = count;
- mLock = lock;
- mScanner = scanner;
- }
- }
-
private static final class Writer implements Closeable {
private final FileOutputStream mOut;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/clipping/ClipStorageReader.java b/packages/DocumentsUI/src/com/android/documentsui/clipping/ClipStorageReader.java
new file mode 100644
index 0000000..2bae0f8
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/clipping/ClipStorageReader.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.clipping;
+
+import android.net.Uri;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.channels.FileLock;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * Reader class used to read uris from clip files stored in {@link ClipStorage}. It provides
+ * synchronization within a single process as an addition to {@link FileLock} which is for
+ * cross-process synchronization.
+ */
+class ClipStorageReader implements Iterable<Uri>, Closeable {
+
+ /**
+ * FileLock can't be held multiple times in a single JVM, but it's possible to have multiple
+ * readers reading the same clip file. Share the FileLock here so that it can be released
+ * when it's not needed.
+ */
+ private static final Map<String, FileLockEntry> sLocks = new HashMap<>();
+
+ private final String mCanonicalPath;
+ private final Scanner mScanner;
+
+ ClipStorageReader(File file) throws IOException {
+ FileInputStream inStream = new FileInputStream(file);
+ mScanner = new Scanner(inStream);
+
+ mCanonicalPath = file.getCanonicalPath(); // Resolve symlink
+ synchronized (sLocks) {
+ if (sLocks.containsKey(mCanonicalPath)) {
+ // Read lock is already held by someone in this JVM, just increment the ref
+ // count.
+ sLocks.get(mCanonicalPath).mCount++;
+ } else {
+ // No map entry, need to lock the file so it won't pass this line until the
+ // corresponding writer is done writing.
+ FileLock lock = inStream.getChannel().lock(0L, Long.MAX_VALUE, true);
+ sLocks.put(mCanonicalPath, new FileLockEntry(1, lock, mScanner));
+ }
+ }
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new Iterator(mScanner);
+ }
+
+ @Override
+ public void close() throws IOException {
+ FileLockEntry ref;
+ synchronized (sLocks) {
+ ref = sLocks.get(mCanonicalPath);
+
+ assert(ref.mCount > 0);
+ if (--ref.mCount == 0) {
+ // If ref count is 0 now, then there is no one who needs to hold the read lock.
+ // Release the lock, and remove the entry.
+ ref.mLock.release();
+ ref.mScanner.close();
+ sLocks.remove(mCanonicalPath);
+ }
+ }
+
+ if (mScanner != ref.mScanner) {
+ mScanner.close();
+ }
+ }
+
+ private static final class Iterator implements java.util.Iterator {
+ private final Scanner mScanner;
+
+ private Iterator(Scanner scanner) {
+ mScanner = scanner;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return mScanner.hasNextLine();
+ }
+
+ @Override
+ public Uri next() {
+ String line = mScanner.nextLine();
+ return Uri.parse(line);
+ }
+ }
+
+ private static final class FileLockEntry {
+ private final FileLock mLock;
+ // We need to keep this scanner here because if the scanner is closed, the file lock is
+ // closed too.
+ private final Scanner mScanner;
+
+ private int mCount;
+
+ private FileLockEntry(int count, FileLock lock, Scanner scanner) {
+ mCount = count;
+ mLock = lock;
+ mScanner = scanner;
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/clipping/DocumentClipper.java
similarity index 87%
rename from packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
rename to packages/DocumentsUI/src/com/android/documentsui/clipping/DocumentClipper.java
index c95ffd1..bdc1836 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/clipping/DocumentClipper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.documentsui;
+package com.android.documentsui.clipping;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -27,9 +27,11 @@
import android.support.annotation.Nullable;
import android.util.Log;
+import com.android.documentsui.Shared;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.RootInfo;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperationService.OpType;
@@ -59,7 +61,7 @@
private final ClipStorage mClipStorage;
private final ClipboardManager mClipboard;
- DocumentClipper(Context context, ClipStorage storage) {
+ public DocumentClipper(Context context, ClipStorage storage) {
mContext = context;
mClipStorage = storage;
mClipboard = context.getSystemService(ClipboardManager.class);
@@ -232,16 +234,42 @@
}
/**
- * Copies documents from given clip data.
+ * Copied documents from given clip data to a root directory.
+ * @param root the root which root directory to copy to
+ * @param destination the root directory
+ * @param clipData the clipData to copy from
+ * @param callback callback to notify when operation finishes
+ */
+ public void copyFromClipData(
+ final RootInfo root,
+ final DocumentInfo destination,
+ final @Nullable ClipData clipData,
+ final FileOperations.Callback callback) {
+ DocumentStack dstStack = new DocumentStack(root, destination);
+ copyFromClipData(dstStack, clipData, callback);
+ }
+
+ /**
+ * Copies documents from given clip data to a folder.
*
- * @param destination destination document
- * @param docStack the document stack to the destination folder
- * @param clipData the clipData to copy from, or null to copy from clipboard
+ * @param destination destination folder
+ * @param docStack the document stack to the destination folder (not including the destination
+ * folder)
+ * @param clipData the clipData to copy from
* @param callback callback to notify when operation finishes
*/
public void copyFromClipData(
final DocumentInfo destination,
- DocumentStack docStack,
+ final DocumentStack docStack,
+ final @Nullable ClipData clipData,
+ final FileOperations.Callback callback) {
+
+ DocumentStack dstStack = new DocumentStack(docStack, destination);
+ copyFromClipData(dstStack, clipData, callback);
+ }
+
+ private void copyFromClipData(
+ final DocumentStack dstStack,
final @Nullable ClipData clipData,
final FileOperations.Callback callback) {
@@ -253,21 +281,19 @@
PersistableBundle bundle = clipData.getDescription().getExtras();
@OpType int opType = getOpType(bundle);
try {
- UrisSupplier uris = UrisSupplier.create(clipData, mContext);
- if (!canCopy(destination)) {
+ if (!canCopy(dstStack.peek())) {
callback.onOperationResult(
- FileOperations.Callback.STATUS_REJECTED, opType, 0);
+ FileOperations.Callback.STATUS_REJECTED, getOpType(clipData), 0);
return;
}
+ UrisSupplier uris = UrisSupplier.create(clipData, mContext);
if (uris.getItemCount() == 0) {
callback.onOperationResult(
FileOperations.Callback.STATUS_ACCEPTED, opType, 0);
return;
}
- DocumentStack dstStack = new DocumentStack(docStack, destination);
-
String srcParentString = bundle.getString(SRC_PARENT_KEY);
Uri srcParent = srcParentString == null ? null : Uri.parse(srcParentString);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/UrisSupplier.java b/packages/DocumentsUI/src/com/android/documentsui/clipping/UrisSupplier.java
similarity index 94%
rename from packages/DocumentsUI/src/com/android/documentsui/UrisSupplier.java
rename to packages/DocumentsUI/src/com/android/documentsui/clipping/UrisSupplier.java
index e4a11ef..7b1ba34 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/UrisSupplier.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/clipping/UrisSupplier.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.documentsui;
+package com.android.documentsui.clipping;
-import static com.android.documentsui.DocumentClipper.OP_JUMBO_SELECTION_SIZE;
-import static com.android.documentsui.DocumentClipper.OP_JUMBO_SELECTION_TAG;
+import static com.android.documentsui.clipping.DocumentClipper.OP_JUMBO_SELECTION_SIZE;
+import static com.android.documentsui.clipping.DocumentClipper.OP_JUMBO_SELECTION_TAG;
import android.content.ClipData;
import android.content.Context;
@@ -28,6 +28,8 @@
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.Shared;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.services.FileOperation;
@@ -110,7 +112,7 @@
private final File mFile;
private final int mSelectionSize;
- private final transient AtomicReference<ClipStorage.Reader> mReader =
+ private final transient AtomicReference<ClipStorageReader> mReader =
new AtomicReference<>();
private JumboUrisSupplier(ClipData clipData, Context context) throws IOException {
@@ -143,7 +145,7 @@
@Override
Iterable<Uri> getUris(ClipStorage storage) throws IOException {
- ClipStorage.Reader reader = mReader.getAndSet(storage.createReader(mFile));
+ ClipStorageReader reader = mReader.getAndSet(storage.createReader(mFile));
if (reader != null) {
reader.close();
mReader.get().close();
@@ -156,7 +158,7 @@
@Override
public void dispose() {
try {
- ClipStorage.Reader reader = mReader.get();
+ ClipStorageReader reader = mReader.get();
if (reader != null) {
reader.close();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 3980cfc..85c988e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -73,7 +73,7 @@
import com.android.documentsui.BaseActivity;
import com.android.documentsui.DirectoryLoader;
import com.android.documentsui.DirectoryResult;
-import com.android.documentsui.DocumentClipper;
+import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.DocumentsActivity;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.Events.InputEvent;
@@ -92,7 +92,7 @@
import com.android.documentsui.Snackbars;
import com.android.documentsui.State;
import com.android.documentsui.State.ViewMode;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.dirlist.UserInputHandler.DocumentDetails;
import com.android.documentsui.model.DocumentInfo;
@@ -142,7 +142,7 @@
private Model mModel;
private MultiSelectManager mSelectionMgr;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
- private UserInputHandler mInputHandler;
+ private UserInputHandler<InputEvent> mInputHandler;
private SelectionModeListener mSelectionModeListener;
private FocusManager mFocusManager;
@@ -184,35 +184,6 @@
private DirectoryDragListener mOnDragListener;
private MenuManager mMenuManager;
- /**
- * A callback to show snackbar at the beginning of moving and copying.
- */
- private final FileOperations.Callback mFileOpCallback = (status, opType, docCount) -> {
- if (status == FileOperations.Callback.STATUS_REJECTED) {
- Snackbars.showPasteFailed(getActivity());
- return;
- }
-
- if (docCount == 0) {
- // Nothing has been pasted, so there is no need to show a snackbar.
- return;
- }
-
- switch (opType) {
- case FileOperationService.OPERATION_MOVE:
- Snackbars.showMove(getActivity(), docCount);
- break;
- case FileOperationService.OPERATION_COPY:
- Snackbars.showCopy(getActivity(), docCount);
- break;
- case FileOperationService.OPERATION_DELETE:
- // We don't show anything for deletion.
- break;
- default:
- throw new UnsupportedOperationException("Unsupported Operation: " + opType);
- }
- };
-
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -309,7 +280,7 @@
// Make sure this is done after the RecyclerView is set up.
mFocusManager = new FocusManager(context, mRecView, mModel);
- mInputHandler = new UserInputHandler(
+ mInputHandler = new UserInputHandler<>(
mSelectionMgr,
mFocusManager,
new Function<MotionEvent, InputEvent>() {
@@ -423,7 +394,8 @@
operation.setDestination(data.getParcelableExtra(Shared.EXTRA_STACK));
- FileOperations.start(getContext(), operation, mFileOpCallback);
+ BaseActivity activity = getBaseActivity();
+ FileOperations.start(activity, operation, activity.fileOpCallback);
}
protected boolean onRightClick(InputEvent e) {
@@ -1021,7 +993,8 @@
.withSrcParent(srcParent.derivedUri)
.build();
- FileOperations.start(getActivity(), operation, mFileOpCallback);
+ BaseActivity activity = getBaseActivity();
+ FileOperations.start(activity, operation, activity.fileOpCallback);
}
})
.setNegativeButton(android.R.string.cancel, null)
@@ -1234,7 +1207,8 @@
BaseActivity activity = (BaseActivity) getActivity();
DocumentInfo destination = activity.getCurrentDirectory();
- mClipper.copyFromClipboard(destination, activity.getDisplayState().stack, mFileOpCallback);
+ mClipper.copyFromClipboard(
+ destination, activity.getDisplayState().stack, activity.fileOpCallback);
getActivity().invalidateOptionsMenu();
}
@@ -1347,7 +1321,7 @@
src == null ? Metrics.USER_ACTION_DRAG_N_DROP_MULTI_WINDOW
: Metrics.USER_ACTION_DRAG_N_DROP);
- mClipper.copyFromClipData(dst, getDisplayState().stack, clipData, mFileOpCallback);
+ mClipper.copyFromClipData(dst, getDisplayState().stack, clipData, activity.fileOpCallback);
return true;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index e58971a..9c0b967 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -21,13 +21,10 @@
import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
-import com.android.documentsui.Events.InputEvent;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -39,6 +36,8 @@
import java.util.Map;
import java.util.Set;
+import javax.annotation.Nullable;
+
/**
* MultiSelectManager provides support traditional multi-item selection support to RecyclerView.
* Additionally it can be configured to restrict selection to a single element, @see
@@ -62,7 +61,7 @@
private final DocumentsAdapter mAdapter;
private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
- private Range mRanger;
+ private @Nullable Range mRanger;
private boolean mSingleSelect;
public MultiSelectManager(DocumentsAdapter adapter, @SelectionMode int mode) {
@@ -223,70 +222,13 @@
}
}
- @VisibleForTesting
- void onLongPress(InputEvent input) {
- if (DEBUG) Log.d(TAG, "Handling long press event.");
+ void snapSelection(int position) {
+ mRanger.snapSelection(position);
- if (!input.isOverItem()) {
- if (DEBUG) Log.i(TAG, "Cannot handle tap. No adapter position available.");
- }
-
- handleAdapterEvent(input);
- }
-
- boolean onSingleTapUp(InputEvent input) {
- if (DEBUG) Log.d(TAG, "Processing tap event.");
- if (!hasSelection()) {
- // No selection active - do nothing.
- return false;
- }
-
- if (!input.isOverItem()) {
- if (DEBUG) Log.d(TAG, "Activity has no position. Canceling selection.");
- clearSelection();
- return false;
- }
-
- handleAdapterEvent(input);
- return true;
- }
-
- /**
- * Handles a change caused by a click on the item with the given position. If the Shift key is
- * held down, this performs a range select; otherwise, it simply toggles the item's selection
- * state.
- */
- private void handleAdapterEvent(InputEvent input) {
- if (mRanger != null && input.isShiftKeyDown()) {
- mRanger.snapSelection(input.getItemPosition());
-
- // We're being lazy here notifying even when something might not have changed.
- // To make this more correct, we'd need to update the Ranger class to return
- // information about what has changed.
- notifySelectionChanged();
- } else {
- int position = input.getItemPosition();
- toggleSelection(position);
- setSelectionRangeBegin(position);
- }
- }
-
- /**
- * A convenience method for toggling selection by adapter position.
- *
- * @param position Adapter position to toggle.
- */
- private void toggleSelection(int position) {
- // Position may be special "no position" during certain
- // transitional phases. If so, skip handling of the event.
- if (position == RecyclerView.NO_POSITION) {
- if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
- return;
- }
- String id = mAdapter.getModelId(position);
- if (id != null) {
- toggleSelection(id);
- }
+ // We're being lazy here notifying even when something might not have changed.
+ // To make this more correct, we'd need to update the Ranger class to return
+ // information about what has changed.
+ notifySelectionChanged();
}
/**
@@ -329,7 +271,9 @@
* @param pos The new end position for the selection range.
*/
void snapRangeSelection(int pos) {
- assert(mRanger != null);
+ if (!isRangeSelectionActive()) {
+ throw new IllegalStateException("Range start point not set.");
+ }
mRanger.snapSelection(pos);
notifySelectionChanged();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/UserInputHandler.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/UserInputHandler.java
index 943815c..07b0cd8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/UserInputHandler.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/UserInputHandler.java
@@ -16,6 +16,10 @@
package com.android.documentsui.dirlist;
+import static com.android.documentsui.Shared.DEBUG;
+
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -30,25 +34,29 @@
/**
* Grand unified-ish gesture/event listener for items in the directory list.
*/
-final class UserInputHandler extends GestureDetector.SimpleOnGestureListener
+public final class UserInputHandler<T extends InputEvent>
+ extends GestureDetector.SimpleOnGestureListener
implements KeyboardEventListener {
+ private static final String TAG = "UserInputHandler";
+
private final MultiSelectManager mSelectionMgr;
private final FocusHandler mFocusHandler;
- private final Function<MotionEvent, InputEvent> mEventConverter;
- private final Function<InputEvent, DocumentDetails> mDocFinder;
+ private final Function<MotionEvent, T> mEventConverter;
+ private final Function<T, DocumentDetails> mDocFinder;
private final Predicate<DocumentDetails> mSelectable;
private final EventHandler mRightClickHandler;
private final DocumentHandler mActivateHandler;
private final DocumentHandler mDeleteHandler;
private final TouchInputDelegate mTouchDelegate;
private final MouseInputDelegate mMouseDelegate;
+ private final KeyInputHandler mKeyListener;
public UserInputHandler(
MultiSelectManager selectionMgr,
FocusHandler focusHandler,
- Function<MotionEvent, InputEvent> eventConverter,
- Function<InputEvent, DocumentDetails> docFinder,
+ Function<MotionEvent, T> eventConverter,
+ Function<T, DocumentDetails> docFinder,
Predicate<DocumentDetails> selectable,
EventHandler rightClickHandler,
DocumentHandler activateHandler,
@@ -65,55 +73,116 @@
mTouchDelegate = new TouchInputDelegate();
mMouseDelegate = new MouseInputDelegate();
+ mKeyListener = new KeyInputHandler();
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
- try (InputEvent event = mEventConverter.apply(e)) {
- return event.isMouseEvent()
- ? mMouseDelegate.onSingleTapUp(event)
- : mTouchDelegate.onSingleTapUp(event);
+ try (T event = mEventConverter.apply(e)) {
+ return onSingleTapUp(event);
}
}
+ @VisibleForTesting
+ boolean onSingleTapUp(T event) {
+ return event.isMouseEvent()
+ ? mMouseDelegate.onSingleTapUp(event)
+ : mTouchDelegate.onSingleTapUp(event);
+ }
+
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
- try (InputEvent event = mEventConverter.apply(e)) {
- return event.isMouseEvent()
- ? mMouseDelegate.onSingleTapConfirmed(event)
- : mTouchDelegate.onSingleTapConfirmed(event);
+ try (T event = mEventConverter.apply(e)) {
+ return onSingleTapConfirmed(event);
}
}
+ @VisibleForTesting
+ boolean onSingleTapConfirmed(T event) {
+ return event.isMouseEvent()
+ ? mMouseDelegate.onSingleTapConfirmed(event)
+ : mTouchDelegate.onSingleTapConfirmed(event);
+ }
+
@Override
public boolean onDoubleTap(MotionEvent e) {
- try (InputEvent event = mEventConverter.apply(e)) {
- return event.isMouseEvent()
- ? mMouseDelegate.onDoubleTap(event)
- : mTouchDelegate.onDoubleTap(event);
+ try (T event = mEventConverter.apply(e)) {
+ return onDoubleTap(event);
}
}
+ @VisibleForTesting
+ boolean onDoubleTap(T event) {
+ return event.isMouseEvent()
+ ? mMouseDelegate.onDoubleTap(event)
+ : mTouchDelegate.onDoubleTap(event);
+ }
+
@Override
public void onLongPress(MotionEvent e) {
- try (InputEvent event = mEventConverter.apply(e)) {
- if (event.isMouseEvent()) {
- mMouseDelegate.onLongPress(event);
- }
- mTouchDelegate.onLongPress(event);
+ try (T event = mEventConverter.apply(e)) {
+ onLongPress(event);
}
}
- private boolean onSelect(DocumentDetails doc) {
+ @VisibleForTesting
+ void onLongPress(T event) {
+ if (event.isMouseEvent()) {
+ mMouseDelegate.onLongPress(event);
+ }
+ mTouchDelegate.onLongPress(event);
+ }
+
+ public boolean onSingleRightClickUp(MotionEvent e) {
+ try (T event = mEventConverter.apply(e)) {
+ return mMouseDelegate.onSingleRightClickUp(event);
+ }
+ }
+
+ @Override
+ public boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ return mKeyListener.onKey(doc, keyCode, event);
+ }
+
+ // TODO: Isolate this hack...see if we can't get this solved at the platform level.
+ public void setLastButtonState(int state) {
+ mMouseDelegate.setLastButtonState(state);
+ }
+
+ private boolean activateDocument(DocumentDetails doc) {
+ return mActivateHandler.accept(doc);
+ }
+
+ private boolean selectDocument(DocumentDetails doc) {
+ assert(doc != null);
mSelectionMgr.toggleSelection(doc.getModelId());
mSelectionMgr.setSelectionRangeBegin(doc.getAdapterPosition());
return true;
}
+ boolean isRangeExtension(T event) {
+ return event.isShiftKeyDown() && mSelectionMgr.isRangeSelectionActive();
+ }
+
+ private void extendSelectionRange(T event) {
+ mSelectionMgr.snapSelection(event.getItemPosition());
+ }
+
private final class TouchInputDelegate {
- public boolean onSingleTapUp(InputEvent event) {
- if (mSelectionMgr.onSingleTapUp(event)) {
+ boolean onSingleTapUp(T event) {
+ if (!event.isOverItem()) {
+ if (DEBUG) Log.d(TAG, "Tap on non-item. Clearing selection.");
+ mSelectionMgr.clearSelection();
+ return false;
+ }
+
+ if (mSelectionMgr.hasSelection()) {
+ if (isRangeExtension(event)) {
+ mSelectionMgr.snapSelection(event.getItemPosition());
+ } else {
+ selectDocument(mDocFinder.apply(event));
+ }
return true;
}
@@ -123,23 +192,31 @@
// Touch events select if they occur in the selection hotspot,
// otherwise they activate.
return doc.isInSelectionHotspot(event)
- ? onSelect(doc)
- : mActivateHandler.accept(doc);
+ ? selectDocument(doc)
+ : activateDocument(doc);
}
return false;
}
- public boolean onSingleTapConfirmed(InputEvent event) {
+ boolean onSingleTapConfirmed(T event) {
return false;
}
- public boolean onDoubleTap(InputEvent event) {
+ boolean onDoubleTap(T event) {
return false;
}
- public void onLongPress(InputEvent event) {
- mSelectionMgr.onLongPress(event);
+ final void onLongPress(T event) {
+ if (!event.isOverItem()) {
+ return;
+ }
+
+ if (isRangeExtension(event)) {
+ extendSelectionRange(event);
+ } else {
+ selectDocument(mDocFinder.apply(event));
+ }
}
}
@@ -155,18 +232,28 @@
private int mLastButtonState = -1;
// true when the previous event has consumed a right click motion event
- private boolean ateRightClick;
+ private boolean mAteRightClick;
// The event has been handled in onSingleTapUp
- private boolean handledTapUp;
+ private boolean mHandledTapUp;
- public boolean onSingleTapUp(InputEvent event) {
+ boolean onSingleTapUp(T event) {
if (eatRightClick()) {
return onSingleRightClickUp(event);
}
- if (mSelectionMgr.onSingleTapUp(event)) {
- handledTapUp = true;
+ if (!event.isOverItem()) {
+ mSelectionMgr.clearSelection();
+ return false;
+ }
+
+ if (mSelectionMgr.hasSelection()) {
+ if (isRangeExtension(event)) {
+ extendSelectionRange(event);
+ } else {
+ selectDocument(mDocFinder.apply(event));
+ }
+ mHandledTapUp = true;
return true;
}
@@ -181,17 +268,17 @@
return false;
}
- handledTapUp = true;
- return onSelect(doc);
+ mHandledTapUp = true;
+ return selectDocument(doc);
}
- public boolean onSingleTapConfirmed(InputEvent event) {
- if (ateRightClick) {
- ateRightClick = false;
+ boolean onSingleTapConfirmed(T event) {
+ if (mAteRightClick) {
+ mAteRightClick = false;
return false;
}
- if (handledTapUp) {
- handledTapUp = false;
+ if (mHandledTapUp) {
+ mHandledTapUp = false;
return false;
}
@@ -204,25 +291,33 @@
return false;
}
- return onSelect(doc);
+ return selectDocument(doc);
}
- public boolean onDoubleTap(InputEvent event) {
- handledTapUp = false;
+ boolean onDoubleTap(T event) {
+ mHandledTapUp = false;
DocumentDetails doc = mDocFinder.apply(event);
if (doc != null) {
return mSelectionMgr.hasSelection()
- ? onSelect(doc)
- : mActivateHandler.accept(doc);
+ ? selectDocument(doc)
+ : activateDocument(doc);
}
return false;
}
- public void onLongPress(InputEvent event) {
- mSelectionMgr.onLongPress(event);
+ final void onLongPress(T event) {
+ if (!event.isOverItem()) {
+ return;
+ }
+
+ if (isRangeExtension(event)) {
+ extendSelectionRange(event);
+ } else {
+ selectDocument(mDocFinder.apply(event));
+ }
}
- private boolean onSingleRightClickUp(InputEvent event) {
+ private boolean onSingleRightClickUp(T event) {
return mRightClickHandler.apply(event);
}
@@ -234,96 +329,77 @@
private boolean eatRightClick() {
if (mLastButtonState == MotionEvent.BUTTON_SECONDARY) {
mLastButtonState = -1;
- ateRightClick = true;
+ mAteRightClick = true;
return true;
}
return false;
}
}
- public boolean onSingleRightClickUp(MotionEvent e) {
- try (InputEvent event = mEventConverter.apply(e)) {
- return mMouseDelegate.onSingleRightClickUp(event);
- }
- }
+ private final class KeyInputHandler {
+ // TODO: Refactor FocusManager to depend only on DocumentDetails so we can eliminate
+ // difficult to test dependency on DocumentHolder.
- // TODO: Isolate this hack...see if we can't get this solved at the platform level.
- public void setLastButtonState(int state) {
- mMouseDelegate.setLastButtonState(state);
- }
-
- // TODO: Refactor FocusManager to depend only on DocumentDetails so we can eliminate
- // difficult to test dependency on DocumentHolder.
- @Override
- public boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event) {
- // Only handle key-down events. This is simpler, consistent with most other UIs, and
- // enables the handling of repeated key events from holding down a key.
- if (event.getAction() != KeyEvent.ACTION_DOWN) {
- return false;
- }
-
- // Ignore tab key events. Those should be handled by the top-level key handler.
- if (keyCode == KeyEvent.KEYCODE_TAB) {
- return false;
- }
-
- if (mFocusHandler.handleKey(doc, keyCode, event)) {
- // Handle range selection adjustments. Extending the selection will adjust the
- // bounds of the in-progress range selection. Each time an unshifted navigation
- // event is received, the range selection is restarted.
- if (shouldExtendSelection(doc, event)) {
- if (!mSelectionMgr.isRangeSelectionActive()) {
- // Start a range selection if one isn't active
- mSelectionMgr.startRangeSelection(doc.getAdapterPosition());
- }
- mSelectionMgr.snapRangeSelection(mFocusHandler.getFocusPosition());
- } else {
- mSelectionMgr.endRangeSelection();
+ boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ // Only handle key-down events. This is simpler, consistent with most other UIs, and
+ // enables the handling of repeated key events from holding down a key.
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return false;
}
- return true;
- }
- // Handle enter key events
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- if (event.isShiftPressed()) {
- onSelect(doc);
+ // Ignore tab key events. Those should be handled by the top-level key handler.
+ if (keyCode == KeyEvent.KEYCODE_TAB) {
+ return false;
+ }
+
+ if (mFocusHandler.handleKey(doc, keyCode, event)) {
+ // Handle range selection adjustments. Extending the selection will adjust the
+ // bounds of the in-progress range selection. Each time an unshifted navigation
+ // event is received, the range selection is restarted.
+ if (shouldExtendSelection(doc, event)) {
+ if (!mSelectionMgr.isRangeSelectionActive()) {
+ // Start a range selection if one isn't active
+ mSelectionMgr.startRangeSelection(doc.getAdapterPosition());
+ }
+ mSelectionMgr.snapRangeSelection(mFocusHandler.getFocusPosition());
+ } else {
+ mSelectionMgr.endRangeSelection();
}
- // For non-shifted enter keypresses, fall through.
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_BUTTON_A:
- return mActivateHandler.accept(doc);
- case KeyEvent.KEYCODE_FORWARD_DEL:
- // This has to be handled here instead of in a keyboard shortcut, because
- // keyboard shortcuts all have to be modified with the 'Ctrl' key.
- if (mSelectionMgr.hasSelection()) {
- mDeleteHandler.accept(doc);
- }
- // Always handle the key, even if there was nothing to delete. This is a
- // precaution to prevent other handlers from potentially picking up the event
- // and triggering extra behaviors.
return true;
- }
+ }
- return false;
- }
+ // Handle enter key events
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_ENTER:
+ if (event.isShiftPressed()) {
+ selectDocument(doc);
+ }
+ // For non-shifted enter keypresses, fall through.
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_BUTTON_A:
+ return activateDocument(doc);
+ case KeyEvent.KEYCODE_FORWARD_DEL:
+ // This has to be handled here instead of in a keyboard shortcut, because
+ // keyboard shortcuts all have to be modified with the 'Ctrl' key.
+ if (mSelectionMgr.hasSelection()) {
+ mDeleteHandler.accept(doc);
+ }
+ // Always handle the key, even if there was nothing to delete. This is a
+ // precaution to prevent other handlers from potentially picking up the event
+ // and triggering extra behaviors.
+ return true;
+ }
- private boolean shouldExtendSelection(DocumentDetails doc, KeyEvent event) {
- if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) {
return false;
}
- return mSelectable.test(doc);
- }
+ private boolean shouldExtendSelection(DocumentDetails doc, KeyEvent event) {
+ if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) {
+ return false;
+ }
- @FunctionalInterface
- interface EventHandler {
- boolean apply(InputEvent input);
- }
-
- @FunctionalInterface
- interface DocumentHandler {
- boolean accept(DocumentDetails doc);
+ return mSelectable.test(doc);
+ }
}
/**
@@ -334,4 +410,14 @@
int getAdapterPosition();
boolean isInSelectionHotspot(InputEvent event);
}
+
+ @FunctionalInterface
+ interface EventHandler {
+ boolean apply(InputEvent event);
+ }
+
+ @FunctionalInterface
+ interface DocumentHandler {
+ boolean accept(DocumentDetails doc);
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
index c4f4dc1..ae7e820 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -42,11 +42,20 @@
public DocumentStack() {};
/**
+ * Creates an instance, and pushes all docs to it in the same order as they're passed as
+ * parameters, i.e. the last document will be at the top of the stack.
+ */
+ public DocumentStack(RootInfo root, DocumentInfo... docs) {
+ for (DocumentInfo doc : docs) {
+ push(doc);
+ }
+
+ this.root = root;
+ }
+
+ /**
* Makes a new copy, and pushes all docs to the new copy in the same order as they're passed
* as parameters, i.e. the last document will be at the top of the stack.
- *
- * @param src
- * @param docs
*/
public DocumentStack(DocumentStack src, DocumentInfo... docs) {
super(src);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 92eea5e..e062dfb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -23,6 +23,7 @@
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
@@ -39,6 +40,7 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -346,6 +348,19 @@
return IconUtils.applyTintColor(context, R.drawable.ic_eject, R.color.item_eject_icon);
}
+ /**
+ * Gets the {@link DocumentInfo} of the root folder of this root.
+ */
+ public @Nullable DocumentInfo getRootDocumentBlocking(Context context) {
+ try {
+ final Uri uri = DocumentsContract.buildDocumentUri(authority, documentId);
+ return DocumentInfo.fromUri(context.getContentResolver(), uri);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to find root", e);
+ return null;
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (o == null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index 7497a83..c8f6a64 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -55,7 +55,7 @@
import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.RootsCache;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 92440a2..64bc1a7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -26,7 +26,7 @@
import android.net.Uri;
import android.util.Log;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperation.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperation.java
index c905a35..43c3bd7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperation.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperation.java
@@ -27,7 +27,7 @@
import android.os.Parcelable;
import android.support.annotation.VisibleForTesting;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.services.FileOperationService.OpType;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index f9f49ca..14ae66e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -40,7 +40,7 @@
import android.provider.DocumentsContract;
import android.util.Log;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.FilesActivity;
import com.android.documentsui.Metrics;
import com.android.documentsui.OperationDialogFragment;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index beae9a8..ab0fae1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -30,7 +30,7 @@
import android.util.Log;
import com.android.documentsui.R;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java
index 76ca2f3..3644abc 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java
@@ -266,11 +266,21 @@
}
@Test
- public void testRootContextMenu_canEject() {
+ public void testRootContextMenu_eject() {
testRootInfo.flags = Root.FLAG_SUPPORTS_EJECT;
FilesMenuManager mgr = new FilesMenuManager(testSearchManager, state);
mgr.updateRootContextMenu(testMenu, testRootInfo);
eject.assertEnabled();
}
+
+ @Test
+ public void testRootContextMenu_ejectInProcess() {
+ testRootInfo.flags = Root.FLAG_SUPPORTS_EJECT;
+ testRootInfo.ejecting = true;
+ FilesMenuManager mgr = new FilesMenuManager(testSearchManager, state);
+ mgr.updateRootContextMenu(testMenu, testRootInfo);
+
+ eject.assertDisabled();
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/ClipStorageTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/clipping/ClipStorageTest.java
similarity index 91%
rename from packages/DocumentsUI/tests/src/com/android/documentsui/ClipStorageTest.java
rename to packages/DocumentsUI/tests/src/com/android/documentsui/clipping/ClipStorageTest.java
index 788a5b3..73366f8 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/ClipStorageTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/clipping/ClipStorageTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.documentsui;
+package com.android.documentsui.clipping;
-import static com.android.documentsui.ClipStorage.NUM_OF_SLOTS;
+import static com.android.documentsui.clipping.ClipStorage.NUM_OF_SLOTS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -29,7 +29,6 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.documentsui.ClipStorage.Reader;
import com.android.documentsui.testing.TestScheduledExecutorService;
import org.junit.AfterClass;
@@ -89,7 +88,7 @@
List<Uri> uris = new ArrayList<>();
File copy = mStorage.getFile(mTag);
- try(Reader provider = mStorage.createReader(copy)) {
+ try(ClipStorageReader provider = mStorage.createReader(copy)) {
for (Uri uri : provider) {
uris.add(uri);
}
@@ -98,7 +97,7 @@
}
@Test
- public void testGetTag_NoAvailableSlot() throws Exception {
+ public void testClaimStorageSlot_NoAvailableSlot() throws Exception {
int firstTag = mStorage.claimStorageSlot();
writeAll(firstTag, TEST_URIS);
mStorage.getFile(firstTag);
@@ -119,8 +118,8 @@
File copy = mStorage.getFile(mTag);
File copy2 = mStorage.getFile(mTag);
- try(Reader reader = mStorage.createReader(copy)) {
- try(Reader reader2 = mStorage.createReader(copy2)){
+ try(ClipStorageReader reader = mStorage.createReader(copy)) {
+ try(ClipStorageReader reader2 = mStorage.createReader(copy2)){
Iterator<Uri> iter = reader.iterator();
Iterator<Uri> iter2 = reader2.iterator();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UrisSupplierTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/clipping/UrisSupplierTest.java
similarity index 97%
rename from packages/DocumentsUI/tests/src/com/android/documentsui/UrisSupplierTest.java
rename to packages/DocumentsUI/tests/src/com/android/documentsui/clipping/UrisSupplierTest.java
index 2622322..9815d0e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UrisSupplierTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/clipping/UrisSupplierTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.documentsui;
+package com.android.documentsui.clipping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -27,6 +27,7 @@
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.documentsui.Shared;
import com.android.documentsui.testing.TestScheduledExecutorService;
import org.junit.AfterClass;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index 7eb3c2e..57b9f92 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -16,15 +16,13 @@
package com.android.documentsui.dirlist;
-import android.support.v7.widget.RecyclerView;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.SparseBooleanArray;
-import com.android.documentsui.TestInputEvent;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
-
-import com.google.common.collect.Lists;
+import com.android.documentsui.testing.dirlist.SelectionProbe;
+import com.android.documentsui.testing.dirlist.TestSelectionListener;
import java.util.HashSet;
import java.util.List;
@@ -33,180 +31,66 @@
@SmallTest
public class MultiSelectManagerTest extends AndroidTestCase {
- private static final List<String> items = TestData.create(100);
+ private static final List<String> ITEMS = TestData.create(100);
private MultiSelectManager mManager;
- private TestCallback mCallback;
+ private TestSelectionListener mCallback;
private TestDocumentsAdapter mAdapter;
+ private SelectionProbe mSelection;
@Override
public void setUp() throws Exception {
- mCallback = new TestCallback();
- mAdapter = new TestDocumentsAdapter(items);
+ mCallback = new TestSelectionListener();
+ mAdapter = new TestDocumentsAdapter(ITEMS);
mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE);
mManager.addCallback(mCallback);
+
+ mSelection = new SelectionProbe(mManager);
}
public void testSelection() {
// Check selection.
- mManager.toggleSelection(items.get(7));
- assertSelection(items.get(7));
+ mManager.toggleSelection(ITEMS.get(7));
+ mSelection.assertSelection(7);
// Check deselection.
- mManager.toggleSelection(items.get(7));
- assertSelectionSize(0);
+ mManager.toggleSelection(ITEMS.get(7));
+ mSelection.assertNoSelection();
}
public void testSelection_NotifiesSelectionChanged() {
// Selection should notify.
- mManager.toggleSelection(items.get(7));
+ mManager.toggleSelection(ITEMS.get(7));
mCallback.assertSelectionChanged();
// Deselection should notify.
- mManager.toggleSelection(items.get(7));
+ mManager.toggleSelection(ITEMS.get(7));
mCallback.assertSelectionChanged();
}
- public void testMouseClick_ShiftClickExtendsSelection() {
- longPress(7);
- shiftClick(11);
- assertRangeSelection(7, 11);
- }
-
- public void testMouseClick_NoPosition_ClearsSelection() {
- longPress(7);
- click(11);
- click(RecyclerView.NO_POSITION);
- assertSelection();
- }
-
- public void testSetSelectionFocusBegin() {
- mManager.setItemsSelected(Lists.newArrayList(items.get(7)), true);
- mManager.setSelectionRangeBegin(7);
- shiftClick(11);
- assertRangeSelection(7, 11);
- }
-
- public void testLongPress_StartsSelectionMode() {
- longPress(7);
- assertSelection(items.get(7));
- }
-
- public void testLongPress_SecondPressExtendsSelection() {
- longPress(7);
- longPress(99);
- assertSelection(items.get(7), items.get(99));
- }
-
- public void testSingleTapUp_UnselectsSelectedItem() {
- longPress(7);
- tap(7);
- assertSelection();
- }
-
- public void testSingleTapUp_NoPosition_ClearsSelection() {
- longPress(7);
- tap(11);
- tap(RecyclerView.NO_POSITION);
- assertSelection();
- }
-
- public void testSingleTapUp_ExtendsSelection() {
- longPress(99);
- tap(7);
- tap(13);
- assertSelection(items.get(7), items.get(99), items.get(13));
- }
-
- public void testSingleTapUp_ShiftCreatesRangeSelection() {
- longPress(7);
- shiftTap(17);
- assertRangeSelection(7, 17);
- }
-
- public void testSingleTapUp_ShiftCreatesRangeSeletion_Backwards() {
- longPress(17);
- shiftTap(7);
- assertRangeSelection(7, 17);
- }
-
- public void testSingleTapUp_SecondShiftClickExtendsSelection() {
- longPress(7);
- shiftTap(11);
- shiftTap(17);
- assertRangeSelection(7, 17);
- }
-
- public void testSingleTapUp_MultipleContiguousRangesSelected() {
- longPress(7);
- shiftTap(11);
- tap(20);
- shiftTap(25);
- assertRangeSelected(7, 11);
- assertRangeSelected(20, 25);
- assertSelectionSize(11);
- }
-
- public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
- longPress(7);
- shiftTap(17);
- shiftTap(10);
- assertRangeSelection(7, 10);
- }
-
- public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
- mManager.onLongPress(TestInputEvent.tap(17));
- shiftTap(7);
- shiftTap(14);
- assertRangeSelection(14, 17);
- }
-
- public void testSingleTapUp_ShiftReversesSelectionDirection() {
- longPress(7);
- shiftTap(17);
- shiftTap(0);
- assertRangeSelection(0, 7);
- }
-
- public void testSingleSelectMode() {
- mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE);
- mManager.addCallback(mCallback);
- longPress(20);
- tap(13);
- assertSelection(items.get(13));
- }
-
- public void testSingleSelectMode_ShiftTap() {
- mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE);
- mManager.addCallback(mCallback);
- longPress(13);
- shiftTap(20);
- assertSelection(items.get(20));
- }
-
public void testRangeSelection() {
mManager.startRangeSelection(15);
mManager.snapRangeSelection(19);
- assertRangeSelection(15, 19);
+ mSelection.assertRangeSelection(15, 19);
}
public void testRangeSelection_snapExpand() {
mManager.startRangeSelection(15);
mManager.snapRangeSelection(19);
mManager.snapRangeSelection(27);
- assertRangeSelection(15, 27);
+ mSelection.assertRangeSelection(15, 27);
}
public void testRangeSelection_snapContract() {
mManager.startRangeSelection(15);
mManager.snapRangeSelection(27);
mManager.snapRangeSelection(19);
- assertRangeSelection(15, 19);
+ mSelection.assertRangeSelection(15, 19);
}
public void testRangeSelection_snapInvert() {
mManager.startRangeSelection(15);
mManager.snapRangeSelection(27);
mManager.snapRangeSelection(3);
- assertRangeSelection(3, 15);
+ mSelection.assertRangeSelection(3, 15);
}
public void testRangeSelection_multiple() {
@@ -215,30 +99,21 @@
mManager.endRangeSelection();
mManager.startRangeSelection(42);
mManager.snapRangeSelection(57);
- assertSelectionSize(29);
- assertRangeSelected(15, 27);
- assertRangeSelected(42, 57);
+ mSelection.assertSelectionSize(29);
+ mSelection.assertRangeSelected(15, 27);
+ mSelection.assertRangeSelected(42, 57);
}
- public void testRangeSelection_singleSelect() {
- mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE);
- mManager.addCallback(mCallback);
- mManager.startRangeSelection(11);
- mManager.snapRangeSelection(19);
- assertSelectionSize(1);
- assertSelection(items.get(19));
- }
-
public void testProvisionalSelection() {
Selection s = mManager.getSelection();
- assertSelection();
+ mSelection.assertNoSelection();
SparseBooleanArray provisional = new SparseBooleanArray();
provisional.append(1, true);
provisional.append(2, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(1), items.get(2));
+ mSelection.assertSelection(1, 2);
}
public void testProvisionalSelection_Replace() {
@@ -253,7 +128,7 @@
provisional.append(3, true);
provisional.append(4, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(3), items.get(4));
+ mSelection.assertSelection(3, 4);
}
public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
@@ -267,7 +142,7 @@
provisional.clear();
provisional.append(1, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(1));
+ mSelection.assertSelection(1);
}
public void testProvisionalSelection_Apply() {
@@ -278,12 +153,12 @@
provisional.append(2, true);
s.setProvisionalSelection(getItemIds(provisional));
s.applyProvisionalSelection();
- assertSelection(items.get(1), items.get(2));
+ mSelection.assertSelection(1, 2);
}
public void testProvisionalSelection_Cancel() {
- mManager.toggleSelection(items.get(1));
- mManager.toggleSelection(items.get(2));
+ mManager.toggleSelection(ITEMS.get(1));
+ mManager.toggleSelection(ITEMS.get(2));
Selection s = mManager.getSelection();
SparseBooleanArray provisional = new SparseBooleanArray();
@@ -293,19 +168,19 @@
s.cancelProvisionalSelection();
// Original selection should remain.
- assertSelection(items.get(1), items.get(2));
+ mSelection.assertSelection(1, 2);
}
public void testProvisionalSelection_IntersectsAppliedSelection() {
- mManager.toggleSelection(items.get(1));
- mManager.toggleSelection(items.get(2));
+ mManager.toggleSelection(ITEMS.get(1));
+ mManager.toggleSelection(ITEMS.get(2));
Selection s = mManager.getSelection();
SparseBooleanArray provisional = new SparseBooleanArray();
provisional.append(2, true);
provisional.append(3, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(1), items.get(2), items.get(3));
+ mSelection.assertSelection(1, 2, 3);
}
private static Set<String> getItemIds(SparseBooleanArray selection) {
@@ -313,82 +188,9 @@
int count = selection.size();
for (int i = 0; i < count; ++i) {
- ids.add(items.get(selection.keyAt(i)));
+ ids.add(ITEMS.get(selection.keyAt(i)));
}
return ids;
}
-
- private void longPress(int position) {
- mManager.onLongPress(TestInputEvent.tap(position));
- }
-
- private void tap(int position) {
- mManager.onSingleTapUp(TestInputEvent.tap(position));
- }
-
- private void shiftTap(int position) {
- mManager.onSingleTapUp(TestInputEvent.shiftTap(position));
- }
-
- private void click(int position) {
- mManager.onSingleTapUp(TestInputEvent.click(position));
- }
-
- private void shiftClick(int position) {
- mManager.onSingleTapUp(TestInputEvent.shiftClick(position));
- }
-
- private void assertSelected(String... expected) {
- for (int i = 0; i < expected.length; i++) {
- Selection selection = mManager.getSelection();
- String err = String.format(
- "Selection %s does not contain %s", selection, expected[i]);
- assertTrue(err, selection.contains(expected[i]));
- }
- }
-
- private void assertSelection(String... expected) {
- assertSelectionSize(expected.length);
- assertSelected(expected);
- }
-
- private void assertRangeSelected(int begin, int end) {
- for (int i = begin; i <= end; i++) {
- assertSelected(items.get(i));
- }
- }
-
- private void assertRangeSelection(int begin, int end) {
- assertSelectionSize(end - begin + 1);
- assertRangeSelected(begin, end);
- }
-
- private void assertSelectionSize(int expected) {
- Selection selection = mManager.getSelection();
- assertEquals(selection.toString(), expected, selection.size());
- }
-
- private static final class TestCallback implements MultiSelectManager.Callback {
-
- Set<String> ignored = new HashSet<>();
- private boolean mSelectionChanged = false;
-
- @Override
- public void onItemStateChanged(String modelId, boolean selected) {}
-
- @Override
- public boolean onBeforeItemStateChange(String modelId, boolean selected) {
- return !ignored.contains(modelId);
- }
-
- @Override
- public void onSelectionChanged() {
- mSelectionChanged = true;
- }
-
- void assertSelectionChanged() {
- assertTrue(mSelectionChanged);
- }
- }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SingleSelectTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SingleSelectTest.java
new file mode 100644
index 0000000..62cb1b0
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SingleSelectTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.documentsui.testing.dirlist.SelectionProbe;
+import com.android.documentsui.testing.dirlist.TestSelectionListener;
+
+import java.util.List;
+
+@SmallTest
+public class MultiSelectManager_SingleSelectTest extends AndroidTestCase {
+
+ private static final List<String> ITEMS = TestData.create(100);
+
+ private MultiSelectManager mManager;
+ private TestSelectionListener mCallback;
+ private TestDocumentsAdapter mAdapter;
+ private SelectionProbe mSelection;
+
+ @Override
+ public void setUp() throws Exception {
+ mCallback = new TestSelectionListener();
+ mAdapter = new TestDocumentsAdapter(ITEMS);
+ mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE);
+ mManager.addCallback(mCallback);
+
+ mSelection = new SelectionProbe(mManager);
+ }
+
+ public void testSimpleSelect() {
+ mManager.toggleSelection(ITEMS.get(3));
+ mManager.toggleSelection(ITEMS.get(4));
+ mCallback.assertSelectionChanged();
+ mSelection.assertSelection(4);
+ }
+
+ public void testRangeSelectionNotEstablished() {
+ mManager.toggleSelection(ITEMS.get(3));
+ mCallback.reset();
+
+ try {
+ mManager.snapRangeSelection(10);
+ fail("Should have thrown.");
+ } catch (Exception expected) {}
+
+ mCallback.assertSelectionUnchanged();
+ mSelection.assertSelection(3);
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestFocusHandler.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestFocusHandler.java
new file mode 100644
index 0000000..0585b9f
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestFocusHandler.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * A purely dummy instance of FocusHandler.
+ */
+public final class TestFocusHandler implements FocusHandler {
+
+ @Override
+ public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ }
+
+ @Override
+ public void restoreLastFocus() {
+ }
+
+ @Override
+ public int getFocusPosition() {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
index d808fe8..4c34546 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
@@ -16,19 +16,17 @@
package com.android.documentsui.dirlist;
-import static org.junit.Assert.*;
-
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.KeyEvent;
+import android.support.v7.widget.RecyclerView;
import android.view.MotionEvent;
-import android.view.View;
import com.android.documentsui.Events.InputEvent;
-import com.android.documentsui.TestInputEvent;
-import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.dirlist.UserInputHandler.DocumentDetails;
+import com.android.documentsui.testing.TestEvent;
+import com.android.documentsui.testing.TestEvent.Builder;
import com.android.documentsui.testing.TestPredicate;
+import com.android.documentsui.testing.dirlist.SelectionProbe;
import org.junit.Before;
import org.junit.Test;
@@ -42,107 +40,71 @@
private static final List<String> ITEMS = TestData.create(100);
+ private UserInputHandler<TestEvent> mInputHandler;
+
private TestDocumentsAdapter mAdapter;
- private MultiSelectManager mSelectionMgr;
+ private SelectionProbe mSelection;
private TestPredicate<DocumentDetails> mCanSelect;
private TestPredicate<InputEvent> mRightClickHandler;
private TestPredicate<DocumentDetails> mActivateHandler;
private TestPredicate<DocumentDetails> mDeleteHandler;
- private TestInputEvent mTestEvent;
- private TestDocDetails mTestDoc;
-
- private UserInputHandler mInputHandler;
+ private Builder mEvent;
@Before
public void setUp() {
mAdapter = new TestDocumentsAdapter(ITEMS);
- mSelectionMgr = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE);
+ MultiSelectManager selectionMgr =
+ new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE);
+
+ mSelection = new SelectionProbe(selectionMgr);
mCanSelect = new TestPredicate<>();
mRightClickHandler = new TestPredicate<>();
mActivateHandler = new TestPredicate<>();
mDeleteHandler = new TestPredicate<>();
- mInputHandler = new UserInputHandler(
- mSelectionMgr,
+ mInputHandler = new UserInputHandler<>(
+ selectionMgr,
new TestFocusHandler(),
(MotionEvent event) -> {
- return mTestEvent;
+ throw new UnsupportedOperationException("Not exercised in tests.");
},
- (InputEvent event) -> {
- return mTestDoc;
+ (TestEvent event) -> {
+ return event.getDocument();
},
mCanSelect,
mRightClickHandler::test,
mActivateHandler::test,
mDeleteHandler::test);
- mTestEvent = new TestInputEvent();
- mTestEvent.mouseEvent = true;
- mTestDoc = new TestDocDetails();
+ mEvent = TestEvent.builder().mouse();
}
@Test
public void testConfirmedClick_StartsSelection() {
- mTestDoc.modelId = "11";
- mInputHandler.onSingleTapConfirmed(null);
- assertSelected("11");
+ mInputHandler.onSingleTapConfirmed(mEvent.at(11).build());
+ mSelection.assertSelection(11);
+ }
+
+ @Test
+ public void testUnconfirmedClick_AddsToExistingSelection() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
+
+ mInputHandler.onSingleTapUp(mEvent.at(11).build());
+ mSelection.assertSelection(7, 11);
}
@Test
public void testDoubleClick_Activates() {
- mTestDoc.modelId = "11";
- mInputHandler.onDoubleTap(null);
- mActivateHandler.assertLastArgument(mTestDoc);
+ mInputHandler.onDoubleTap(mEvent.at(11).build());
+ mActivateHandler.assertLastArgument(mEvent.build());
}
- void assertSelected(String id) {
- Selection sel = mSelectionMgr.getSelection();
- assertTrue(sel.contains(id));
- }
-
- private final class TestDocDetails implements DocumentDetails {
-
- private String modelId;
- private int position;
- private boolean inHotspot;
-
- @Override
- public String getModelId() {
- return modelId;
- }
-
- @Override
- public int getAdapterPosition() {
- return position;
- }
-
- @Override
- public boolean isInSelectionHotspot(InputEvent event) {
- return inHotspot;
- }
-
- }
-
- private final class TestFocusHandler implements FocusHandler {
-
- @Override
- public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
- return false;
- }
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- }
-
- @Override
- public void restoreLastFocus() {
- }
-
- @Override
- public int getFocusPosition() {
- return 0;
- }
+ @Test
+ public void testClickOff_ClearsSelection() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(11).build());
+ mInputHandler.onSingleTapUp(mEvent.at(RecyclerView.NO_POSITION).build());
+ mSelection.assertNoSelection();
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
new file mode 100644
index 0000000..1d763f9
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+
+import com.android.documentsui.Events.InputEvent;
+import com.android.documentsui.dirlist.UserInputHandler.DocumentDetails;
+import com.android.documentsui.testing.TestEvent;
+import com.android.documentsui.testing.TestEvent.Builder;
+import com.android.documentsui.testing.TestPredicate;
+import com.android.documentsui.testing.dirlist.SelectionProbe;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * UserInputHandler / MultiSelectManager integration test covering the shared
+ * responsibility of range selection.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class UserInputHandler_RangeTest {
+
+ private static final List<String> ITEMS = TestData.create(100);
+
+ private UserInputHandler<TestEvent> mInputHandler;
+
+ private TestDocumentsAdapter mAdapter;
+ private SelectionProbe mSelection;
+ private TestPredicate<DocumentDetails> mCanSelect;
+ private TestPredicate<InputEvent> mRightClickHandler;
+ private TestPredicate<DocumentDetails> mActivateHandler;
+ private TestPredicate<DocumentDetails> mDeleteHandler;
+ private Builder mEvent;
+
+ @Before
+ public void setUp() {
+
+ mAdapter = new TestDocumentsAdapter(ITEMS);
+ MultiSelectManager selectionMgr =
+ new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE);
+
+ mSelection = new SelectionProbe(selectionMgr);
+ mCanSelect = new TestPredicate<>();
+ mRightClickHandler = new TestPredicate<>();
+ mActivateHandler = new TestPredicate<>();
+ mDeleteHandler = new TestPredicate<>();
+
+ mInputHandler = new UserInputHandler<>(
+ selectionMgr,
+ new TestFocusHandler(),
+ (MotionEvent event) -> {
+ throw new UnsupportedOperationException("Not exercised in tests.");
+ },
+ (TestEvent event) -> {
+ return event.getDocument();
+ },
+ mCanSelect,
+ mRightClickHandler::test,
+ mActivateHandler::test,
+ mDeleteHandler::test);
+
+ mEvent = TestEvent.builder().mouse();
+ }
+
+ @Test
+ public void testExtendRange() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
+ mSelection.assertRangeSelection(7, 11);
+ }
+
+ @Test
+ public void testExtendRangeContinues() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
+ mInputHandler.onSingleTapUp(mEvent.at(21).shift().build());
+ mSelection.assertRangeSelection(7, 21);
+ }
+
+ @Test
+ public void testMultipleContiguousRanges() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
+
+ // click without shift sets a new range start point.
+ mInputHandler.onSingleTapUp(mEvent.at(20).unshift().build());
+ mInputHandler.onSingleTapUp(mEvent.at(25).shift().build());
+
+ mSelection.assertRangeSelected(7, 11);
+ mSelection.assertRangeSelected(20, 25);
+
+ mSelection.assertRangeNotSelected(12, 19);
+ mSelection.assertSelectionSize(11);
+ }
+
+ @Test
+ public void testReducesSelectionRange() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(17).shift().build());
+ mInputHandler.onSingleTapUp(mEvent.at(10).shift().build());
+ mSelection.assertRangeSelection(7, 10);
+ }
+
+ @Test
+ public void testReducesSelectionRange_Reverse() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(17).build());
+ mInputHandler.onSingleTapUp(mEvent.at(7).shift().build());
+ mInputHandler.onSingleTapUp(mEvent.at(14).shift().build());
+ mSelection.assertRangeSelection(14, 17);
+ }
+
+ @Test
+ public void testExtendsRange_Reverse() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(12).build());
+ mInputHandler.onSingleTapUp(mEvent.at(5).shift().build());
+ mSelection.assertRangeSelection(5, 12);
+ }
+
+ @Test
+ public void testExtendsRange_ReversesAfterForwardClick() {
+ mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
+ mInputHandler.onSingleTapUp(mEvent.at(0).shift().build());
+ mSelection.assertRangeSelection(0, 7);
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
new file mode 100644
index 0000000..2d1453e
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+
+import com.android.documentsui.Events.InputEvent;
+import com.android.documentsui.dirlist.UserInputHandler.DocumentDetails;
+import com.android.documentsui.testing.TestEvent;
+import com.android.documentsui.testing.TestEvent.Builder;
+import com.android.documentsui.testing.TestPredicate;
+import com.android.documentsui.testing.dirlist.SelectionProbe;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class UserInputHandler_TouchTest {
+
+ private static final List<String> ITEMS = TestData.create(100);
+
+ private UserInputHandler<TestEvent> mInputHandler;
+
+ private TestDocumentsAdapter mAdapter;
+ private SelectionProbe mSelection;
+ private TestPredicate<DocumentDetails> mCanSelect;
+ private TestPredicate<InputEvent> mRightClickHandler;
+ private TestPredicate<DocumentDetails> mActivateHandler;
+ private TestPredicate<DocumentDetails> mDeleteHandler;
+
+ private Builder mEvent;
+
+ @Before
+ public void setUp() {
+
+ mAdapter = new TestDocumentsAdapter(ITEMS);
+ MultiSelectManager selectionMgr =
+ new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE);
+
+ mSelection = new SelectionProbe(selectionMgr);
+ mCanSelect = new TestPredicate<>();
+ mRightClickHandler = new TestPredicate<>();
+ mActivateHandler = new TestPredicate<>();
+ mDeleteHandler = new TestPredicate<>();
+
+ mInputHandler = new UserInputHandler<>(
+ selectionMgr,
+ new TestFocusHandler(),
+ (MotionEvent event) -> {
+ throw new UnsupportedOperationException("Not exercised in tests.");
+ },
+ (TestEvent event) -> {
+ return event.getDocument();
+ },
+ mCanSelect,
+ mRightClickHandler::test,
+ mActivateHandler::test,
+ mDeleteHandler::test);
+
+ mEvent = TestEvent.builder();
+ }
+
+ @Test
+ public void testTap_ActivatesWhenNoExistingSelection() {
+ mInputHandler.onSingleTapUp(mEvent.at(11).build());
+ mActivateHandler.assertLastArgument(mEvent.build());
+ }
+
+ @Test
+ public void testLongPress_StartsSelectionMode() {
+ mInputHandler.onLongPress(mEvent.at(7).build());
+ mSelection.assertSelection(7);
+ }
+
+ @Test
+ public void testLongPress_SecondPressExtendsSelection() {
+ mInputHandler.onLongPress(mEvent.at(7).build());
+ mInputHandler.onLongPress(mEvent.at(99).build());
+ mInputHandler.onLongPress(mEvent.at(13).build());
+ mSelection.assertSelection(7, 13, 99);
+ }
+
+ @Test
+ public void testTap_UnselectsSelectedItem() {
+ mInputHandler.onLongPress(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(7).build());
+ mSelection.assertNoSelection();
+ }
+
+ @Test
+ public void testTapOff_ClearsSelection() {
+ mInputHandler.onLongPress(mEvent.at(7).build());
+ mInputHandler.onSingleTapUp(mEvent.at(11).build());
+ mInputHandler.onSingleTapUp(mEvent.at(RecyclerView.NO_POSITION).build());
+ mSelection.assertNoSelection();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
index 053942b..6e4e534 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
@@ -27,7 +27,7 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.DocumentsProviderHelper;
import com.android.documentsui.StubProvider;
import com.android.documentsui.model.DocumentInfo;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
index b49d15d..d6bbe5a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
@@ -32,7 +32,7 @@
import android.test.ServiceTestCase;
import android.test.suitebuilder.annotation.MediumTest;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.testing.DocsProviders;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
index 0c273c0..1fbcf37 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
@@ -23,7 +23,7 @@
import android.app.Notification.Builder;
import android.content.Context;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/DocsProviders.java b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/DocsProviders.java
index d438892..c08157f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/DocsProviders.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/DocsProviders.java
@@ -18,7 +18,7 @@
import android.net.Uri;
-import com.android.documentsui.UrisSupplier;
+import com.android.documentsui.clipping.UrisSupplier;
import java.util.List;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestEvent.java b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestEvent.java
new file mode 100644
index 0000000..98fa2de
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestEvent.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.testing;
+
+import com.android.documentsui.Events.InputEvent;
+import com.android.documentsui.TestInputEvent;
+import com.android.documentsui.dirlist.UserInputHandler.DocumentDetails;
+
+/**
+ * Events and DocDetails are closely related. For the pursposes of this test
+ * we coalesce the two in a single, handy-dandy test class.
+ */
+public class TestEvent extends TestInputEvent implements DocumentDetails {
+
+ private String modelId;
+ private boolean inHotspot;
+
+ @Override
+ public String getModelId() {
+ return modelId;
+ }
+
+ @Override
+ public int getAdapterPosition() {
+ return getItemPosition();
+ }
+
+ @Override
+ public boolean isInSelectionHotspot(InputEvent event) {
+ return inHotspot;
+ }
+
+ public TestEvent at(int position) {
+ this.position = position; // this is both "adapter position" and "item position".
+ modelId = String.valueOf(position);
+ return this;
+ }
+
+ public TestEvent shift() {
+ this.shiftKeyDow = true;
+ return this;
+ }
+
+ public TestEvent inHotspot() {
+ this.inHotspot = true;
+ return this;
+ }
+
+ public DocumentDetails getDocument() {
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return modelId != null ? modelId.hashCode() : -1;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof TestEvent)) {
+ return false;
+ }
+
+ TestEvent other = (TestEvent) o;
+ return position == other.position
+ && modelId == other.modelId
+ && shiftKeyDow == other.shiftKeyDow
+ && mouseEvent == other.mouseEvent;
+ }
+
+ public static final Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+
+ private TestEvent mState = new TestEvent();
+
+ public Builder reset() {
+ mState = new TestEvent();
+ return this;
+ }
+
+ public Builder at(int position) {
+ mState.position = position; // this is both "adapter position" and "item position".
+ mState.modelId = String.valueOf(position);
+ return this;
+ }
+
+ public Builder shift() {
+ mState.shiftKeyDow = true;
+ return this;
+ }
+
+ public Builder unshift() {
+ mState.shiftKeyDow = false;
+ return this;
+ }
+
+ public Builder inHotspot() {
+ mState.inHotspot = true;
+ return this;
+ }
+
+ public Builder mouse() {
+ mState.mouseEvent = true;
+ return this;
+ }
+
+ public TestEvent build() {
+ // Return a copy, so nobody can mess w/ our internal state.
+ TestEvent e = new TestEvent();
+ e.position = mState.position;
+ e.modelId = mState.modelId;
+ e.shiftKeyDow = mState.shiftKeyDow;
+ e.mouseEvent = mState.mouseEvent;
+ return e;
+ }
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/dirlist/SelectionProbe.java b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/dirlist/SelectionProbe.java
new file mode 100644
index 0000000..12f4642
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/dirlist/SelectionProbe.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.testing.dirlist;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.documentsui.dirlist.MultiSelectManager;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+
+/**
+ * Helper class for making assertions against the state of a MultiSelectManager instance.
+ */
+public final class SelectionProbe {
+
+ private final MultiSelectManager mMgr;
+
+ public SelectionProbe(MultiSelectManager mgr) {
+ mMgr = mgr;
+ }
+
+ public void assertRangeSelected(int begin, int end) {
+ for (int i = begin; i <= end; i++) {
+ assertSelected(i);
+ }
+ }
+
+ public void assertRangeNotSelected(int begin, int end) {
+ for (int i = begin; i <= end; i++) {
+ assertNotSelected(i);
+ }
+ }
+
+ public void assertRangeSelection(int begin, int end) {
+ assertSelectionSize(end - begin + 1);
+ assertRangeSelected(begin, end);
+ }
+
+ public void assertSelectionSize(int expected) {
+ Selection selection = mMgr.getSelection();
+ assertEquals(selection.toString(), expected, selection.size());
+ }
+
+ public void assertNoSelection() {
+ assertSelectionSize(0);
+ }
+
+ public void assertSelection(int... ids) {
+ assertSelected(ids);
+ assertEquals(ids.length, mMgr.getSelection().size());
+ }
+
+ public void assertSelected(int... ids) {
+ Selection sel = mMgr.getSelection();
+ for (int id : ids) {
+ String sid = String.valueOf(id);
+ assertTrue(sid + " is not in selection " + sel, sel.contains(sid));
+ }
+ }
+
+ public void assertNotSelected(int... ids) {
+ Selection sel = mMgr.getSelection();
+ for (int id : ids) {
+ String sid = String.valueOf(id);
+ assertFalse(sid + " is in selection " + sel, sel.contains(sid));
+ }
+ }
+
+ public void select(int...positions) {
+ for (int position : positions) {
+ mMgr.toggleSelection(String.valueOf(position));
+ }
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/dirlist/TestSelectionListener.java b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/dirlist/TestSelectionListener.java
new file mode 100644
index 0000000..08f29f0
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/dirlist/TestSelectionListener.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.testing.dirlist;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.documentsui.dirlist.MultiSelectManager;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public final class TestSelectionListener implements MultiSelectManager.Callback {
+
+ Set<String> ignored = new HashSet<>();
+ private boolean mSelectionChanged = false;
+
+ @Override
+ public void onItemStateChanged(String modelId, boolean selected) {}
+
+ @Override
+ public boolean onBeforeItemStateChange(String modelId, boolean selected) {
+ return !ignored.contains(modelId);
+ }
+
+ @Override
+ public void onSelectionChanged() {
+ mSelectionChanged = true;
+ }
+
+ public void reset() {
+ mSelectionChanged = false;
+ }
+
+ public void assertSelectionChanged() {
+ assertTrue(mSelectionChanged);
+ }
+
+ public void assertSelectionUnchanged() {
+ assertFalse(mSelectionChanged);
+ }
+}
\ No newline at end of file
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 239f6a6..1341476 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -491,6 +491,8 @@
@Override
public void deleteDocument(String docId) throws FileNotFoundException {
final File file = getFileForDocId(docId);
+ final File visibleFile = getFileForDocId(docId, true);
+
final boolean isDirectory = file.isDirectory();
if (isDirectory) {
FileUtils.deleteContents(file);
@@ -499,7 +501,6 @@
throw new IllegalStateException("Failed to delete " + file);
}
- final File visibleFile = getFileForDocId(docId, true);
if (visibleFile != null) {
final ContentResolver resolver = getContext().getContentResolver();
final Uri externalUri = MediaStore.Files.getContentUri("external");
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 9083212..f9e2686 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -16,6 +16,8 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
LOCAL_MODULE := Keyguard
@@ -30,6 +32,8 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_JAR_EXCLUDE_FILES := none
+
include $(BUILD_STATIC_JAVA_LIBRARY)
#include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Keyguard/res/values-my-rMM/dimens.xml b/packages/Keyguard/res/values-my-rMM/dimens.xml
new file mode 100644
index 0000000..21b2a46
--- /dev/null
+++ b/packages/Keyguard/res/values-my-rMM/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<resources>
+ <dimen name="bottom_text_spacing_digital">4dp</dimen>
+</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 9d1df26..e1657c7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -127,6 +127,11 @@
super.onConfigurationChanged(newConfig);
mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
+ // Some layouts like burmese have a different margin for the clock
+ MarginLayoutParams layoutParams = (MarginLayoutParams) mClockView.getLayoutParams();
+ layoutParams.bottomMargin = getResources().getDimensionPixelSize(
+ R.dimen.bottom_text_spacing_digital);
+ mClockView.setLayoutParams(layoutParams);
mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
diff --git a/packages/Keyguard/test/Android.mk b/packages/Keyguard/test/Android.mk
index 15059c6..54224b7 100644
--- a/packages/Keyguard/test/Android.mk
+++ b/packages/Keyguard/test/Android.mk
@@ -16,6 +16,8 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := KeyguardTest
diff --git a/packages/Keyguard/test/SampleTrustAgent/Android.mk b/packages/Keyguard/test/SampleTrustAgent/Android.mk
index 2a18ee1..6ffb018 100644
--- a/packages/Keyguard/test/SampleTrustAgent/Android.mk
+++ b/packages/Keyguard/test/SampleTrustAgent/Android.mk
@@ -16,6 +16,8 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := SampleTrustAgent
@@ -27,6 +29,6 @@
# LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
include $(BUILD_PACKAGE)
diff --git a/packages/PrintSpooler/res/drawable/print_button.xml b/packages/PrintSpooler/res/drawable/print_button.xml
index b59afba..0114103 100644
--- a/packages/PrintSpooler/res/drawable/print_button.xml
+++ b/packages/PrintSpooler/res/drawable/print_button.xml
@@ -16,7 +16,7 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/print_button_tint_color">
+ android:color="?android:attr/colorControlHighlight">
<item
android:drawable="@drawable/print_button_background">
</item>
diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml
index 9b4e944..d83d364 100644
--- a/packages/PrintSpooler/res/values/colors.xml
+++ b/packages/PrintSpooler/res/values/colors.xml
@@ -16,8 +16,6 @@
<resources>
- <color name="print_button_tint_color">#EEFF41</color>
-
<color name="print_preview_scrim_color">#99000000</color>
<color name="print_preview_background_color">#F2F1F2</color>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 5b9b169..6e1385a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -94,6 +94,7 @@
// but the content has changed.
if (mNextCommand == null) {
if (mUpdateSpec.pages != null && (mDocumentInfo.changed
+ || mDocumentInfo.writtenPages == null
|| (mDocumentInfo.info.getPageCount()
!= PrintDocumentInfo.PAGE_COUNT_UNKNOWN
&& !PageRangeUtils.contains(mDocumentInfo.writtenPages,
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index 96cae5c..13c22c4 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M per logbuffer"</item>
<item msgid="5431354956856655120">"16 M per logbuffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Af"</item>
+ <item msgid="3054662377365844197">"Alles"</item>
+ <item msgid="688870735111627832">"Alles behalwe radio"</item>
+ <item msgid="2850427388488887328">"net kern"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Af"</item>
+ <item msgid="172978079776521897">"Alle loglêerbuffers"</item>
+ <item msgid="3873873912383879240">"Alles behalwe radiologlêerbuffers"</item>
+ <item msgid="8489661142527693381">"net kernloglêerbuffer"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasie af"</item>
<item msgid="6624864048416710414">"Animasieskaal .5x"</item>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 839ea32..5767829 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
<item msgid="5431354956856655120">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ጠፍቷል"</item>
+ <item msgid="3054662377365844197">"ሁሉም"</item>
+ <item msgid="688870735111627832">"ከሬዲዮ በስተቀር ሁሉም"</item>
+ <item msgid="2850427388488887328">"አውራ ከዋኝ ብቻ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ጠፍቷል"</item>
+ <item msgid="172978079776521897">"የሁሉም ምዝግብ ማስታወሻ ቋቶች"</item>
+ <item msgid="3873873912383879240">"ከሬዲዮ ምዝግብ ማስታወሻ ቋቶች በስተቀር ሁሉም"</item>
+ <item msgid="8489661142527693381">"የአውራ ከዋኝ ምዝግብ ማስታወሻ ቋት ብቻ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"እነማ ጠፍቷል"</item>
<item msgid="6624864048416710414">"የእነማ ልኬት ለውጥ.5x"</item>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 4c422d8..e3d70fe 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"٤ ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
<item msgid="5431354956856655120">"١٦ ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"إيقاف"</item>
+ <item msgid="3054662377365844197">"الكل"</item>
+ <item msgid="688870735111627832">"الكل دون اللاسلكي"</item>
+ <item msgid="2850427388488887328">"kernel فقط"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"إيقاف"</item>
+ <item msgid="172978079776521897">"كل المخازن المؤقتة للسجلات"</item>
+ <item msgid="3873873912383879240">"كل المخازن المؤقتة باستثناء مخازن سجلات اللاسلكي"</item>
+ <item msgid="8489661142527693381">"التخزين المؤقت لسجل kernel فقط"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"إيقاف الرسوم المتحركة"</item>
<item msgid="6624864048416710414">"حجم الرسوم المتحركة 0.5x"</item>
diff --git a/packages/SettingsLib/res/values-az-rAZ/arrays.xml b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
index 46795a5..396dfa1 100644
--- a/packages/SettingsLib/res/values-az-rAZ/arrays.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"hər jurnal buferinə 4M"</item>
<item msgid="5431354956856655120">"hər jurnal buferinə 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Deaktiv"</item>
+ <item msgid="3054662377365844197">"Bütün"</item>
+ <item msgid="688870735111627832">"Radiodan başqa hamısı"</item>
+ <item msgid="2850427388488887328">"yalnız kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Qeyri-aktiv"</item>
+ <item msgid="172978079776521897">"Bütün loq buferləri"</item>
+ <item msgid="3873873912383879240">"Radio loq buferlərindən başqa hamısı"</item>
+ <item msgid="8489661142527693381">"yalnız kernel loq bufferi"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasiya deaktiv"</item>
<item msgid="6624864048416710414">"Animasiya miqyası .5 x"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 5afb3c4..3e9f904 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB po međumemoriji evidencije"</item>
<item msgid="5431354956856655120">"16 MB po međumemoriji evidencije"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Isključeno"</item>
+ <item msgid="3054662377365844197">"Sve"</item>
+ <item msgid="688870735111627832">"Sve sem radija"</item>
+ <item msgid="2850427388488887328">"samo jezgro"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Isključeno"</item>
+ <item msgid="172978079776521897">"Sve međumemorije evidencija"</item>
+ <item msgid="3873873912383879240">"Sve osim međumemorija evidencija za radio"</item>
+ <item msgid="8489661142527693381">"samo međumemorija evidencije jezgra"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija je isključena"</item>
<item msgid="6624864048416710414">"Razmera animacije 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-be-rBY/arrays.xml b/packages/SettingsLib/res/values-be-rBY/arrays.xml
index e1c8257..20106ef 100644
--- a/packages/SettingsLib/res/values-be-rBY/arrays.xml
+++ b/packages/SettingsLib/res/values-be-rBY/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M на буфер журнала"</item>
<item msgid="5431354956856655120">"16M на буфер журнала"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Адключана"</item>
+ <item msgid="3054662377365844197">"Усе"</item>
+ <item msgid="688870735111627832">"Усе, акрамя радыё"</item>
+ <item msgid="2850427388488887328">"толькі ядро"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Адключана"</item>
+ <item msgid="172978079776521897">"Усе буферы журналаў"</item>
+ <item msgid="3873873912383879240">"Усе, акрамя буфераў журналаў радыё"</item>
+ <item msgid="8489661142527693381">"толькі буфер журнала ядра"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анімацыя выключаная"</item>
<item msgid="6624864048416710414">"Маштаб анімацыі 0.5x"</item>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index ba4bd0f..8e803f5 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Рег. буфер – 4 МБ"</item>
<item msgid="5431354956856655120">"Рег. буфер – 16 МБ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Изкл."</item>
+ <item msgid="3054662377365844197">"Всички"</item>
+ <item msgid="688870735111627832">"Вс. без радио"</item>
+ <item msgid="2850427388488887328">"само ядрото"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Изкл."</item>
+ <item msgid="172978079776521897">"Всички регистрационни буфери"</item>
+ <item msgid="3873873912383879240">"Всички регистрационни буфери освен тези за радиото"</item>
+ <item msgid="8489661142527693381">"само регистрационния буфер на ядрото"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимацията е изключена"</item>
<item msgid="6624864048416710414">"Скала на анимацията .5x"</item>
diff --git a/packages/SettingsLib/res/values-bn-rBD/arrays.xml b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
index 0931492..d653a97 100644
--- a/packages/SettingsLib/res/values-bn-rBD/arrays.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"লগ বাফার প্রতি ৪M"</item>
<item msgid="5431354956856655120">"লগ বাফার প্রতি ১৬M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"বন্ধ আছে"</item>
+ <item msgid="3054662377365844197">"সমস্ত"</item>
+ <item msgid="688870735111627832">"সমস্ত কিন্তু রেডিও"</item>
+ <item msgid="2850427388488887328">"শুধুমাত্র কার্নেল"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"বন্ধ আছে"</item>
+ <item msgid="172978079776521897">"সমস্ত লগ বাফার"</item>
+ <item msgid="3873873912383879240">"সমস্ত কিন্তু রেডিও লগ বাফারগুলি"</item>
+ <item msgid="8489661142527693381">"শুধুমাত্র কার্নেল লগ বাফার"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"অ্যানিমেশন বন্ধ করুন"</item>
<item msgid="6624864048416710414">"অ্যানিমেশন স্কেল .৫x"</item>
diff --git a/packages/SettingsLib/res/values-bs-rBA/arrays.xml b/packages/SettingsLib/res/values-bs-rBA/arrays.xml
index c1cf9ea..8452696 100644
--- a/packages/SettingsLib/res/values-bs-rBA/arrays.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M po međumemoriji dnevnika"</item>
<item msgid="5431354956856655120">"16M po međumemoriji dnevnika"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Isključeno"</item>
+ <item msgid="3054662377365844197">"Svi"</item>
+ <item msgid="688870735111627832">"Svi osim radija"</item>
+ <item msgid="2850427388488887328">"samo kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Isključeno"</item>
+ <item msgid="172978079776521897">"Međuspremnici svih zapisnika"</item>
+ <item msgid="3873873912383879240">"Međuspremnici svih zapisnika osim radija"</item>
+ <item msgid="8489661142527693381">"samo međuspremnik zapisnika kernela"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija isključena"</item>
<item msgid="6624864048416710414">"Animacija razmjera .5x"</item>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index 3f22fae..e4f618e 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M / memòria intermèdia reg."</item>
<item msgid="5431354956856655120">"16 M / memòria intermèdia reg."</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desactivat"</item>
+ <item msgid="3054662377365844197">"Tot"</item>
+ <item msgid="688870735111627832">"Tot menys mòbil"</item>
+ <item msgid="2850427388488887328">"només kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desactivat"</item>
+ <item msgid="172978079776521897">"Totes les memòries intermèdies de registre"</item>
+ <item msgid="3873873912383879240">"Tot menys mem. interm. de registre de senyal mòbil"</item>
+ <item msgid="8489661142527693381">"només memòria intermèdia del registre de kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animació desactivada"</item>
<item msgid="6624864048416710414">"Escala d\'animació 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index e00f9ee..b0185e8 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB na vyrovnávací paměť protokolů"</item>
<item msgid="5431354956856655120">"16 MB na vyrovnávací paměť protokolů"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Vypnuto"</item>
+ <item msgid="3054662377365844197">"Vše"</item>
+ <item msgid="688870735111627832">"Bezdrát. ne"</item>
+ <item msgid="2850427388488887328">"pouze jádro"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Vypnuto"</item>
+ <item msgid="172978079776521897">"Všechny vyrovnávací paměti protokolů"</item>
+ <item msgid="3873873912383879240">"Všechny kromě protokolu bezdrátových modulů"</item>
+ <item msgid="8489661142527693381">"pouze protokol vyrovnávací paměti jádra"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animace je vypnuta"</item>
<item msgid="6624864048416710414">"Měřítko animace 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index d930cfe..d06f39f 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB pr. logbuffer"</item>
<item msgid="5431354956856655120">"16 MB pr. logbuffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Slået fra"</item>
+ <item msgid="3054662377365844197">"Alle"</item>
+ <item msgid="688870735111627832">"Radio undtaget"</item>
+ <item msgid="2850427388488887328">"kun kerne"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Slået fra"</item>
+ <item msgid="172978079776521897">"Alle logbuffere"</item>
+ <item msgid="3873873912383879240">"Alle undtagen radiologbuffere"</item>
+ <item msgid="8489661142527693381">"kun logbuffer for kerne"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation fra"</item>
<item msgid="6624864048416710414">"Animationsskala 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index 6a83617..9a81e8f 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 Mio. pro Puffer"</item>
<item msgid="5431354956856655120">"16 Mio. pro Puffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Aus"</item>
+ <item msgid="3054662377365844197">"Alle"</item>
+ <item msgid="688870735111627832">"Alle außer Funkschnittstelle"</item>
+ <item msgid="2850427388488887328">"Nur Kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Aus"</item>
+ <item msgid="172978079776521897">"Alle Protokollzwischenspeicher"</item>
+ <item msgid="3873873912383879240">"Alle Protokollzwischenspeicher außer Funkschnittstelle"</item>
+ <item msgid="8489661142527693381">"Nur Kernelprotokoll-Zwischenspeicher"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation aus"</item>
<item msgid="6624864048416710414">"Animationsmaßstab: 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 73707ac..a6ce80a 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M ανά προσ. μν. αρχ. καταγρ."</item>
<item msgid="5431354956856655120">"16 M ανά πρ. μν. αρχ. καταγρ."</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Ανενεργό"</item>
+ <item msgid="3054662377365844197">"Όλα"</item>
+ <item msgid="688870735111627832">"Όλοι εκτός από του αποστολέα"</item>
+ <item msgid="2850427388488887328">"μόνο πυρήνας"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Ανενεργό"</item>
+ <item msgid="172978079776521897">"Όλα τα αρχεία καταγραφής προσωρινής μνήμης"</item>
+ <item msgid="3873873912383879240">"Όλα εκτός από τα αρχεία κατ.προσ.μνήμης αποστολέα"</item>
+ <item msgid="8489661142527693381">"μόνο προσωρινή μνήμη αρχείου καταγραφής πυρήνα"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Κινούμ.εικόνες απενεργοποιημένες"</item>
<item msgid="6624864048416710414">"Κλίμ. κινούμ. εικ. 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index ca5065a..2ee613f 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M per log buffer"</item>
<item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Off"</item>
+ <item msgid="3054662377365844197">"All"</item>
+ <item msgid="688870735111627832">"All but radio"</item>
+ <item msgid="2850427388488887328">"kernel only"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Off"</item>
+ <item msgid="172978079776521897">"All log buffers"</item>
+ <item msgid="3873873912383879240">"All but radio log buffers"</item>
+ <item msgid="8489661142527693381">"kernel log buffer only"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
<item msgid="6624864048416710414">"Animation scale .5x"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index ca5065a..2ee613f 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M per log buffer"</item>
<item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Off"</item>
+ <item msgid="3054662377365844197">"All"</item>
+ <item msgid="688870735111627832">"All but radio"</item>
+ <item msgid="2850427388488887328">"kernel only"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Off"</item>
+ <item msgid="172978079776521897">"All log buffers"</item>
+ <item msgid="3873873912383879240">"All but radio log buffers"</item>
+ <item msgid="8489661142527693381">"kernel log buffer only"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
<item msgid="6624864048416710414">"Animation scale .5x"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index ca5065a..2ee613f 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M per log buffer"</item>
<item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Off"</item>
+ <item msgid="3054662377365844197">"All"</item>
+ <item msgid="688870735111627832">"All but radio"</item>
+ <item msgid="2850427388488887328">"kernel only"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Off"</item>
+ <item msgid="172978079776521897">"All log buffers"</item>
+ <item msgid="3873873912383879240">"All but radio log buffers"</item>
+ <item msgid="8489661142527693381">"kernel log buffer only"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
<item msgid="6624864048416710414">"Animation scale .5x"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index fa48fbc..eae9b1b 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/búfer registro"</item>
<item msgid="5431354956856655120">"16 M/búfer registro"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desactivado"</item>
+ <item msgid="3054662377365844197">"Todo"</item>
+ <item msgid="688870735111627832">"Excepto radio"</item>
+ <item msgid="2850427388488887328">"solo kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desactivado"</item>
+ <item msgid="172978079776521897">"Todos los búferes de registro"</item>
+ <item msgid="3873873912383879240">"Todos los búferes de registro, excepto radio"</item>
+ <item msgid="8489661142527693381">"solo búfer de registro de kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
<item msgid="6624864048416710414">"Escala de animación 0.5x"</item>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 4b6bbbb..168f378 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/búfer registro"</item>
<item msgid="5431354956856655120">"16 M/búfer registro"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"No"</item>
+ <item msgid="3054662377365844197">"Todo"</item>
+ <item msgid="688870735111627832">"Todo menos señal móvil"</item>
+ <item msgid="2850427388488887328">"solo kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"No"</item>
+ <item msgid="172978079776521897">"Todos los búferes de registro"</item>
+ <item msgid="3873873912383879240">"Todo excepto búferes de registro de señal móvil"</item>
+ <item msgid="8489661142527693381">"solo búfer de registro del kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
<item msgid="6624864048416710414">"Escala de animación 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-et-rEE/arrays.xml b/packages/SettingsLib/res/values-et-rEE/arrays.xml
index b29b20f..019bf50 100644
--- a/packages/SettingsLib/res/values-et-rEE/arrays.xml
+++ b/packages/SettingsLib/res/values-et-rEE/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 000 000 / logipuhver"</item>
<item msgid="5431354956856655120">"16 000 000 / logipuhver"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Väljas"</item>
+ <item msgid="3054662377365844197">"Kõik"</item>
+ <item msgid="688870735111627832">"Kõik, v.a raadio"</item>
+ <item msgid="2850427388488887328">"ainult tuum"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Väljas"</item>
+ <item msgid="172978079776521897">"Kõik logi puhvrid"</item>
+ <item msgid="3873873912383879240">"Kõik, v.a raadiologi puhvrid"</item>
+ <item msgid="8489661142527693381">"ainult tuuma logi puhver"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatsioon väljas"</item>
<item msgid="6624864048416710414">"Animatsiooni skaala 0,5 korda"</item>
diff --git a/packages/SettingsLib/res/values-eu-rES/arrays.xml b/packages/SettingsLib/res/values-eu-rES/arrays.xml
index 3e0906b..c617445 100644
--- a/packages/SettingsLib/res/values-eu-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-eu-rES/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M erregistroen bufferreko"</item>
<item msgid="5431354956856655120">"16 M erregistroen bufferreko"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desaktibatuta"</item>
+ <item msgid="3054662377365844197">"Guztiak"</item>
+ <item msgid="688870735111627832">"Guztiak, irratiarenak izan ezik"</item>
+ <item msgid="2850427388488887328">"kernela soilik"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desaktibatuta"</item>
+ <item msgid="172978079776521897">"Erregistroen buffer guztiak"</item>
+ <item msgid="3873873912383879240">"Erregistroen buffer guztiak, irratiarenak izan ezik"</item>
+ <item msgid="8489661142527693381">"kernelaren erregistroaren bufferra soilik"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animazioa desaktibatuta"</item>
<item msgid="6624864048416710414">"Animazio-eskala: 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 97e301f..6dc8491 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"۴ میلیون در هر بافر گزارش"</item>
<item msgid="5431354956856655120">"۱۶ میلیون در هر بافر گزارش"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"خاموش"</item>
+ <item msgid="3054662377365844197">"همه"</item>
+ <item msgid="688870735111627832">"همه بهجز رادیو"</item>
+ <item msgid="2850427388488887328">"فقط هسته اصلی"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"خاموش"</item>
+ <item msgid="172978079776521897">"همه بافرهای گزارش"</item>
+ <item msgid="3873873912383879240">"همه بهجز بافرهای گزارش رادیو"</item>
+ <item msgid="8489661142527693381">"فقط بافر گزارش هسته اصلی"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"پویانمایی خاموش"</item>
<item msgid="6624864048416710414">"مقیاس پویانمایی 0.5x"</item>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 4d67954..3c2fe61 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 Mt / lokipuskuri"</item>
<item msgid="5431354956856655120">"16 Mt / lokipuskuri"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Ei käytössä"</item>
+ <item msgid="3054662377365844197">"Kaikki"</item>
+ <item msgid="688870735111627832">"Kaikki paitsi radio"</item>
+ <item msgid="2850427388488887328">"vain kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Ei käytössä"</item>
+ <item msgid="172978079776521897">"Kaikki lokipuskurit"</item>
+ <item msgid="3873873912383879240">"Kaikki paitsi radiolokipuskurit"</item>
+ <item msgid="8489661142527693381">"vain kernel-lokipuskuri"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animaatio pois käytöstä"</item>
<item msgid="6624864048416710414">"Animaatioasteikko 0,5-kertainen"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 8936e34..ba25d27 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 Mo/tampon journal"</item>
<item msgid="5431354956856655120">"16 Mo/tampon journal"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Désactivé"</item>
+ <item msgid="3054662377365844197">"Tous"</item>
+ <item msgid="688870735111627832">"Tous sauf radio"</item>
+ <item msgid="2850427388488887328">"noyau uniquement"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Désactivé"</item>
+ <item msgid="172978079776521897">"Tous les tampons de journal"</item>
+ <item msgid="3873873912383879240">"Tous les tampons de journal sauf celui de la radio"</item>
+ <item msgid="8489661142527693381">"tampon journal du noyau uniquement"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation désactivée"</item>
<item msgid="6624864048416710414">"Échelle d\'animation 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index 99f5e30..3340afb 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 Mo par tampon journal"</item>
<item msgid="5431354956856655120">"16 Mo par tampon journal"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Désactivé"</item>
+ <item msgid="3054662377365844197">"Tous"</item>
+ <item msgid="688870735111627832">"Tous sauf radio"</item>
+ <item msgid="2850427388488887328">"noyau uniquement"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Désactivé"</item>
+ <item msgid="172978079776521897">"Toutes les mémoires tampon journal"</item>
+ <item msgid="3873873912383879240">"Toutes sauf les mémoires tampon journal radio"</item>
+ <item msgid="8489661142527693381">"tampon journal du noyau uniquement"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation désactivée"</item>
<item msgid="6624864048416710414">"Échelle d\'animation x 0,5"</item>
diff --git a/packages/SettingsLib/res/values-gl-rES/arrays.xml b/packages/SettingsLib/res/values-gl-rES/arrays.xml
index 5723173..201cda2 100644
--- a/packages/SettingsLib/res/values-gl-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-gl-rES/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M por búfer de rexistro"</item>
<item msgid="5431354956856655120">"16 M por búfer de rexistro"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desactivado"</item>
+ <item msgid="3054662377365844197">"Todo"</item>
+ <item msgid="688870735111627832">"Agás radio"</item>
+ <item msgid="2850427388488887328">"só kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desactivado"</item>
+ <item msgid="172978079776521897">"Todos os búfers de rexistro"</item>
+ <item msgid="3873873912383879240">"Todo agás os búfers de rexistro de radio"</item>
+ <item msgid="8489661142527693381">"só búfer do rexistro do kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
<item msgid="6624864048416710414">"Escala de animación 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-gu-rIN/arrays.xml b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
index 16a3471..c746188 100644
--- a/packages/SettingsLib/res/values-gu-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"લૉગ બફર દીઠ 4M"</item>
<item msgid="5431354956856655120">"લૉગ બફર દીઠ 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"બંધ"</item>
+ <item msgid="3054662377365844197">"તમામ"</item>
+ <item msgid="688870735111627832">"તમામ પરંતુ રેડિઓ"</item>
+ <item msgid="2850427388488887328">"ફક્ત કર્નલ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"બંધ"</item>
+ <item msgid="172978079776521897">"તમામ લૉગ બફર્સ"</item>
+ <item msgid="3873873912383879240">"તમામ પરંતુ રેડિઓ લૉગ બફર્સ"</item>
+ <item msgid="8489661142527693381">"ફક્ત કર્નલ લૉગ બફર"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"એનિમેશન બંધ"</item>
<item msgid="6624864048416710414">"એનિમેશન સ્કેલ .5x"</item>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 6756245..29b6bef 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M प्रति लॉग बफ़र"</item>
<item msgid="5431354956856655120">"16M प्रति लॉग बफ़र"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"बंद"</item>
+ <item msgid="3054662377365844197">"सभी"</item>
+ <item msgid="688870735111627832">"रेडियो छोड़कर सभी"</item>
+ <item msgid="2850427388488887328">"केवल कर्नल"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"बंद"</item>
+ <item msgid="172978079776521897">"सभी लॉग बफ़र"</item>
+ <item msgid="3873873912383879240">"रेडियो लॉग बफ़र को छोड़कर सभी"</item>
+ <item msgid="8489661142527693381">"केवल कर्नल लॉग बफ़र"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"एनिमेशन बंद"</item>
<item msgid="6624864048416710414">"एनिमेशन स्केल .5x"</item>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 792d45c..a2d253c 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB po međusprem. zapisnika"</item>
<item msgid="5431354956856655120">"16 MB po međusprem. zapisnika"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Isključeno"</item>
+ <item msgid="3054662377365844197">"Sve"</item>
+ <item msgid="688870735111627832">"Sve osim radija"</item>
+ <item msgid="2850427388488887328">"samo jezgra"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Isključeno"</item>
+ <item msgid="172978079776521897">"Svi međuspremnici zapisa"</item>
+ <item msgid="3873873912383879240">"Sve osim međuspremnika zapisnika radija"</item>
+ <item msgid="8489661142527693381">"samo međuspremnik zapisnika jezgre"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija isključena"</item>
<item msgid="6624864048416710414">"Brzina animacije 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 36cf322..41ce4b0 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB/naplópuffer"</item>
<item msgid="5431354956856655120">"16 MB/naplópuffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Kikapcsolva"</item>
+ <item msgid="3054662377365844197">"Összes"</item>
+ <item msgid="688870735111627832">"Rádiót kivéve"</item>
+ <item msgid="2850427388488887328">"csak kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Kikapcsolva"</item>
+ <item msgid="172978079776521897">"Minden naplópuffer"</item>
+ <item msgid="3873873912383879240">"A rádiónapló-pufferen kívül mindegyik"</item>
+ <item msgid="8489661142527693381">"csak kernelnaplópuffer"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animáció ki"</item>
<item msgid="6624864048416710414">"Animáció tempója: 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
index da7362b..e93cbfc 100644
--- a/packages/SettingsLib/res/values-hy-rAM/arrays.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Պահնակ՝ առավ. 4ՄԲ"</item>
<item msgid="5431354956856655120">"Պահնակ՝ առավ. 16ՄԲ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Անջատված է"</item>
+ <item msgid="3054662377365844197">"Բոլորը"</item>
+ <item msgid="688870735111627832">"Բոլորը, ռադիոյից բացի"</item>
+ <item msgid="2850427388488887328">"միայն միջուկը"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Անջատված է"</item>
+ <item msgid="172978079776521897">"Մատյանի բոլոր բուֆերները"</item>
+ <item msgid="3873873912383879240">"Մատյանի բոլոր բուֆերները, ռադիո բուֆերներից բացի"</item>
+ <item msgid="8489661142527693381">"միայն միջուկի մատյանի պահնակը"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Անջատել շարժապատկերը"</item>
<item msgid="6624864048416710414">"Շարժապատկերի սանդղակը` .5x"</item>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 8c8ae11..a612639 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/penyangga log"</item>
<item msgid="5431354956856655120">"16 M/penyangga log"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Nonaktif"</item>
+ <item msgid="3054662377365844197">"Semua"</item>
+ <item msgid="688870735111627832">"Selain radio"</item>
+ <item msgid="2850427388488887328">"khusus kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Nonaktif"</item>
+ <item msgid="172978079776521897">"Semua penyangga log"</item>
+ <item msgid="3873873912383879240">"Semua kecuali penyangga log radio"</item>
+ <item msgid="8489661142527693381">"khusus penyangga log kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasi mati"</item>
<item msgid="6624864048416710414">"Skala animasi 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-is-rIS/arrays.xml b/packages/SettingsLib/res/values-is-rIS/arrays.xml
index b6f9243..64d4da2 100644
--- a/packages/SettingsLib/res/values-is-rIS/arrays.xml
+++ b/packages/SettingsLib/res/values-is-rIS/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/biðminni"</item>
<item msgid="5431354956856655120">"16 M/biðminni"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Slökkt"</item>
+ <item msgid="3054662377365844197">"Allt"</item>
+ <item msgid="688870735111627832">"Allt n. útvarp"</item>
+ <item msgid="2850427388488887328">"einungis kjarni"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Slökkt"</item>
+ <item msgid="172978079776521897">"Allt biðminni"</item>
+ <item msgid="3873873912383879240">"Allt nema útvarpsbiðminni"</item>
+ <item msgid="8489661142527693381">"einungis kjarnaannálabiðminni"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Slökkt á hreyfiáhrifum"</item>
<item msgid="6624864048416710414">"Lengd hreyfiáhrifa 5x"</item>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 09e2231..e6938e0 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB/buffer log"</item>
<item msgid="5431354956856655120">"16 MB/buffer log"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Off"</item>
+ <item msgid="3054662377365844197">"Tutti"</item>
+ <item msgid="688870735111627832">"Tutti tranne il segnale radio"</item>
+ <item msgid="2850427388488887328">"solo kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Off"</item>
+ <item msgid="172978079776521897">"Tutti i buffer log"</item>
+ <item msgid="3873873912383879240">"Tutti tranne i buffer log del segnale radio"</item>
+ <item msgid="8489661142527693381">"solo buffer log kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animazione disattivata"</item>
<item msgid="6624864048416710414">"Scala animazione 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 151d16e..7bd46ad 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M לכל מאגר יומן"</item>
<item msgid="5431354956856655120">"16M לכל מאגר יומן"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"כבוי"</item>
+ <item msgid="3054662377365844197">"הכול"</item>
+ <item msgid="688870735111627832">"הכול מלבד רדיו"</item>
+ <item msgid="2850427388488887328">"ליבה בלבד"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"כבוי"</item>
+ <item msgid="172978079776521897">"כל מאגרי הנתונים הזמניים של היומן"</item>
+ <item msgid="3873873912383879240">"הכול מלבד מאגרי הנתונים הזמניים של יומן הרדיו"</item>
+ <item msgid="8489661142527693381">"מאגר נתונים זמני של היומן השמור בליבה בלבד"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"אנימציה כבויה"</item>
<item msgid="6624864048416710414">"קנה מידה לאנימציה 5x."</item>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index d8a8a0a..5b9b41c 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M / ログバッファ"</item>
<item msgid="5431354956856655120">"16 M / ログバッファ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"OFF"</item>
+ <item msgid="3054662377365844197">"すべて"</item>
+ <item msgid="688870735111627832">"ラジオ以外すべて"</item>
+ <item msgid="2850427388488887328">"カーネルのみ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"OFF"</item>
+ <item msgid="172978079776521897">"すべてのログバッファ"</item>
+ <item msgid="3873873912383879240">"ラジオ ログバッファ以外すべて"</item>
+ <item msgid="8489661142527693381">"カーネル ログ バッファのみ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"アニメーションオフ"</item>
<item msgid="6624864048416710414">"アニメーションスケール.5x"</item>
diff --git a/packages/SettingsLib/res/values-ka-rGE/arrays.xml b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
index d6213c1..5e63ddd 100644
--- a/packages/SettingsLib/res/values-ka-rGE/arrays.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 მბაიტი / ჟურნალის ბუფერი"</item>
<item msgid="5431354956856655120">"16 მბაიტი / ჟურნალის ბუფერი"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"გამორთული"</item>
+ <item msgid="3054662377365844197">"ყველა"</item>
+ <item msgid="688870735111627832">"რადიოს გარდა ყველა"</item>
+ <item msgid="2850427388488887328">"მხოლოდ ბირთვი"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"გამორთული"</item>
+ <item msgid="172978079776521897">"ჟურნალების ყველა ბუფერი"</item>
+ <item msgid="3873873912383879240">"რადიოჟურნალების ბუფერების გარდა ყველა"</item>
+ <item msgid="8489661142527693381">"მხოლოდ ბირთვის ჟურნალის ბუფერი"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ანიმაციის გამორთვა"</item>
<item msgid="6624864048416710414">"ანიმაციის სიჩქარე .5x"</item>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
index e876a3d..d1dae87 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Әр журнал буферіне 4 МБ"</item>
<item msgid="5431354956856655120">"Әр журнал буферіне 16 МБ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Өшірулі"</item>
+ <item msgid="3054662377365844197">"Барлығы"</item>
+ <item msgid="688870735111627832">"Радиодан басқасының барлығы"</item>
+ <item msgid="2850427388488887328">"тек ядро"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Өшірулі"</item>
+ <item msgid="172978079776521897">"Барлық журнал буфері"</item>
+ <item msgid="3873873912383879240">"Радио журналының буферлерінен басқасының барлығы"</item>
+ <item msgid="8489661142527693381">"тек ядро журналының буфері"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Aнимация өшірілген"</item>
<item msgid="6624864048416710414">"Aнимация өлшемі .5x"</item>
diff --git a/packages/SettingsLib/res/values-km-rKH/arrays.xml b/packages/SettingsLib/res/values-km-rKH/arrays.xml
index 000f3c0..17371f6 100644
--- a/packages/SettingsLib/res/values-km-rKH/arrays.xml
+++ b/packages/SettingsLib/res/values-km-rKH/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M per log buffer"</item>
<item msgid="5431354956856655120">"16M per log buffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"បិទ"</item>
+ <item msgid="3054662377365844197">"ទាំងអស់"</item>
+ <item msgid="688870735111627832">"ទាំងអស់ក្រៅពីវិទ្យុ"</item>
+ <item msgid="2850427388488887328">"kernel តែប៉ុណ្ណោះ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"បិទ"</item>
+ <item msgid="172978079776521897">"អង្គចងចាំកំណត់ហេតុបណ្តោះអាសន្នទាំងអស់"</item>
+ <item msgid="3873873912383879240">"ទាំងអស់ក្រៅពីអង្គចងចាំកំណត់ហេតុវិទ្យុបណ្តោះអាសន្ន"</item>
+ <item msgid="8489661142527693381">"អង្គចងចាំបណ្ដោះអាសន្នកំណត់ហេតុ kernel តែប៉ុណ្ណោះ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"បិទចលនា"</item>
<item msgid="6624864048416710414">"មាត្រដ្ឋានចលនា .5x"</item>
diff --git a/packages/SettingsLib/res/values-kn-rIN/arrays.xml b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
index 5c38077..5f6d699 100644
--- a/packages/SettingsLib/res/values-kn-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 4M"</item>
<item msgid="5431354956856655120">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ಆಫ್"</item>
+ <item msgid="3054662377365844197">"ಎಲ್ಲಾ"</item>
+ <item msgid="688870735111627832">"ಎಲ್ಲಾ ಆದರೆ ರೇಡಿಯೊ"</item>
+ <item msgid="2850427388488887328">"ಕೆರ್ನಲ್ ಮಾತ್ರ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ಆಫ್ ಆಗಿದೆ"</item>
+ <item msgid="172978079776521897">"ಎಲ್ಲಾ ಲಾಗ್ ಬಫರ್ಗಳು"</item>
+ <item msgid="3873873912383879240">"ಎಲ್ಲಾ ಆದರೆ ರೇಡಿಯೊ ಲಾಗ್ ಬಫರ್ಗಳು"</item>
+ <item msgid="8489661142527693381">"ಕೆರ್ನಲ್ ಲಾಗ್ ಬಫರ್ ಮಾತ್ರ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ಆನಿಮೇಶನ್ ಆಫ್"</item>
<item msgid="6624864048416710414">"ಅನಿಮೇಶನ್ ಮಾಪಕ .5x"</item>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index c3f4a02..596f93e 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"로그 버퍼당 4M"</item>
<item msgid="5431354956856655120">"로그 버퍼당 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"사용 안함"</item>
+ <item msgid="3054662377365844197">"전체"</item>
+ <item msgid="688870735111627832">"라디오 외 모두"</item>
+ <item msgid="2850427388488887328">"커널만"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"사용 안함"</item>
+ <item msgid="172978079776521897">"모든 로그 버퍼"</item>
+ <item msgid="3873873912383879240">"라디오 로그 버퍼를 제외한 모든 버퍼"</item>
+ <item msgid="8489661142527693381">"커널 로그 버퍼만"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"애니메이션 사용 안함"</item>
<item msgid="6624864048416710414">"애니메이션 배율 .5x"</item>
diff --git a/packages/SettingsLib/res/values-ky-rKG/arrays.xml b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
index 0676414..33a0b5d 100644
--- a/packages/SettingsLib/res/values-ky-rKG/arrays.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Буфер: 4М ашпашы керек"</item>
<item msgid="5431354956856655120">"Буфер: 16М ашпашы керек"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Өчүк"</item>
+ <item msgid="3054662377365844197">"Бардыгы"</item>
+ <item msgid="688870735111627832">"Радиодон башка"</item>
+ <item msgid="2850427388488887328">"өзөк гана"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Өчүк"</item>
+ <item msgid="172978079776521897">"Бардык таржымал буферлери"</item>
+ <item msgid="3873873912383879240">"Радио таржымал буферлеринен башкаларынын баары"</item>
+ <item msgid="8489661142527693381">"өзөктүк журнал буфери гана"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимацияны өчүрүү"</item>
<item msgid="6624864048416710414">"Анимация масштабы .5x"</item>
diff --git a/packages/SettingsLib/res/values-lo-rLA/arrays.xml b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
index 46911c7..7a6b77a 100644
--- a/packages/SettingsLib/res/values-lo-rLA/arrays.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"ບັບເຟີ 4M ຕໍ່ບັນທຶກ"</item>
<item msgid="5431354956856655120">"ບັບເຟີ 16M ຕໍ່ບັນທຶກ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ປິດ"</item>
+ <item msgid="3054662377365844197">"ທັງໝົດ"</item>
+ <item msgid="688870735111627832">"ທັງໝົດຍົກເວັ້ນວິທະຍຸ"</item>
+ <item msgid="2850427388488887328">"ເຄີນເນວເທົ່ານັ້ນ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ປິດ"</item>
+ <item msgid="172978079776521897">"ບັບເຟີບັນທຶກທັງໝົດ"</item>
+ <item msgid="3873873912383879240">"ທັງໝົດຍົກເວັ້ນບັບເຟີບັນທຶກວິທະຍຸ"</item>
+ <item msgid="8489661142527693381">"ບັບເຟີບັນທຶກເຄີນເນວເທົ່ານັ້ນ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ປິດອະນິເມຊັນ"</item>
<item msgid="6624864048416710414">"ຂະໜາດອະນິເມຊັນ .5x"</item>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 4fad399..49908ad 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB žurnalo buferis"</item>
<item msgid="5431354956856655120">"16 MB žurnalo buferis"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Išjungta"</item>
+ <item msgid="3054662377365844197">"Viskas"</item>
+ <item msgid="688870735111627832">"Viskas, išsk. rad. r."</item>
+ <item msgid="2850427388488887328">"tik branduolys"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Išjungta"</item>
+ <item msgid="172978079776521897">"Visi žurnalų buferiai"</item>
+ <item msgid="3873873912383879240">"Visi, išskyrus radijo ryšio žurnalų buferius"</item>
+ <item msgid="8489661142527693381">"tik branduolio žurnalo buferis"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija išjungta"</item>
<item msgid="6624864048416710414">"Animacijos mastelis 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-mk-rMK/arrays.xml b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
index a6c5ac0..a72bcd3 100644
--- a/packages/SettingsLib/res/values-mk-rMK/arrays.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/меѓумеморија"</item>
<item msgid="5431354956856655120">"16 M/меѓумеморија"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Исклучено"</item>
+ <item msgid="3054662377365844197">"Сите"</item>
+ <item msgid="688870735111627832">"Сите освен радио"</item>
+ <item msgid="2850427388488887328">"само јадро"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Исклучено"</item>
+ <item msgid="172978079776521897">"Привремена меморија на целата евиденција"</item>
+ <item msgid="3873873912383879240">"Привремена мем. на цела евиденција освен за радио"</item>
+ <item msgid="8489661142527693381">"само привремена меморија за евиденција на јадро"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Без анимација"</item>
<item msgid="6624864048416710414">"Опсег на анимација 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-ml-rIN/arrays.xml b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
index bbad21c..ac6841e 100644
--- a/packages/SettingsLib/res/values-ml-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
<item msgid="5431354956856655120">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ഓഫ്"</item>
+ <item msgid="3054662377365844197">"എല്ലാം"</item>
+ <item msgid="688870735111627832">"റേഡിയോ ഒഴികെയുള്ള എല്ലാം"</item>
+ <item msgid="2850427388488887328">"കേർനൽ മാത്രം"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ഓഫ്"</item>
+ <item msgid="172978079776521897">"എല്ലാ ലോഗ് ബഫറുകളും"</item>
+ <item msgid="3873873912383879240">"റേഡിയോ ലോഗ് ബഫറുകൾ ഒഴികെയുള്ള എല്ലാം"</item>
+ <item msgid="8489661142527693381">"കേർനൽ ലോഗ് ബഫർ മാത്രം"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ആനിമേഷൻ ഓഫുചെയ്യുക"</item>
<item msgid="6624864048416710414">"ആനിമേഷൻ സ്കെയിൽ .5x"</item>
diff --git a/packages/SettingsLib/res/values-mn-rMN/arrays.xml b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
index f470ca8..e812043 100644
--- a/packages/SettingsLib/res/values-mn-rMN/arrays.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"лог буфер бүрт 4M"</item>
<item msgid="5431354956856655120">"лог буфер бүрт 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Идэвхгүй"</item>
+ <item msgid="3054662377365844197">"Бүгд"</item>
+ <item msgid="688870735111627832">"Радиогоос бусад бүх"</item>
+ <item msgid="2850427388488887328">"зөвхөн төвд"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Идэвхгүй"</item>
+ <item msgid="172978079776521897">"Бүх логийн хамгаалалт"</item>
+ <item msgid="3873873912383879240">"Радиогоос бусад бүх логийн хамгаалалт"</item>
+ <item msgid="8489661142527693381">"зөвхөн үйлдлийн системийн төв логийн хамгаалалтад"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Дүрс амилуулалт идэвхгүй"</item>
<item msgid="6624864048416710414">"Дүрс амилуулах далайц .5x"</item>
diff --git a/packages/SettingsLib/res/values-mr-rIN/arrays.xml b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
index 765f650..5de2f49 100644
--- a/packages/SettingsLib/res/values-mr-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"प्रति लॉग बफर 4M"</item>
<item msgid="5431354956856655120">"प्रति लॉग बफर 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"बंद"</item>
+ <item msgid="3054662377365844197">"सर्व"</item>
+ <item msgid="688870735111627832">"सर्व परंतु रेडिओ"</item>
+ <item msgid="2850427388488887328">"फक्त कर्नेल"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"बंद"</item>
+ <item msgid="172978079776521897">"सर्व लॉग बफर"</item>
+ <item msgid="3873873912383879240">"सर्व परंतु रेडिओ लॉग बफर"</item>
+ <item msgid="8489661142527693381">"फक्त कर्नेल लॉग बफर"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"अॅनिमेशन बंद"</item>
<item msgid="6624864048416710414">"अॅनिमेशन स्केल .5x"</item>
diff --git a/packages/SettingsLib/res/values-ms-rMY/arrays.xml b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
index 2e31792..d6ea50c 100644
--- a/packages/SettingsLib/res/values-ms-rMY/arrays.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M per penimbal log"</item>
<item msgid="5431354956856655120">"16M per penimbal log"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Mati"</item>
+ <item msgid="3054662377365844197">"Semua"</item>
+ <item msgid="688870735111627832">"Sma kcli radio"</item>
+ <item msgid="2850427388488887328">"inti sahaja"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Mati"</item>
+ <item msgid="172978079776521897">"Semua penimbal log"</item>
+ <item msgid="3873873912383879240">"Semua kecuali penimbal log radio"</item>
+ <item msgid="8489661142527693381">"penimbal log inti sahaja"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasi dimatikan"</item>
<item msgid="6624864048416710414">"Skala animasi .5x"</item>
diff --git a/packages/SettingsLib/res/values-my-rMM/arrays.xml b/packages/SettingsLib/res/values-my-rMM/arrays.xml
index 41a59ff..7ba8e94 100644
--- a/packages/SettingsLib/res/values-my-rMM/arrays.xml
+++ b/packages/SettingsLib/res/values-my-rMM/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 4M"</item>
<item msgid="5431354956856655120">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ပိတ်ပါ"</item>
+ <item msgid="3054662377365844197">"အားလုံး"</item>
+ <item msgid="688870735111627832">"ရေဒီယိုမှလွဲ၍ အားလုံး"</item>
+ <item msgid="2850427388488887328">"ကာနယ်သာ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ပိတ်ပါ"</item>
+ <item msgid="172978079776521897">"မှတ်တမ်းသိမ်းဆည်းရန် လျာထားချက်များ အားလုံး"</item>
+ <item msgid="3873873912383879240">"ရေဒီယို မှတ်တမ်းသိမ်းဆည်းရန်လျာထားချက်မှလွဲ၍ အားလုံး"</item>
+ <item msgid="8489661142527693381">"ကာနယ်မှတ်တမ်းသိမ်းဆည်းရန် လျာထားချက်သာ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"လှုပ်ရှားသက်ဝင်မှုပုံများကိုပိတ်ပါ"</item>
<item msgid="6624864048416710414">"လှုပ်ရှားသက်ဝင်မှုပုံ စကေး ၅ဆ"</item>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 7c33b14..bc4ff27 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M per loggbuffer"</item>
<item msgid="5431354956856655120">"16M per loggbuffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Av"</item>
+ <item msgid="3054662377365844197">"Alle"</item>
+ <item msgid="688870735111627832">"Unntatt radio"</item>
+ <item msgid="2850427388488887328">"bare kjerne"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Av"</item>
+ <item msgid="172978079776521897">"Alle loggbuffere"</item>
+ <item msgid="3873873912383879240">"Alle unntatt radiologgbuffere"</item>
+ <item msgid="8489661142527693381">"bare kjerneloggbuffer"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasjon av"</item>
<item msgid="6624864048416710414">"Animasjonsskala 0,5 x"</item>
diff --git a/packages/SettingsLib/res/values-ne-rNP/arrays.xml b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
index eb63951..2063f17 100644
--- a/packages/SettingsLib/res/values-ne-rNP/arrays.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"४एम प्रति लग बफर"</item>
<item msgid="5431354956856655120">"१६एम प्रति लग बफर"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"निष्क्रिय"</item>
+ <item msgid="3054662377365844197">"सबै"</item>
+ <item msgid="688870735111627832">"रेडियो बाहेक सबै"</item>
+ <item msgid="2850427388488887328">"कर्नेल मात्र"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"निष्क्रिय"</item>
+ <item msgid="172978079776521897">"सबै लग सम्बन्धी बफरहरू"</item>
+ <item msgid="3873873912383879240">"रेडियो सम्बन्धी लगका बफरहरू बाहेक सबै"</item>
+ <item msgid="8489661142527693381">"कर्नेलको लग सम्बन्धी बफर मात्र"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"सजीविकरण बन्द"</item>
<item msgid="6624864048416710414">"सजीविकरण मापन .5x"</item>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index 504b3d8..4cdd4fa 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M per logbuffer"</item>
<item msgid="5431354956856655120">"16 M per logbuffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Uit"</item>
+ <item msgid="3054662377365844197">"Alle"</item>
+ <item msgid="688870735111627832">"Alle beh. keuzerondje"</item>
+ <item msgid="2850427388488887328">"alleen kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Uit"</item>
+ <item msgid="172978079776521897">"Alle logboekbuffers"</item>
+ <item msgid="3873873912383879240">"Alle logboekbuffers behalve voor keuzerondjes"</item>
+ <item msgid="8489661142527693381">"alleen kernel-logbuffer"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatie uit"</item>
<item msgid="6624864048416710414">"Animatieschaal 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-pa-rIN/arrays.xml b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
index 2f6dd7a..d0a26c8 100644
--- a/packages/SettingsLib/res/values-pa-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
<item msgid="5431354956856655120">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ਬੰਦ"</item>
+ <item msgid="3054662377365844197">"ਸਭ"</item>
+ <item msgid="688870735111627832">"ਸਭ ਪਰ ਰੇਡੀਓ"</item>
+ <item msgid="2850427388488887328">"ਸਿਰਫ਼ ਕਰਨਲ"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ਬੰਦ"</item>
+ <item msgid="172978079776521897">"ਸਭ ਲੌਗ ਬਫ਼ਰ"</item>
+ <item msgid="3873873912383879240">"ਸਭ ਪਰ ਰੇਡੀਓ ਲੌਗ ਬਫ਼ਰ"</item>
+ <item msgid="8489661142527693381">"ਸਿਰਫ਼ ਕਰਨਲ ਲੌਗ ਬਫ਼ਰ"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ਐਨੀਮੇਸ਼ਨ ਬੰਦ"</item>
<item msgid="6624864048416710414">"ਐਨੀਮੇਸ਼ਨ ਸਕੇਲ .5x"</item>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 8786a3e..ff36e42 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB/bufor dziennika"</item>
<item msgid="5431354956856655120">"16 MB/bufor dziennika"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Wyłączone"</item>
+ <item msgid="3054662377365844197">"Wszystkie"</item>
+ <item msgid="688870735111627832">"Bez radiowych"</item>
+ <item msgid="2850427388488887328">"tylko jądro"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Wyłączone"</item>
+ <item msgid="172978079776521897">"Wszystkie bufory dziennika"</item>
+ <item msgid="3873873912383879240">"Wszystkie oprócz buforów dzienników radiowych"</item>
+ <item msgid="8489661142527693381">"tylko bufor dziennika jądra"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacja wyłączona"</item>
<item msgid="6624864048416710414">"Skala animacji 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index 1e79c30..90f061c 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/buffer de log"</item>
<item msgid="5431354956856655120">"16 M/buffer de log"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desativado"</item>
+ <item msgid="3054662377365844197">"Todos"</item>
+ <item msgid="688870735111627832">"Todos, exceto o rádio"</item>
+ <item msgid="2850427388488887328">"somente kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desativado"</item>
+ <item msgid="172978079776521897">"Todos os buffers de registro"</item>
+ <item msgid="3873873912383879240">"Todos, exceto os buffers de registro de rádio"</item>
+ <item msgid="8489661142527693381">"somente buffer de registro de kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desligada"</item>
<item msgid="6624864048416710414">"Escala da animação 0,5 x"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index b67d661..2c8b835 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M por buffer de registo"</item>
<item msgid="5431354956856655120">"16 M por buffer de registo"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desativado"</item>
+ <item msgid="3054662377365844197">"Todos"</item>
+ <item msgid="688870735111627832">"Td, exc. rádio"</item>
+ <item msgid="2850427388488887328">"apenas kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desativado"</item>
+ <item msgid="172978079776521897">"Todos os buffers de registo"</item>
+ <item msgid="3873873912383879240">"Todos, exceto os buffers de registo de rádio"</item>
+ <item msgid="8489661142527693381">"apenas buffer do registo do kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desativada"</item>
<item msgid="6624864048416710414">"Escala de animação 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index 1e79c30..90f061c 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/buffer de log"</item>
<item msgid="5431354956856655120">"16 M/buffer de log"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Desativado"</item>
+ <item msgid="3054662377365844197">"Todos"</item>
+ <item msgid="688870735111627832">"Todos, exceto o rádio"</item>
+ <item msgid="2850427388488887328">"somente kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Desativado"</item>
+ <item msgid="172978079776521897">"Todos os buffers de registro"</item>
+ <item msgid="3873873912383879240">"Todos, exceto os buffers de registro de rádio"</item>
+ <item msgid="8489661142527693381">"somente buffer de registro de kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desligada"</item>
<item msgid="6624864048416710414">"Escala da animação 0,5 x"</item>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index 8c32593..d5574dd 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB/zonă-tampon de înregistrări în jurnal"</item>
<item msgid="5431354956856655120">"16 MB/zonă-tampon de înregistrări în jurnal"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Dezactivată"</item>
+ <item msgid="3054662377365844197">"Toate"</item>
+ <item msgid="688870735111627832">"Toate, fără radio"</item>
+ <item msgid="2850427388488887328">"numai nucleul"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Dezactivată"</item>
+ <item msgid="172978079776521897">"Toate zonele-tampon pentru jurnale"</item>
+ <item msgid="3873873912383879240">"Toate zonele-tampon pentru jurnale fără cele radio"</item>
+ <item msgid="8489661142527693381">"numai zona-tampon pentru jurnalul nucleului"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animație dezactivată"</item>
<item msgid="6624864048416710414">"Animație la scara 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index 7d0dd6c..2fff9dd 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Буфер: макс. 4 МБ"</item>
<item msgid="5431354956856655120">"Буфер: макс. 16 МБ"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Отключено"</item>
+ <item msgid="3054662377365844197">"Все"</item>
+ <item msgid="688870735111627832">"Все, кроме системных"</item>
+ <item msgid="2850427388488887328">"только ядро"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Отключено"</item>
+ <item msgid="172978079776521897">"Все буферы журналов"</item>
+ <item msgid="3873873912383879240">"Все, кроме буферов системного журнала"</item>
+ <item msgid="8489661142527693381">"только буфер журнала ядра"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Без анимации"</item>
<item msgid="6624864048416710414">"Анимация 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-si-rLK/arrays.xml b/packages/SettingsLib/res/values-si-rLK/arrays.xml
index c4a6550..518a330 100644
--- a/packages/SettingsLib/res/values-si-rLK/arrays.xml
+++ b/packages/SettingsLib/res/values-si-rLK/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"ලොග අන්තරාවකට 4M"</item>
<item msgid="5431354956856655120">"ලොග අන්තරාවකට 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ක්රියාවිරහිතය"</item>
+ <item msgid="3054662377365844197">"සියලු"</item>
+ <item msgid="688870735111627832">"සැම වුවද රේඩි."</item>
+ <item msgid="2850427388488887328">"කර්නල පමණි"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ක්රියාවිරහිතයි"</item>
+ <item msgid="172978079776521897">"සියලු ලොග අන්තරාචය"</item>
+ <item msgid="3873873912383879240">"සියලු නමුත් රේඩියෝ ලොග අන්තරාචය"</item>
+ <item msgid="8489661142527693381">"කර්නල ලොග් අන්තරාචය පමණි"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"සජිවිකරණය අක්රිය කිරීම"</item>
<item msgid="6624864048416710414">"සජීවීකරණ පරිමාණය .5x"</item>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 3e9ced6..2848040 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB na vyrov. pamäť denníka"</item>
<item msgid="5431354956856655120">"16 MB na vyrov. pamäť denníka"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Vypnuté"</item>
+ <item msgid="3054662377365844197">"Všetko"</item>
+ <item msgid="688870735111627832">"Okrem rádia"</item>
+ <item msgid="2850427388488887328">"iba jadro"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Vypnuté"</item>
+ <item msgid="172978079776521897">"Všetky vyrovnávacie pamäte denníka"</item>
+ <item msgid="3873873912383879240">"Všetky vyrovnávacie pamäte denníka (okrem rádia)"</item>
+ <item msgid="8489661142527693381">"iba vyrovnávacia pamäť denníka jadra"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animácia je vypnutá"</item>
<item msgid="6624864048416710414">"Mierka animácie 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 705f6e6..baa16ac 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M/medpomnilnik dnevnika"</item>
<item msgid="5431354956856655120">"16 M/medpomnilnik dnevnika"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Izklopljeno"</item>
+ <item msgid="3054662377365844197">"Vse"</item>
+ <item msgid="688870735111627832">"Vse (brez rad.)"</item>
+ <item msgid="2850427388488887328">"samo jedro"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Izklopljeno"</item>
+ <item msgid="172978079776521897">"Vsi medpomnilniki dnevnika"</item>
+ <item msgid="3873873912383879240">"Vsi medpomnilniki dnevnika, razen za radio"</item>
+ <item msgid="8489661142527693381">"samo medpomnilnik dnevnika jedra"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija je izključena"</item>
<item msgid="6624864048416710414">"Merilo animacije: 0,5 x"</item>
diff --git a/packages/SettingsLib/res/values-sq-rAL/arrays.xml b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
index 07b92557..c40ad83 100644
--- a/packages/SettingsLib/res/values-sq-rAL/arrays.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 milionë/memorie regjistrimi"</item>
<item msgid="5431354956856655120">"16 milionë/memorie regjistrimi"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Joaktive"</item>
+ <item msgid="3054662377365844197">"Të gjitha"</item>
+ <item msgid="688870735111627832">"Të gjitha përveç atyre radio"</item>
+ <item msgid="2850427388488887328">"vetëm bërthama"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Joaktive"</item>
+ <item msgid="172978079776521897">"Të gjitha memoriet e regjistrit"</item>
+ <item msgid="3873873912383879240">"Të gjitha memoriet e regjistrit, përveç atyre radio"</item>
+ <item msgid="8489661142527693381">"vetëm memoria e regjistrimit të bërthamës"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacioni është i çaktivizuar"</item>
<item msgid="6624864048416710414">"Shkalla e animacionit 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index 4a8f843..1817558 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB по међумеморији евиденције"</item>
<item msgid="5431354956856655120">"16 MB по међумеморији евиденције"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Искључено"</item>
+ <item msgid="3054662377365844197">"Све"</item>
+ <item msgid="688870735111627832">"Све сeм радија"</item>
+ <item msgid="2850427388488887328">"само језгро"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Искључено"</item>
+ <item msgid="172978079776521897">"Све међумеморије евиденција"</item>
+ <item msgid="3873873912383879240">"Све осим међумеморија евиденција за радио"</item>
+ <item msgid="8489661142527693381">"само међумеморија евиденције језгра"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимација је искључена"</item>
<item msgid="6624864048416710414">"Размера анимације 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index e5476f4..9ecedca 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 MB/loggbuffert"</item>
<item msgid="5431354956856655120">"16 MB/loggbuffert"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Av"</item>
+ <item msgid="3054662377365844197">"Alla"</item>
+ <item msgid="688870735111627832">"Alla utom radio"</item>
+ <item msgid="2850427388488887328">"endast kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Av"</item>
+ <item msgid="172978079776521897">"Alla loggbuffertar"</item>
+ <item msgid="3873873912383879240">"Alla loggbuffertar utom för radio"</item>
+ <item msgid="8489661142527693381">"endast buffert av kernellogg"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animering avstängd"</item>
<item msgid="6624864048416710414">"Animering i skala 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index e41c8c6..e2fbfc3 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"M4 kwa kila akiba ya kumbukumbu"</item>
<item msgid="5431354956856655120">"M16 kwa kila akiba ya kumbukumbu"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Yamezimwa"</item>
+ <item msgid="3054662377365844197">"Zote"</item>
+ <item msgid="688870735111627832">"Zote isipokuwa redio"</item>
+ <item msgid="2850427388488887328">"keneli pekee"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Imezimwa"</item>
+ <item msgid="172978079776521897">"Akiba ya kumbukumbu zote"</item>
+ <item msgid="3873873912383879240">"Zote isipokuwa akiba ya kumbukumbu za redio"</item>
+ <item msgid="8489661142527693381">"akiba ya kumbukumbu ya keneli pekee"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Haiwani imezimwa"</item>
<item msgid="6624864048416710414">"Skeli .5x ya haiwani"</item>
diff --git a/packages/SettingsLib/res/values-ta-rIN/arrays.xml b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
index 4d28aa0..fed3cd1 100644
--- a/packages/SettingsLib/res/values-ta-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M / லாக் பஃபர்"</item>
<item msgid="5431354956856655120">"16M / லாக் பஃபர்"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"முடக்கத்தில்"</item>
+ <item msgid="3054662377365844197">"எல்லாம்"</item>
+ <item msgid="688870735111627832">"எல்லாம் (ரேடியோ தவிர்த்து)"</item>
+ <item msgid="2850427388488887328">"கெர்னல் மட்டும்"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"முடக்கத்தில்"</item>
+ <item msgid="172978079776521897">"தற்காலிகமாகச் சேமித்த எல்லா பதிவுகளும்"</item>
+ <item msgid="3873873912383879240">"எல்லாம் (தற்காலிகமாகச் சேமித்த ரேடியோ பதிவுகள் தவிர்த்து)"</item>
+ <item msgid="8489661142527693381">"கெர்னல் லாக் பஃபர் மட்டும்"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"அனிமேஷனை முடக்கு"</item>
<item msgid="6624864048416710414">"அனிமேஷன் அளவு .5x"</item>
diff --git a/packages/SettingsLib/res/values-te-rIN/arrays.xml b/packages/SettingsLib/res/values-te-rIN/arrays.xml
index 106f194..482a1da 100644
--- a/packages/SettingsLib/res/values-te-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-te-rIN/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"లాగ్ బఫర్కి 4M"</item>
<item msgid="5431354956856655120">"లాగ్ బఫర్కి 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ఆఫ్ చేయి"</item>
+ <item msgid="3054662377365844197">"అన్నీ"</item>
+ <item msgid="688870735111627832">"అన్నీ కానీ రేడియో"</item>
+ <item msgid="2850427388488887328">"కెర్నెల్ మాత్రమే"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ఆఫ్ చేయి"</item>
+ <item msgid="172978079776521897">"అన్ని లాగ్ బఫర్లు"</item>
+ <item msgid="3873873912383879240">"అన్నీ కానీ రేడియో లాగ్ బఫర్లు"</item>
+ <item msgid="8489661142527693381">"కెర్నెల్ లాగ్ బఫర్ మాత్రమే"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"యానిమేషన్ ఆఫ్లో ఉంది"</item>
<item msgid="6624864048416710414">"యానిమేషన్ ప్రమాణం .5x"</item>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 5e03cc3..08caeb6 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
<item msgid="5431354956856655120">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ปิด"</item>
+ <item msgid="3054662377365844197">"ทั้งหมด"</item>
+ <item msgid="688870735111627832">"ทั้งหมดเว้นวิทยุ"</item>
+ <item msgid="2850427388488887328">"เฉพาะเคอร์เนล"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ปิด"</item>
+ <item msgid="172978079776521897">"บัฟเฟอร์บันทึกทั้งหมด"</item>
+ <item msgid="3873873912383879240">"ทั้งหมดยกเว้นบัฟเฟอร์บันทึกวิทยุ"</item>
+ <item msgid="8489661142527693381">"เฉพาะบัฟเฟอร์ไฟล์บันทึกเคอร์เนล"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ปิดภาพเคลื่อนไหว"</item>
<item msgid="6624864048416710414">"ภาพเคลื่อนไหวขนาด 0.5 เท่า"</item>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index 9f99fd2..a1505dc 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M kada log buffer"</item>
<item msgid="5431354956856655120">"16M kada log buffer"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Naka-off"</item>
+ <item msgid="3054662377365844197">"Lahat"</item>
+ <item msgid="688870735111627832">"Maliban sa radyo"</item>
+ <item msgid="2850427388488887328">"kernel lang"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Naka-off"</item>
+ <item msgid="172978079776521897">"Lahat ng buffer ng log"</item>
+ <item msgid="3873873912383879240">"Lahat maliban sa buffer ng log ng radyo"</item>
+ <item msgid="8489661142527693381">"kernel log buffer lang"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Naka-off ang animation"</item>
<item msgid="6624864048416710414">"Scale ng animation .5x"</item>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index b0ffc39..c97e79c 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Günlük arabelleği başına 4 MB"</item>
<item msgid="5431354956856655120">"Günlük arabelleği başına 16 MB"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Kapalı"</item>
+ <item msgid="3054662377365844197">"Tümü"</item>
+ <item msgid="688870735111627832">"Radyo hariç tümü"</item>
+ <item msgid="2850427388488887328">"yaln. çekirdek"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Kapalı"</item>
+ <item msgid="172978079776521897">"Günlük arabelleklerin tümü"</item>
+ <item msgid="3873873912383879240">"Radyo günlük arabellekleri hariç tümü"</item>
+ <item msgid="8489661142527693381">"yalnızca çekirdek günlük arabelleği"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasyon kapalı"</item>
<item msgid="6624864048416710414">"Animasyon ölçeği 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 2032cb4..7b720f3 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Буфер журналу: 4 Мб"</item>
<item msgid="5431354956856655120">"Буфер журналу: 16 Мб"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Вимкнено"</item>
+ <item msgid="3054662377365844197">"Усі"</item>
+ <item msgid="688870735111627832">"Усі, крім радіо"</item>
+ <item msgid="2850427388488887328">"лише ядро"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Вимкнено"</item>
+ <item msgid="172978079776521897">"Буфери всіх журналів"</item>
+ <item msgid="3873873912383879240">"Буфери всіх журналів, крім радіо"</item>
+ <item msgid="8489661142527693381">"лише буфер журналу ядра"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анімацію вимкнено"</item>
<item msgid="6624864048416710414">"Анімація 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-ur-rPK/arrays.xml b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
index 1aebccd..4f081e5 100644
--- a/packages/SettingsLib/res/values-ur-rPK/arrays.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M فی لاگ بفر"</item>
<item msgid="5431354956856655120">"16M فی لاگ بفر"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"آف"</item>
+ <item msgid="3054662377365844197">"تمام"</item>
+ <item msgid="688870735111627832">"ریڈیو کے سوا تمام"</item>
+ <item msgid="2850427388488887328">"صرف کرنل"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"آف"</item>
+ <item msgid="172978079776521897">"تمام لاگ بفرز"</item>
+ <item msgid="3873873912383879240">"ریڈیو لاگ بفرز کے سوا تمام"</item>
+ <item msgid="8489661142527693381">"صرف کرنل لاگ بفر"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"اینیمیشن آف ہے"</item>
<item msgid="6624864048416710414">"اینیمیشن اسکیل .5x"</item>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
index fc3a549..f501242 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"Bufer: maks. 4 MB"</item>
<item msgid="5431354956856655120">"Bufer: maks. 16 MB"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"O‘chiq"</item>
+ <item msgid="3054662377365844197">"Hammasi"</item>
+ <item msgid="688870735111627832">"Radiodan boshqa hammasi"</item>
+ <item msgid="2850427388488887328">"faqat yadro"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"O‘chiq"</item>
+ <item msgid="172978079776521897">"Barcha jurnallar buferi"</item>
+ <item msgid="3873873912383879240">"Radio jurnallar buferidan tashqari hammasi"</item>
+ <item msgid="8489661142527693381">"faqat yadro jurnali buferi"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatsiya o‘chiq"</item>
<item msgid="6624864048416710414">"Animatsiya (0,5x)"</item>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 95b24ef..237b4f4 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M/lần tải nhật ký"</item>
<item msgid="5431354956856655120">"16M/lần tải nhật ký"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Tắt"</item>
+ <item msgid="3054662377365844197">"Tất cả"</item>
+ <item msgid="688870735111627832">"Tất cả trừ đài"</item>
+ <item msgid="2850427388488887328">"chỉ kernel"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Tắt"</item>
+ <item msgid="172978079776521897">"Tất cả lần tải nhật ký"</item>
+ <item msgid="3873873912383879240">"Tất cả trừ lần tải nhật ký qua đài"</item>
+ <item msgid="8489661142527693381">"chỉ vùng đệm nhật ký kernel"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Tắt hình động"</item>
<item msgid="6624864048416710414">"Tỷ lệ hình động 0,5x"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index 19853ef..fe65884 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"每個記錄緩衝區 4M"</item>
<item msgid="5431354956856655120">"每個記錄緩衝區 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"關閉"</item>
+ <item msgid="3054662377365844197">"全部"</item>
+ <item msgid="688870735111627832">"所有非無線電"</item>
+ <item msgid="2850427388488887328">"只限核心"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"關閉"</item>
+ <item msgid="172978079776521897">"所有記錄緩衝區"</item>
+ <item msgid="3873873912383879240">"所有非無線電記錄緩衝區"</item>
+ <item msgid="8489661142527693381">"只限核心記錄緩衝區"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"關閉動畫"</item>
<item msgid="6624864048416710414">"動畫比例 .5x"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 443a512..0939e93 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"每個紀錄緩衝區 4M"</item>
<item msgid="5431354956856655120">"每個紀錄緩衝區 16M"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"關閉"</item>
+ <item msgid="3054662377365844197">"全部"</item>
+ <item msgid="688870735111627832">"無線電以外"</item>
+ <item msgid="2850427388488887328">"僅限核心"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"關閉"</item>
+ <item msgid="172978079776521897">"所有紀錄緩衝區"</item>
+ <item msgid="3873873912383879240">"無線電紀錄緩衝區以外的所有紀錄緩衝區"</item>
+ <item msgid="8489661142527693381">"僅限核心紀錄緩衝區"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"關閉動畫"</item>
<item msgid="6624864048416710414">"動畫比例 0.5x"</item>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index c04c175..772dee8 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -80,8 +80,18 @@
<item msgid="3606047780792894151">"4M ngebhafa yelogu ngayinye"</item>
<item msgid="5431354956856655120">"16M ngebhafa yelogu ngayinye"</item>
</string-array>
- <!-- no translation found for select_logpersist_titles:3 (2850427388488887328) -->
- <!-- no translation found for select_logpersist_summaries:3 (8489661142527693381) -->
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"Valiwe"</item>
+ <item msgid="3054662377365844197">"Konke"</item>
+ <item msgid="688870735111627832">"Konke ngaphandle kwerediyo"</item>
+ <item msgid="2850427388488887328">"i-kernel kuphela"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"Valiwe"</item>
+ <item msgid="172978079776521897">"Onke amabhafa elogi"</item>
+ <item msgid="3873873912383879240">"Konke ngaphandle kwamabhafa elogi yerediyo"</item>
+ <item msgid="8489661142527693381">"ilogi ye-kernel kuphela"</item>
+ </string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Isithombe esinyakazayo sivliwe"</item>
<item msgid="6624864048416710414">"Isilinganiso sesithombe esinyakazayo ngu-05x"</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 548ddf8..e049079 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -169,7 +169,7 @@
* Determine whether a package is a "system package", in which case certain things (like
* disabling notifications or disabling the package altogether) should be disallowed.
*/
- public static boolean isSystemPackage(PackageManager pm, PackageInfo pkg) {
+ public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
if (sSystemSignature == null) {
sSystemSignature = new Signature[]{ getSystemSignature(pm) };
}
@@ -187,7 +187,8 @@
|| pkg.packageName.equals(sPermissionControllerPackageName)
|| pkg.packageName.equals(sServicesSystemSharedLibPackageName)
|| pkg.packageName.equals(sSharedSystemSharedLibPackageName)
- || pkg.packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
+ || pkg.packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
+ || isDeviceProvisioningPackage(resources, pkg.packageName);
}
private static Signature getFirstSignature(PackageInfo pkg) {
@@ -205,4 +206,14 @@
}
return null;
}
+
+ /**
+ * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
+ * returns {@code false}.
+ */
+ public static boolean isDeviceProvisioningPackage(Resources resources, String packageName) {
+ String deviceProvisioningPackage = resources.getString(
+ com.android.internal.R.string.config_deviceProvisioningPackage);
+ return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 7392453..16bfc56 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -582,10 +582,10 @@
public ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator,
boolean foreground) {
synchronized (mRebuildSync) {
- synchronized (mEntriesMap) {
+ synchronized (mRebuildingSessions) {
mRebuildingSessions.add(this);
mRebuildRequested = true;
- mRebuildAsync = false;
+ mRebuildAsync = true;
mRebuildFilter = filter;
mRebuildComparator = comparator;
mRebuildForeground = foreground;
@@ -597,23 +597,7 @@
}
}
- // We will wait for .25s for the list to be built.
- long waitend = SystemClock.uptimeMillis()+250;
-
- while (mRebuildResult == null) {
- long now = SystemClock.uptimeMillis();
- if (now >= waitend) {
- break;
- }
- try {
- mRebuildSync.wait(waitend - now);
- } catch (InterruptedException e) {
- }
- }
-
- mRebuildAsync = true;
-
- return mRebuildResult;
+ return null;
}
}
@@ -776,7 +760,7 @@
public void handleMessage(Message msg) {
// Always try rebuilding list first thing, if needed.
ArrayList<Session> rebuildingSessions = null;
- synchronized (mEntriesMap) {
+ synchronized (mRebuildingSessions) {
if (mRebuildingSessions.size() > 0) {
rebuildingSessions = new ArrayList<Session>(mRebuildingSessions);
mRebuildingSessions.clear();
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index 78d7c56..a99e668 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.util.DisplayMetrics;
@@ -95,7 +96,9 @@
}
final Resources res = context.getResources();
- final DisplayMetrics metrics = res.getDisplayMetrics();
+ final DisplayMetrics metrics = new DisplayMetrics();
+ context.getDisplay().getRealMetrics(metrics);
+
final int currentDensity = metrics.densityDpi;
int currentDensityIndex = -1;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 108814e..978ca94 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -216,7 +216,4 @@
<!-- Default setting for ability to add users from the lock screen -->
<bool name="def_add_users_from_lockscreen">false</bool>
-
- <!-- Default setting for disallow oem unlock. -->
- <bool name="def_oem_unlock_disallow">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index b79ce80..bf48e5d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -247,7 +247,6 @@
return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES:
case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES:
- case Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX:
case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE:
return !TextUtils.isEmpty(Settings.Secure.getString(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 950c7d3..1928f92 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -799,7 +799,8 @@
// If this is a setting that is currently restricted for this user, do not allow
// unrestricting changes.
- if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
+ if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value,
+ Binder.getCallingUid())) {
return false;
}
@@ -930,7 +931,8 @@
// If this is a setting that is currently restricted for this user, do not allow
// unrestricting changes.
- if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
+ if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value,
+ Binder.getCallingUid())) {
return false;
}
@@ -1153,7 +1155,7 @@
* @return true if the change is prohibited, false if the change is allowed.
*/
private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
- String value) {
+ String value, int callingUid) {
String restriction;
switch (setting) {
case Settings.Secure.LOCATION_MODE:
@@ -1191,6 +1193,15 @@
restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
break;
+ case Settings.Secure.ALWAYS_ON_VPN_APP:
+ case Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN:
+ // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn
+ if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
+ return false;
+ }
+ restriction = UserManager.DISALLOW_CONFIG_VPN;
+ break;
+
default:
if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
if ("0".equals(value)) return false;
@@ -2074,7 +2085,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 128;
+ private static final int SETTINGS_VERSION = 129;
private final int mUserId;
@@ -2330,17 +2341,41 @@
}
if (currentVersion == 127) {
- // Version 127: Disable OEM unlock setting by default on some devices.
- final SettingsState globalSettings = getGlobalSettingsLocked();
- String defaultOemUnlockDisabled = (getContext().getResources()
- .getBoolean(R.bool.def_oem_unlock_disallow) ? "1" : "0");
- globalSettings.insertSettingLocked(
- Settings.Global.OEM_UNLOCK_DISALLOWED,
- defaultOemUnlockDisabled,
- SettingsState.SYSTEM_PACKAGE_NAME);
+ // version 127 is no longer used.
currentVersion = 128;
}
+ if (currentVersion == 128) {
+ // Version 128: Allow OEMs to grant DND access to default apps. Note that
+ // the new apps are appended to the list of already approved apps.
+ final SettingsState systemSecureSettings =
+ getSecureSettingsLocked(userId);
+
+ final Setting policyAccess = systemSecureSettings.getSettingLocked(
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+ String defaultPolicyAccess = getContext().getResources().getString(
+ com.android.internal.R.string.config_defaultDndAccessPackages);
+ if (!TextUtils.isEmpty(defaultPolicyAccess)) {
+ if (policyAccess.isNull()) {
+ systemSecureSettings.insertSettingLocked(
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ defaultPolicyAccess,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ } else {
+ StringBuilder currentSetting =
+ new StringBuilder(policyAccess.getValue());
+ currentSetting.append(":");
+ currentSetting.append(defaultPolicyAccess);
+ systemSecureSettings.updateSettingLocked(
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ currentSetting.toString(),
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ }
+
+ currentVersion = 129;
+ }
+
// vXXX: Add new settings above this point.
// Return the current version.
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 6d8b9f6..258c82e 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -16,17 +16,21 @@
include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
Keyguard \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
- android-support-v17-leanback \
+ android-support-v17-leanback
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
framework-protos \
SystemUI-proto-tags
@@ -39,19 +43,6 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_RESOURCE_DIR := \
- frameworks/base/packages/Keyguard/res \
- $(LOCAL_PATH)/res \
- frameworks/support/v7/preference/res \
- frameworks/support/v14/preference/res \
- frameworks/support/v7/appcompat/res \
- frameworks/support/v7/recyclerview/res \
- frameworks/support/v17/leanback/res
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat \
- --extra-packages android.support.v17.leanback
-
ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental
diff --git a/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml b/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml
new file mode 100644
index 0000000..778ccbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:alpha="0.3">
+
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M6,12c0,5.5,4.5,10,10,10c1,0,2-0.2,3-0.5c-4.1-1.3-7-5.1-7-9.5s2.9-8.3,7-9.5C18.1,2.2,17.1,2,16,2C10.5,2,6,6.5,6,12z" />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml b/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml
new file mode 100644
index 0000000..aaca663
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M6,12c0,5.5,4.5,10,10,10c1,0,2-0.2,3-0.5c-4.1-1.3-7-5.1-7-9.5s2.9-8.3,7-9.5C18.1,2.2,17.1,2,16,2C10.5,2,6,6.5,6,12z" />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
index 258bd0f..4d7f325 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
@@ -1,37 +1,30 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2016 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
+ 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
- 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.
+ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.0dp"
- android:height="24dp"
- android:viewportWidth="36.0"
- android:viewportHeight="36.0">
-
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFF"
- android:pathData="M6.797,13.334h1.231v1.522H6.797v2.509h-1.62v-2.509H1.101l-0.039-1.157l4.069-7.643h1.666V13.334z
-M2.648,13.334h2.53V8.721L5.137,8.713L4.984,9.148L2.648,13.334z" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
<path
- android:fillColor="#FFFFFF"
- android:pathData="M16.155,15.836c-0.269,0.439-0.695,0.832-1.282,1.177c-0.587,0.344-1.344,0.517-2.271,0.517
-c-1.151,0-2.098-0.432-2.841-1.294c-0.744-0.862-1.115-1.978-1.115-3.345v-2.36c0-1.367,0.359-2.481,1.077-3.343
-c0.719-0.863,1.643-1.293,2.772-1.293c1.132,0,2.017,0.331,2.649,0.994c0.633,0.663,0.941,1.528,0.924,2.594l-0.021,0.047h-1.545
-c0-0.638-0.171-1.15-0.513-1.538c-0.341-0.389-0.831-0.583-1.469-0.583c-0.674,0-1.217,0.292-1.63,0.877
-c-0.413,0.585-0.619,1.328-0.619,2.229v2.375c0,0.912,0.215,1.662,0.645,2.25c0.431,0.587,0.992,0.881,1.684,0.881
-c0.522,0,0.935-0.068,1.238-0.205c0.304-0.138,0.533-0.305,0.688-0.502v-2.338h-2.041v-1.413h3.668V15.836z" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M11.9,9.9c-0.2,0.4 -0.6,0.7 -1.0,0.9s-1.0,0.4 -1.8,0.4c-0.9,0.0 -1.7,-0.3 -2.2,-0.8S6.1,9.0 6.1,7.9L6.1,5.6c0.0,-1.1 0.3,-1.9 0.8,-2.4S8.2,2.4 9.0,2.4c1.0,0.0 1.7,0.2 2.1,0.7s0.7,1.2 0.7,2.1l-1.6,0.0c0.0,-0.5 -0.1,-0.9 -0.2,-1.1S9.5,3.7 9.0,3.7c-0.4,0.0 -0.7,0.2 -0.9,0.5S7.8,5.0 7.8,5.6l0.0,2.3c0.0,0.7 0.1,1.1 0.3,1.4c0.2,0.3 0.6,0.5 1.0,0.5c0.3,0.0 0.6,0.0 0.7,-0.1s0.3,-0.2 0.4,-0.3L10.2,7.8L9.0,7.8L9.0,6.6l2.9,0.0L11.9,9.9z"/>
<path
- android:fillColor="#FFFFFF"
- android:pathData="M19.366,14.701v-2.232h-2.25v-1.541h2.25V8.695h1.5v2.232h2.256v1.541h-2.256v2.232H19.366z" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17.7,4.4l-1.900001,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.900001,0.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
new file mode 100644
index 0000000..3af0629
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
@@ -0,0 +1,33 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.3,3.8L7.0,3.8L7.0,11.0L5.4,11.0L5.4,3.8L4.0,3.8L4.0,2.5l4.3,0.0L8.3,3.8z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12.4,7.3l-1.7,0.0l0.0,2.4l2.1,0.0L12.799999,11.0L9.0,11.0L9.0,2.5l3.7,0.0l0.0,1.3l-2.1,0.0l0.0,2.1l1.7,0.0L12.4,7.3L12.4,7.3z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18.4,4.4l-1.9,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.9,0.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
index 17a4394..3cdd3e1 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
@@ -1,37 +1,30 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2016 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
+ 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
+ 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.
+ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15dp"
- android:height="20dp"
- android:viewportWidth="36"
- android:viewportHeight="36">
-
+ android:width="17.0dp"
+ android:height="17.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFF"
- android:pathData="M6.797,13.334h1.231v1.522H6.797v2.509h-1.62v-2.509H1.101l-0.039-1.157l4.069-7.643h1.666V13.334z
-M2.648,13.334h2.53V8.721L5.137,8.713L4.984,9.148L2.648,13.334z" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
<path
- android:fillColor="#FFFFFF"
- android:pathData="M16.155,15.836c-0.269,0.439-0.695,0.832-1.282,1.177c-0.587,0.344-1.344,0.517-2.271,0.517
-c-1.151,0-2.098-0.432-2.841-1.294c-0.744-0.862-1.115-1.978-1.115-3.345v-2.36c0-1.367,0.359-2.481,1.077-3.343
-c0.719-0.863,1.643-1.293,2.772-1.293c1.132,0,2.017,0.331,2.649,0.994c0.633,0.663,0.941,1.528,0.924,2.594l-0.021,0.047h-1.545
-c0-0.638-0.171-1.15-0.513-1.538c-0.341-0.389-0.831-0.583-1.469-0.583c-0.674,0-1.217,0.292-1.63,0.877
-c-0.413,0.585-0.619,1.328-0.619,2.229v2.375c0,0.912,0.215,1.662,0.645,2.25c0.431,0.587,0.992,0.881,1.684,0.881
-c0.522,0,0.935-0.068,1.238-0.205c0.304-0.138,0.533-0.305,0.688-0.502v-2.338h-2.041v-1.413h3.668V15.836z" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M11.9,9.9c-0.2,0.4 -0.6,0.7 -1.0,0.9s-1.0,0.4 -1.8,0.4c-0.9,0.0 -1.7,-0.3 -2.2,-0.8S6.1,9.0 6.1,7.9L6.1,5.6c0.0,-1.1 0.3,-1.9 0.8,-2.4S8.2,2.4 9.0,2.4c1.0,0.0 1.7,0.2 2.1,0.7s0.7,1.2 0.7,2.1l-1.6,0.0c0.0,-0.5 -0.1,-0.9 -0.2,-1.1S9.5,3.7 9.0,3.7c-0.4,0.0 -0.7,0.2 -0.9,0.5S7.8,5.0 7.8,5.6l0.0,2.3c0.0,0.7 0.1,1.1 0.3,1.4c0.2,0.3 0.6,0.5 1.0,0.5c0.3,0.0 0.6,0.0 0.7,-0.1s0.3,-0.2 0.4,-0.3L10.2,7.8L9.0,7.8L9.0,6.6l2.9,0.0L11.9,9.9z"/>
<path
- android:fillColor="#FFFFFF"
- android:pathData="M19.366,14.701v-2.232h-2.25v-1.541h2.25V8.695h1.5v2.232h2.256v1.541h-2.256v2.232H19.366z" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17.7,4.4l-1.900001,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.900001,0.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml
new file mode 100644
index 0000000..db18fad
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml
@@ -0,0 +1,33 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17.0dp"
+ android:height="17.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.3,3.8L7.0,3.8L7.0,11.0L5.4,11.0L5.4,3.8L4.0,3.8L4.0,2.5l4.3,0.0L8.3,3.8z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12.4,7.3l-1.7,0.0l0.0,2.4l2.1,0.0L12.799999,11.0L9.0,11.0L9.0,2.5l3.7,0.0l0.0,1.3l-2.1,0.0l0.0,2.1l1.7,0.0L12.4,7.3L12.4,7.3z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18.4,4.4l-1.9,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.9,0.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/battery_detail.xml b/packages/SystemUI/res/layout/battery_detail.xml
index 1f24ab0..8abfcf6 100644
--- a/packages/SystemUI/res/layout/battery_detail.xml
+++ b/packages/SystemUI/res/layout/battery_detail.xml
@@ -25,7 +25,7 @@
android:id="@+id/charge_and_estimation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="72dp"
+ android:paddingStart="16dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/colorAccent" />
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 63390e2..967db26 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -47,11 +47,12 @@
<com.android.systemui.qs.NonInterceptingScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1">
+ android:layout_weight="1"
+ android:fillViewport="true">
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="match_parent"/>
</com.android.systemui.qs.NonInterceptingScrollView>
<include layout="@layout/qs_detail_buttons" />
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index 8352e30..f809c68 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -25,20 +25,9 @@
android:background="@drawable/btn_borderless_rect"
android:gravity="center">
- <ImageView
- android:id="@*android:id/up"
- android:layout_width="@dimen/qs_detail_image_width"
- android:layout_height="@dimen/qs_detail_image_height"
- android:layout_marginEnd="@dimen/qs_detail_back_margin_end"
- android:padding="@dimen/qs_detail_image_padding"
- android:clickable="true"
- android:background="?android:attr/selectableItemBackground"
- android:contentDescription="@*android:string/action_bar_up_description"
- android:src="?android:attr/homeAsUpIndicator" />
-
<TextView
android:id="@android:id/title"
- android:paddingLeft="@dimen/qs_detail_header_text_padding"
+ android:paddingStart="@dimen/qs_detail_header_text_padding"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
diff --git a/packages/SystemUI/res/layout/qs_detail_items.xml b/packages/SystemUI/res/layout/qs_detail_items.xml
index 0b08a55..9a7e1b6 100644
--- a/packages/SystemUI/res/layout/qs_detail_items.xml
+++ b/packages/SystemUI/res/layout/qs_detail_items.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
<!-- extends FrameLayout -->
-<com.android.systemui.qs.QSDetailItems xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.qs.QSDetailItems
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -29,26 +30,26 @@
android:layout_height="match_parent"
android:orientation="vertical"
sysui:itemHeight="@dimen/qs_detail_item_height"
- style="@style/AutoSizingList" />
+ style="@style/AutoSizingList"/>
<LinearLayout
android:id="@android:id/empty"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
+ android:gravity="center"
+ android:orientation="vertical">
<ImageView
android:id="@android:id/icon"
android:layout_width="56dp"
- android:layout_height="56dp" />
+ android:layout_height="56dp"/>
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
- android:textAppearance="@style/TextAppearance.QS.DetailEmpty" />
+ android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
</LinearLayout>
</com.android.systemui.qs.QSDetailItems>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 3b8b909..6673d6e 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -111,7 +111,7 @@
android:layout_alignParentTop="true"
android:paddingStart="16dp"
android:paddingEnd="16dp"
- android:paddingTop="2dp"
+ android:paddingTop="6dp"
android:visibility="gone"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
android:text="@*android:string/emergency_calls_only"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 134388f..fa30f49 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -224,9 +224,25 @@
<!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
<integer name="doze_pickup_vibration_threshold">2000</integer>
- <!-- Doze: can we assume the pickup sensor includes a proximity check? -->
+ <!-- Doze: can we assume the pickup sensor includes a proximity check?
+ This is ignored if doze_pickup_subtype_performs_proximity_check is not empty.
+ @deprecated: use doze_pickup_subtype_performs_proximity_check instead.-->
<bool name="doze_pickup_performs_proximity_check">false</bool>
+ <!-- Doze: a list of pickup sensor subtypes that perform a proximity check before they trigger.
+ If not empty, either * or !* must appear to specify the default.
+ If empty, falls back to doze_pickup_performs_proximity_check.
+
+ Examples: 1,2,3,!* -> subtypes 1,2 and 3 perform the check, all others don't.
+ !1,!2,* -> subtypes 1 and 2 don't perform the check, all others do.
+ !8,* -> subtype 8 does not perform the check, all others do
+ 1,1,* -> illegal, every item may only appear once
+ 1,!1,* -> illegal, no contradictions allowed
+ 1,2 -> illegal, need either * or !*
+ 1,,4a3 -> illegal, no empty or non-numeric terms allowed
+ -->
+ <string name="doze_pickup_subtype_performs_proximity_check"></string>
+
<!-- Doze: pulse parameter - how long does it take to fade in? -->
<integer name="doze_pulse_duration_in">900</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index da04934..5bd0e87 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -212,7 +212,7 @@
<dimen name="qs_detail_empty_text_size">14sp</dimen>
<dimen name="qs_detail_margin_top">28dp</dimen>
<dimen name="qs_detail_back_margin_end">16dp</dimen>
- <dimen name="qs_detail_header_text_padding">0dp</dimen>
+ <dimen name="qs_detail_header_text_padding">16dp</dimen>
<dimen name="qs_data_usage_text_size">14sp</dimen>
<dimen name="qs_data_usage_usage_text_size">36sp</dimen>
<dimen name="qs_battery_padding">2dp</dimen>
@@ -396,6 +396,8 @@
<!-- The font size of the date in QS -->
<dimen name="qs_date_collapsed_size">14sp</dimen>
+ <!-- Amount the date/time move when emergency calls only is present -->
+ <dimen name="qs_date_time_translation">8dp</dimen>
<!-- Battery level text padding end when in expanded QS and on Keyguard -->
<dimen name="battery_level_padding_end">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 71816f7..8ad4d9b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -354,6 +354,9 @@
<!-- Content description of the data connection type LTE for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_lte">LTE</string>
+ <!-- Content description of the data connection type LTE+ for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_data_connection_lte_plus">LTE+</string>
+
<!-- Content description of the data connection type CDMA for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_cdma">CDMA</string>
@@ -750,6 +753,12 @@
<string name="quick_settings_cellular_detail_data_warning"><xliff:g id="data_limit" example="2.0 GB">%s</xliff:g> warning</string>
<!-- QuickSettings: Work mode [CHAR LIMIT=NONE] -->
<string name="quick_settings_work_mode_label">Work mode</string>
+ <!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
+ <string name="quick_settings_night_display_label">Night Light</string>
+ <!-- QuickSettings: Summary for the toggle to deactivate Night display when it's on (renamed "Night Light" with title caps). [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_night_display_summary_on">Night Light on, tap to turn off</string>
+ <!-- QuickSettings: Label for the toggle to activate Night display when it's off (renamed "Night Light" with title caps). [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_night_display_summary_off">Night Light off, tap to turn on</string>
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">No recent items</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 39a3412..52b5a54 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -55,7 +55,8 @@
com.android.systemui.media.RingtonePlayer.class,
com.android.systemui.keyboard.KeyboardUI.class,
com.android.systemui.tv.pip.PipUI.class,
- com.android.systemui.shortcut.ShortcutKeyDispatcher.class
+ com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
+ com.android.systemui.VendorServices.class
};
/**
diff --git a/packages/SystemUI/src/com/android/systemui/VendorServices.java b/packages/SystemUI/src/com/android/systemui/VendorServices.java
new file mode 100644
index 0000000..0be6b12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/VendorServices.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui;
+
+/**
+ * Placeholder for any vendor-specific services.
+ */
+public class VendorServices extends SystemUI {
+
+ @Override
+ public void start() {
+ // no-op
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index af2a286..9eceeac 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -47,7 +47,7 @@
private static final long TIMEOUT_SERVICE = 2500;
private static final long TIMEOUT_ACTIVITY = 1000;
- private final Context mContext;
+ protected final Context mContext;
private final WindowManager mWindowManager;
private final AssistDisclosure mAssistDisclosure;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 5f1b042..661b347 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -214,6 +214,10 @@
}
private void requestPulse(final int reason) {
+ requestPulse(reason, false /* performedProxCheck */);
+ }
+
+ private void requestPulse(final int reason, boolean performedProxCheck) {
if (mHost != null && mDreaming && !mPulsing) {
// Let the host know we want to pulse. Wait for it to be ready, then
// turn the screen on. When finished, turn the screen off again.
@@ -226,10 +230,9 @@
return;
}
final long start = SystemClock.uptimeMillis();
- final boolean nonBlocking = reason == DozeLog.PULSE_REASON_SENSOR_PICKUP
- && mDozeParameters.getPickupPerformsProxCheck();
- if (nonBlocking) {
- // proximity check is only done to capture statistics, continue pulsing
+ if (performedProxCheck) {
+ // the caller already performed a successful proximity check; we'll only do one to
+ // capture statistics, continue pulsing immediately.
continuePulsing(reason);
}
// perform a proximity check
@@ -239,7 +242,7 @@
final boolean isNear = result == RESULT_NEAR;
final long end = SystemClock.uptimeMillis();
DozeLog.traceProximityResult(mContext, isNear, end - start, reason);
- if (nonBlocking) {
+ if (performedProxCheck) {
// we already continued
return;
}
@@ -540,9 +543,12 @@
mWakeLock.acquire();
try {
if (DEBUG) Log.d(mTag, "onTrigger: " + triggerEventToString(event));
+ boolean sensorPerformsProxCheck = false;
if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
int subType = (int) event.values[0];
MetricsLogger.action(mContext, MetricsEvent.ACTION_AMBIENT_GESTURE, subType);
+ sensorPerformsProxCheck = mDozeParameters.getPickupSubtypePerformsProxCheck(
+ subType);
}
if (mDebugVibrate) {
final Vibrator v = (Vibrator) mContext.getSystemService(
@@ -555,7 +561,7 @@
}
mRegistered = false;
- requestPulse(mPulseReason);
+ requestPulse(mPulseReason, sensorPerformsProxCheck);
updateListener(); // reregister, this sensor only fires once
// reset the notification pulse schedule, but only if we think we were not triggered
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 805e9d6..14944d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -63,11 +63,12 @@
private boolean mScanState;
private boolean mClosingDetail;
private boolean mFullyExpanded;
- protected View mQsDetailHeaderBack;
private BaseStatusBarHeader mHeader;
private boolean mTriggeredExpand;
private int mOpenX;
private int mOpenY;
+ private boolean mAnimating;
+ private boolean mSwitchState;
public QSDetail(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -92,7 +93,6 @@
mDetailDoneButton = (TextView) findViewById(android.R.id.button1);
mQsDetailHeader = findViewById(R.id.qs_detail_header);
- mQsDetailHeaderBack = mQsDetailHeader.findViewById(com.android.internal.R.id.up);
mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
@@ -109,7 +109,6 @@
mQsPanel.closeDetail();
}
};
- mQsDetailHeaderBack.setOnClickListener(doneListener);
mDetailDoneButton.setOnClickListener(doneListener);
}
@@ -215,6 +214,7 @@
protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
if (visibleDiff) {
+ mAnimating = true;
if (mFullyExpanded || mDetailAdapter != null) {
setAlpha(1);
mClipper.animateCircularClip(x, y, mDetailAdapter != null, listener);
@@ -246,7 +246,7 @@
mQsDetailHeader.setClickable(false);
} else {
mQsDetailHeaderSwitch.setVisibility(VISIBLE);
- mQsDetailHeaderSwitch.setChecked(toggleState);
+ handleToggleStateChanged(toggleState);
mQsDetailHeader.setClickable(true);
mQsDetailHeader.setOnClickListener(new OnClickListener() {
@Override
@@ -260,6 +260,10 @@
}
private void handleToggleStateChanged(boolean state) {
+ mSwitchState = state;
+ if (mAnimating) {
+ return;
+ }
mQsDetailHeaderSwitch.setChecked(state);
}
@@ -276,6 +280,10 @@
}
}
+ private void checkPendingAnimations() {
+ handleToggleStateChanged(mSwitchState);
+ }
+
protected QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
@Override
public void onToggleStateChanged(final boolean state) {
@@ -313,6 +321,8 @@
// If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
// called, this will avoid accidentally turning off the grid when we don't want to.
animation.removeListener(this);
+ mAnimating = false;
+ checkPendingAnimations();
};
@Override
@@ -322,6 +332,8 @@
mQsPanel.setGridContentVisibility(false);
mHeader.setVisibility(View.INVISIBLE);
}
+ mAnimating = false;
+ checkPendingAnimations();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 569a567..b36221d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -71,7 +71,7 @@
super(host);
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mComponent = ComponentName.unflattenFromString(action);
- mTile = new Tile(mComponent);
+ mTile = new Tile();
setTileIcon();
mServiceManager = host.getTileServices().getTileWrapper(this);
mService = mServiceManager.getTileService();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index 407453c..451e1f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -94,4 +94,8 @@
return false;
}
}
+
+ public IQSTileService getService() {
+ return mService;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 79f9de6..681005c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -26,6 +26,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -37,6 +38,7 @@
import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
+
import libcore.util.Objects;
import java.util.Set;
@@ -67,6 +69,7 @@
private final Handler mHandler;
private final Intent mIntent;
private final UserHandle mUser;
+ private final IBinder mToken = new Binder();
private Set<Integer> mQueuedMessages = new ArraySet<>();
private QSTileServiceWrapper mWrapper;
@@ -88,7 +91,7 @@
mHandler = handler;
mIntent = intent;
mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder());
- mIntent.putExtra(TileService.EXTRA_COMPONENT, intent.getComponent());
+ mIntent.putExtra(TileService.EXTRA_TOKEN, mToken);
mUser = user;
if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
}
@@ -396,6 +399,10 @@
handleDeath();
}
+ public IBinder getToken() {
+ return mToken;
+ }
+
public interface TileChangeListener {
void onTileChanged(ComponentName tile);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 3d030f9..f3e4d60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -25,6 +25,7 @@
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Handler;
+import android.os.IBinder;
import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
@@ -32,6 +33,7 @@
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import java.util.List;
@@ -106,6 +108,10 @@
return mStateManager;
}
+ public IBinder getToken() {
+ return mStateManager.getToken();
+ }
+
public void setBindRequested(boolean bindRequested) {
if (mBindRequested == bindRequested) return;
mBindRequested = bindRequested;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 6f0bed2..575f198 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -25,10 +25,12 @@
import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.util.ArrayMap;
@@ -52,6 +54,7 @@
private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+ private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>();
private final Context mContext;
private final Handler mHandler;
private final Handler mMainHandler;
@@ -82,6 +85,7 @@
synchronized (mServices) {
mServices.put(tile, service);
mTiles.put(component, tile);
+ mTokenMap.put(service.getToken(), tile);
}
return service;
}
@@ -95,6 +99,7 @@
service.setBindAllowed(false);
service.handleDestroy();
mServices.remove(tile);
+ mTokenMap.remove(service.getToken());
mTiles.remove(tile.getComponent());
final String slot = tile.getComponent().getClassName();
mMainHandler.post(new Runnable() {
@@ -138,8 +143,9 @@
}
}
- private void verifyCaller(String packageName) {
+ private void verifyCaller(CustomTile tile) {
try {
+ String packageName = tile.getComponent().getPackageName();
int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
Binder.getCallingUserHandle().getIdentifier());
if (Binder.getCallingUid() != uid) {
@@ -170,10 +176,9 @@
}
@Override
- public void updateQsTile(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void updateQsTile(Tile tile, IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
synchronized (mServices) {
final TileServiceManager tileServiceManager = mServices.get(customTile);
@@ -186,10 +191,9 @@
}
@Override
- public void onStartSuccessful(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onStartSuccessful(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
synchronized (mServices) {
final TileServiceManager tileServiceManager = mServices.get(customTile);
@@ -200,10 +204,9 @@
}
@Override
- public void onShowDialog(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onShowDialog(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
customTile.onDialogShown();
mHost.collapsePanels();
@@ -212,10 +215,9 @@
}
@Override
- public void onDialogHidden(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onDialogHidden(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
mServices.get(customTile).setShowingDialog(false);
customTile.onDialogHidden();
@@ -223,23 +225,22 @@
}
@Override
- public void onStartActivity(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onStartActivity(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
mHost.collapsePanels();
}
}
@Override
- public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) {
- final ComponentName componentName = tile.getComponentName();
- String packageName = componentName.getPackageName();
- verifyCaller(packageName);
- CustomTile customTile = getTileForComponent(componentName);
+ public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
try {
+ ComponentName componentName = customTile.getComponent();
+ String packageName = componentName.getPackageName();
UserHandle userHandle = getCallingUserHandle();
PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0,
userHandle.getIdentifier());
@@ -263,9 +264,9 @@
}
@Override
- public Tile getTile(ComponentName componentName) {
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public Tile getTile(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
return customTile.getQsTile();
}
@@ -273,10 +274,9 @@
}
@Override
- public void startUnlockAndRun(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void startUnlockAndRun(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
customTile.startUnlockAndRun();
}
@@ -294,6 +294,12 @@
return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
}
+ private CustomTile getTileForToken(IBinder token) {
+ synchronized (mServices) {
+ return mTokenMap.get(token);
+ }
+ }
+
private CustomTile getTileForComponent(ComponentName component) {
synchronized (mServices) {
return mTiles.get(component);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index f892a24..68f594b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -90,11 +90,11 @@
mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
return;
}
+ showDetail(true);
if (!mState.value) {
mState.value = true;
mController.setBluetoothEnabled(true);
}
- showDetail(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 04cb553..91821ba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -122,9 +122,9 @@
if (mState.value) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
} else {
+ showDetail(true);
int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
mController.setZen(zen, null, TAG);
- showDetail(true);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
new file mode 100644
index 0000000..9a3549e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Intent;
+import android.provider.Settings;
+import android.widget.Switch;
+
+import com.android.internal.app.NightDisplayController;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+public class NightDisplayTile extends QSTile<QSTile.BooleanState>
+ implements NightDisplayController.Callback {
+
+ private final NightDisplayController mController;
+
+ public NightDisplayTile(Host host) {
+ super(host);
+ mController = new NightDisplayController(mContext);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return NightDisplayController.isAvailable(mContext);
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ protected void handleClick() {
+ final boolean activated = !mState.value;
+ MetricsLogger.action(mContext, getMetricsCategory(), activated);
+ mController.setActivated(activated);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final boolean isActivated = mController.isActivated();
+ state.value = isActivated;
+ state.label = mContext.getString(R.string.quick_settings_night_display_label);
+ state.icon = ResourceIcon.get(isActivated ? R.drawable.ic_qs_night_display_on
+ : R.drawable.ic_qs_night_display_off);
+ state.contentDescription = mContext.getString(isActivated
+ ? R.string.quick_settings_night_display_summary_on
+ : R.string.quick_settings_night_display_summary_off);
+ state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+ = Switch.class.getName();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.QS_NIGHT_DISPLAY;
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+ }
+
+ @Override
+ protected void setListening(boolean listening) {
+ if (listening) {
+ mController.setListener(this);
+ refreshState();
+ } else {
+ mController.setListener(null);
+ }
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_night_display_label);
+ }
+
+ @Override
+ public void onActivated(boolean activated) {
+ refreshState();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 8910864..ba79a18 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -116,11 +116,11 @@
mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
return;
}
+ showDetail(true);
if (!mState.value) {
mController.setWifiEnabled(true);
mState.value = true;
}
- showDetail(true);
}
@Override
@@ -371,5 +371,5 @@
}
mItems.setItems(items);
}
- };
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index b66a4fb..c497cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -186,7 +186,7 @@
try {
final PackageInfo info =
pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
- systemApp = Utils.isSystemPackage(pm, info);
+ systemApp = Utils.isSystemPackage(getResources(), pm, info);
} catch (PackageManager.NameNotFoundException e) {
// unlikely.
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index b53a999..63f726b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -49,6 +49,13 @@
mViews.clear();
}
+ void addView(View view, boolean landscape) {
+ addView(view);
+ if (view instanceof ButtonInterface) {
+ ((ButtonInterface) view).setLandscape(landscape);
+ }
+ }
+
void addView(View view) {
mViews.add(view);
view.setOnClickListener(mClickListener);
@@ -178,5 +185,7 @@
void setImageDrawable(@Nullable Drawable drawable);
void abortCurrentGesture();
+
+ void setLandscape(boolean landscape);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 1d890d0..9b3ed33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -21,6 +21,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
+import android.util.SparseBooleanArray;
import com.android.systemui.R;
@@ -39,6 +40,8 @@
private static PulseSchedule sPulseSchedule;
+ private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
+
public DozeParameters(Context context) {
mContext = context;
}
@@ -61,7 +64,20 @@
pw.print(" getPulseSchedule(): "); pw.println(getPulseSchedule());
pw.print(" getPulseScheduleResets(): "); pw.println(getPulseScheduleResets());
pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
- pw.print(" getPickupPerformsProxCheck(): "); pw.println(getPickupPerformsProxCheck());
+ pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println(
+ dumpPickupSubtypePerformsProxCheck());
+ }
+
+ private String dumpPickupSubtypePerformsProxCheck() {
+ // Refresh sPickupSubtypePerformsProxMatcher
+ getPickupSubtypePerformsProxCheck(0);
+
+ if (sPickupSubtypePerformsProxMatcher == null) {
+ return "fallback: " + mContext.getResources().getBoolean(
+ R.bool.doze_pickup_performs_proximity_check);
+ } else {
+ return "spec: " + sPickupSubtypePerformsProxMatcher.mSpec;
+ }
}
public boolean getDisplayStateSupported() {
@@ -106,10 +122,6 @@
return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
}
- public boolean getPickupPerformsProxCheck() {
- return getBoolean("doze.pickup.proxcheck", R.bool.doze_pickup_performs_proximity_check);
- }
-
public boolean getPulseOnNotifications() {
return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
}
@@ -143,6 +155,101 @@
return SystemProperties.get(propName, mContext.getString(resId));
}
+ public boolean getPickupSubtypePerformsProxCheck(int subType) {
+ String spec = getString("doze.pickup.proxcheck",
+ R.string.doze_pickup_subtype_performs_proximity_check);
+
+ if (TextUtils.isEmpty(spec)) {
+ // Fall back to non-subtype based property.
+ return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
+ }
+
+ if (sPickupSubtypePerformsProxMatcher == null
+ || !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) {
+ sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec);
+ }
+
+ return sPickupSubtypePerformsProxMatcher.isIn(subType);
+ }
+
+
+ /**
+ * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
+ * listed, will not match numbers that are listed with a ! prefix, and will match / not match
+ * unlisted numbers depending on whether * or !* is present.
+ *
+ * * -> match any numbers that are not explicitly listed
+ * !* -> don't match any numbers that are not explicitly listed
+ * 2 -> match 2
+ * !3 -> don't match 3
+ *
+ * It is illegal to specify:
+ * - an empty spec
+ * - a spec containing that are empty, or a lone !
+ * - a spec for anything other than numbers or *
+ * - multiple terms for the same number / multiple *s
+ */
+ public static class IntInOutMatcher {
+ private static final String WILDCARD = "*";
+ private static final char OUT_PREFIX = '!';
+
+ private final SparseBooleanArray mIsIn;
+ private final boolean mDefaultIsIn;
+ final String mSpec;
+
+ public IntInOutMatcher(String spec) {
+ if (TextUtils.isEmpty(spec)) {
+ throw new IllegalArgumentException("Spec must not be empty");
+ }
+
+ boolean defaultIsIn = false;
+ boolean foundWildcard = false;
+
+ mSpec = spec;
+ mIsIn = new SparseBooleanArray();
+
+ for (String itemPrefixed : spec.split(",", -1)) {
+ if (itemPrefixed.length() == 0) {
+ throw new IllegalArgumentException(
+ "Illegal spec, must not have zero-length items: `" + spec + "`");
+ }
+ boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX;
+ String item = isIn ? itemPrefixed : itemPrefixed.substring(1);
+
+ if (itemPrefixed.length() == 0) {
+ throw new IllegalArgumentException(
+ "Illegal spec, must not have zero-length items: `" + spec + "`");
+ }
+
+ if (WILDCARD.equals(item)) {
+ if (foundWildcard) {
+ throw new IllegalArgumentException("Illegal spec, `" + WILDCARD +
+ "` must not appear multiple times in `" + spec + "`");
+ }
+ defaultIsIn = isIn;
+ foundWildcard = true;
+ } else {
+ int key = Integer.parseInt(item);
+ if (mIsIn.indexOfKey(key) >= 0) {
+ throw new IllegalArgumentException("Illegal spec, `" + key +
+ "` must not appear multiple times in `" + spec + "`");
+ }
+ mIsIn.put(key, isIn);
+ }
+ }
+
+ if (!foundWildcard) {
+ throw new IllegalArgumentException("Illegal spec, must specify either * or !*");
+ }
+
+ mDefaultIsIn = defaultIsIn;
+ }
+
+ public boolean isIn(int value) {
+ return (mIsIn.get(value, mDefaultIsIn));
+ }
+ }
+
public static class PulseSchedule {
private static final Pattern PATTERN = Pattern.compile("(\\d+?)s", 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index dd46b08..06c8b68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -28,7 +28,6 @@
import android.widget.Space;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.tuner.TunerService;
@@ -71,6 +70,8 @@
private View mLastRot0;
private View mLastRot90;
+ private boolean mAlternativeOrder;
+
public NavigationBarInflaterView(Context context, AttributeSet attrs) {
super(context, attrs);
mDensity = context.getResources().getConfiguration().densityDpi;
@@ -114,6 +115,7 @@
false);
mRot90.setId(R.id.rot90);
addView(mRot90);
+ updateAlternativeOrder();
if (getParent() instanceof NavigationBarView) {
((NavigationBarView) getParent()).updateRotatedViews();
}
@@ -152,6 +154,26 @@
}
}
+ public void setAlternativeOrder(boolean alternativeOrder) {
+ if (alternativeOrder != mAlternativeOrder) {
+ mAlternativeOrder = alternativeOrder;
+ updateAlternativeOrder();
+ }
+ }
+
+ private void updateAlternativeOrder() {
+ updateAlternativeOrder(mRot0.findViewById(R.id.ends_group));
+ updateAlternativeOrder(mRot0.findViewById(R.id.center_group));
+ updateAlternativeOrder(mRot90.findViewById(R.id.ends_group));
+ updateAlternativeOrder(mRot90.findViewById(R.id.center_group));
+ }
+
+ private void updateAlternativeOrder(View v) {
+ if (v instanceof ReverseLinearLayout) {
+ ((ReverseLinearLayout) v).setAlternativeOrder(mAlternativeOrder);
+ }
+ }
+
private void initiallyFill(ButtonDispatcher buttonDispatcher) {
addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.ends_group));
addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group));
@@ -258,7 +280,7 @@
params.width = (int) (params.width * size);
}
parent.addView(v);
- addToDispatchers(v);
+ addToDispatchers(v, landscape);
View lastView = landscape ? mLastRot90 : mLastRot0;
if (lastView != null) {
v.setAccessibilityTraversalAfter(lastView.getId());
@@ -305,16 +327,16 @@
return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START));
}
- private void addToDispatchers(View v) {
+ private void addToDispatchers(View v, boolean landscape) {
if (mButtonDispatchers != null) {
final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
if (indexOfKey >= 0) {
- mButtonDispatchers.valueAt(indexOfKey).addView(v);
+ mButtonDispatchers.valueAt(indexOfKey).addView(v, landscape);
} else if (v instanceof ViewGroup) {
final ViewGroup viewGroup = (ViewGroup)v;
final int N = viewGroup.getChildCount();
for (int i = 0; i < N; i++) {
- addToDispatchers(viewGroup.getChildAt(i));
+ addToDispatchers(viewGroup.getChildAt(i), landscape);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6a2324f..160baaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -99,6 +99,8 @@
private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
private Configuration mConfiguration;
+ private NavigationBarInflaterView mNavigationInflaterView;
+
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
private boolean mHomeAppearing;
@@ -472,9 +474,10 @@
@Override
public void onFinishInflate() {
+ mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
+ R.id.navigation_inflater);
updateRotatedViews();
- ((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers(
- mButtonDisatchers);
+ mNavigationInflaterView.setButtonDispatchers(mButtonDisatchers);
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
@@ -530,6 +533,7 @@
}
mCurrentView = mRotatedViews[rot];
mCurrentView.setVisibility(View.VISIBLE);
+ mNavigationInflaterView.setAlternativeOrder(rot == Surface.ROTATION_90);
for (int i = 0; i < mButtonDisatchers.size(); i++) {
mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9687ba6..99fbad2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -78,7 +79,6 @@
private static final int CAP_HEIGHT = 1456;
private static final int FONT_HEIGHT = 2163;
- private static final float HEADER_RUBBERBAND_FACTOR = 2.05f;
private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
private static final String COUNTER_PANEL_OPEN = "panel_open";
@@ -1376,8 +1376,7 @@
int min = mStatusBarMinHeight;
if (mStatusBar.getBarState() != StatusBarState.KEYGUARD
&& mNotificationStackScroller.getNotGoneChildCount() == 0) {
- int minHeight = (int) ((mQsMinExpansionHeight + getOverExpansionAmount())
- * HEADER_RUBBERBAND_FACTOR);
+ int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
min = Math.max(min, minHeight);
}
int maxHeight;
@@ -1552,15 +1551,8 @@
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
return 0;
}
- if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
- return Math.min(0, mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight);
- }
- float stackTranslation = mNotificationStackScroller.getStackTranslation();
- float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
- if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) {
- translation = mNotificationStackScroller.getTopPadding() + stackTranslation
- - mQsMinExpansionHeight;
- }
+ float translation = NotificationUtils.interpolate(-mQsMinExpansionHeight, 0,
+ mNotificationStackScroller.getAppearFraction(mExpandedHeight));
return Math.min(0, translation);
}
@@ -1968,7 +1960,7 @@
if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
return mNotificationStackScroller.getPeekHeight();
} else {
- return mQsMinExpansionHeight * HEADER_RUBBERBAND_FACTOR;
+ return mQsMinExpansionHeight;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d969451..2cdcff3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -52,6 +52,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.media.AudioAttributes;
import android.media.MediaMetadata;
@@ -200,7 +201,7 @@
public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
- HeadsUpManager.OnHeadsUpChangedListener {
+ HeadsUpManager.OnHeadsUpChangedListener, DisplayManager.DisplayListener {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
public static final boolean SPEW = false;
@@ -685,6 +686,8 @@
mUnlockMethodCache.addListener(this);
startKeyguard();
+ mContext.getSystemService(DisplayManager.class).registerDisplayListener(this, null);
+
mDozeServiceHost = new DozeServiceHost();
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
putComponent(DozeHost.class, mDozeServiceHost);
@@ -881,9 +884,9 @@
mLightStatusBarController = new LightStatusBarController(mIconController,
mBatteryController);
mKeyguardMonitor = new KeyguardMonitor(mContext);
+ mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
+ mHandler, this);
if (UserManager.get(mContext).isUserSwitcherEnabled()) {
- mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
- mHandler, this);
createUserSwitcher();
}
@@ -2584,7 +2587,7 @@
@Override
public void handleSystemNavigationKey(int key) {
if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
- if (!panelsEnabled()) {
+ if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()) {
return;
}
@@ -3512,6 +3515,21 @@
}
@Override
+ public void onDisplayAdded(int displayId) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ repositionNavigationBar();
+ }
+ }
+
+ @Override
public void userSwitched(int newUserId) {
super.userSwitched(newUserId);
if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index ca7f905..405ccd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -52,6 +52,7 @@
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.NightDisplayTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.UserTile;
import com.android.systemui.qs.tiles.WifiTile;
@@ -399,7 +400,7 @@
ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
- mContext, mServices, new Tile(component), intent,
+ mContext, mServices, new Tile(), intent,
new UserHandle(ActivityManager.getCurrentUser()));
lifecycleManager.onStopListening();
lifecycleManager.onTileRemoved();
@@ -413,7 +414,7 @@
ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
- mContext, mServices, new Tile(component), intent,
+ mContext, mServices, new Tile(), intent,
new UserHandle(ActivityManager.getCurrentUser()));
lifecycleManager.onTileAdded();
lifecycleManager.flushMessagesAndUnbind();
@@ -440,6 +441,7 @@
else if (tileSpec.equals("user")) return new UserTile(this);
else if (tileSpec.equals("battery")) return new BatteryTile(this);
else if (tileSpec.equals("saver")) return new DataSaverTile(this);
+ else if (tileSpec.equals("night")) return new NightDisplayTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 63ac098..e1a2354 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -37,11 +37,11 @@
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
-import com.android.systemui.qs.QSAnimator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSPanel.Callback;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.TouchAnimator;
+import com.android.systemui.qs.TouchAnimator.Builder;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
@@ -84,13 +84,13 @@
private ImageView mMultiUserAvatar;
- private TouchAnimator mSecondHalfAnimator;
- private TouchAnimator mFirstHalfAnimator;
+ private TouchAnimator mAnimator;
protected TouchAnimator mSettingsAlpha;
private float mExpansionAmount;
protected QSTileHost mHost;
protected View mEdit;
private boolean mShowFullAlarm;
+ private float mDateTimeTranslation;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -111,6 +111,7 @@
mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
mDateTimeGroup.setPivotX(0);
mDateTimeGroup.setPivotY(0);
+ mDateTimeTranslation = getResources().getDimension(R.dimen.qs_date_time_translation);
mShowFullAlarm = getResources().getBoolean(R.bool.quick_settings_show_full_alarm);
mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator);
@@ -152,15 +153,13 @@
FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
- mSecondHalfAnimator = new TouchAnimator.Builder()
+ Builder builder = new Builder()
.addFloat(mShowFullAlarm ? mAlarmStatus : findViewById(R.id.date), "alpha", 0, 1)
- .addFloat(mEmergencyOnly, "alpha", 0, 1)
- .build();
+ .addFloat(mEmergencyOnly, "alpha", 0, 1);
if (mShowFullAlarm) {
- mFirstHalfAnimator = new TouchAnimator.Builder()
- .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0)
- .build();
+ builder.addFloat(mAlarmStatusCollapsed, "alpha", 1, 0);
}
+ mAnimator = builder.build();
updateSettingsAnimator();
}
@@ -223,10 +222,8 @@
@Override
public void setExpansion(float headerExpansionFraction) {
mExpansionAmount = headerExpansionFraction;
- mSecondHalfAnimator.setPosition(headerExpansionFraction);
- if (mShowFullAlarm) {
- mFirstHalfAnimator.setPosition(headerExpansionFraction);
- }
+ updateDateTimePosition();
+ mAnimator.setPosition(headerExpansionFraction);
mSettingsAlpha.setPosition(headerExpansionFraction);
updateAlarmVisibilities();
@@ -264,6 +261,7 @@
protected void updateVisibilities() {
updateAlarmVisibilities();
+ updateDateTimePosition();
mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly
? View.VISIBLE : View.INVISIBLE);
mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
@@ -274,6 +272,11 @@
mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
}
+ private void updateDateTimePosition() {
+ mDateTimeAlarmGroup.setTranslationY(mShowEmergencyCallsOnly
+ ? mExpansionAmount * mDateTimeTranslation : 0);
+ }
+
private void updateListeners() {
if (mListening) {
mNextAlarmController.addStateChangedCallback(this);
@@ -315,7 +318,8 @@
public void onClick(View v) {
if (v == mSettingsButton) {
MetricsLogger.action(mContext,
- MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH);
+ mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
+ : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
if (mSettingsButton.isTunerClick()) {
if (TunerService.isTunerEnabled(mContext)) {
TunerService.showResetRequest(mContext, new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
index 3682aa1..f45967a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
@@ -30,7 +30,11 @@
*/
public class ReverseLinearLayout extends LinearLayout {
- private boolean mIsLayoutRtl;
+ /** If true, the layout is reversed vs. a regular linear layout */
+ private boolean mIsLayoutReverse;
+
+ /** If true, the layout is opposite to it's natural reversity from the layout direction */
+ private boolean mIsAlternativeOrder;
public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -39,45 +43,50 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mIsLayoutRtl = getResources().getConfiguration()
- .getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ updateOrder();
}
@Override
public void addView(View child) {
reversParams(child.getLayoutParams());
- if (mIsLayoutRtl) {
- super.addView(child);
- } else {
+ if (mIsLayoutReverse) {
super.addView(child, 0);
+ } else {
+ super.addView(child);
}
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
reversParams(params);
- if (mIsLayoutRtl) {
- super.addView(child, params);
- } else {
+ if (mIsLayoutReverse) {
super.addView(child, 0, params);
+ } else {
+ super.addView(child, params);
}
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateRTLOrder();
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ updateOrder();
+ }
+
+ public void setAlternativeOrder(boolean alternative) {
+ mIsAlternativeOrder = alternative;
+ updateOrder();
}
/**
* In landscape, the LinearLayout is not auto mirrored since it is vertical. Therefore we
* have to do it manually
*/
- private void updateRTLOrder() {
- boolean isLayoutRtl = getResources().getConfiguration()
- .getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- if (mIsLayoutRtl != isLayoutRtl) {
- // RTL changed, swap the order of all views.
+ private void updateOrder() {
+ boolean isLayoutRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ boolean isLayoutReverse = isLayoutRtl ^ mIsAlternativeOrder;
+
+ if (mIsLayoutReverse != isLayoutReverse) {
+ // reversity changed, swap the order of all views.
int childCount = getChildCount();
ArrayList<View> childList = new ArrayList<>(childCount);
for (int i = 0; i < childCount; i++) {
@@ -87,7 +96,7 @@
for (int i = childCount - 1; i >= 0; i--) {
super.addView(childList.get(i));
}
- mIsLayoutRtl = isLayoutRtl;
+ mIsLayoutReverse = isLayoutReverse;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index a035eee..a326806 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -357,11 +357,12 @@
public void dump(PrintWriter pw) {
int N = mStatusIcons.getChildCount();
- pw.println(" system icons: " + N);
+ pw.println(" icon views: " + N);
for (int i=0; i<N; i++) {
StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
pw.println(" [" + i + "] icon=" + ic);
}
+ super.dump(pw);
}
public void dispatchDemoCommand(String command, Bundle args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
index 97b31f2..6821879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -81,9 +81,9 @@
public void dump(PrintWriter pw) {
final int N = mSlots.size();
- pw.println("Icon list:");
+ pw.println(" icon slots: " + N);
for (int i=0; i<N; i++) {
- pw.printf(" %2d: (%s) %s\n", i, mSlots.get(i), mIcons.get(i));
+ pw.printf(" %2d: (%s) %s\n", i, mSlots.get(i), mIcons.get(i));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index d8b1a62..3df7590 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -265,6 +265,11 @@
public void setImageDrawable(@Nullable Drawable drawable) {
super.setImageDrawable(drawable);
}
+
+ @Override
+ public void setLandscape(boolean landscape) {
+ //no op
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 970fed0..c175180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -112,6 +112,10 @@
notifyKeyguardChanged();
}
+ public boolean isDeviceInteractive() {
+ return mKeyguardUpdateMonitor.isDeviceInteractive();
+ }
+
private void updateCanSkipBouncerState() {
mCanSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(mCurrentUser);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index ac3246d..8178bda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -201,7 +201,7 @@
TelephonyIcons.FOUR_G_PLUS);
} else {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, TelephonyIcons.LTE);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, TelephonyIcons.LTE_PLUS);
}
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 7a042af..a31bc04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -786,6 +786,7 @@
datatype.equals("g") ? TelephonyIcons.G :
datatype.equals("h") ? TelephonyIcons.H :
datatype.equals("lte") ? TelephonyIcons.LTE :
+ datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
datatype.equals("roam") ? TelephonyIcons.ROAMING :
TelephonyIcons.UNKNOWN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index d91b332..ed8c7ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -208,10 +208,12 @@
};
static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte;
+ static final int QS_DATA_LTE_PLUS = R.drawable.ic_qs_signal_lte_plus;
static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
static final int ROAMING_ICON = R.drawable.stat_sys_data_fully_connected_roam;
static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte;
+ static final int ICON_LTE_PLUS = R.drawable.stat_sys_data_fully_connected_lte_plus;
static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g;
static final int ICON_E = R.drawable.stat_sys_data_fully_connected_e;
static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;
@@ -393,6 +395,21 @@
TelephonyIcons.QS_DATA_LTE
);
+ static final MobileIconGroup LTE_PLUS = new MobileIconGroup(
+ "LTE+",
+ TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+ TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ TelephonyIcons.TELEPHONY_NO_NETWORK,
+ TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.accessibility_data_connection_lte_plus,
+ TelephonyIcons.ICON_LTE_PLUS,
+ true,
+ TelephonyIcons.QS_DATA_LTE_PLUS
+ );
+
static final MobileIconGroup ROAMING = new MobileIconGroup(
"Roaming",
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 4e03365..c883bba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -99,6 +99,7 @@
private Dialog mExitGuestDialog;
private Dialog mAddUserDialog;
private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
+ private boolean mResumeUserOnGuestLogout = true;
private boolean mSimpleUserSwitcher;
private boolean mAddUsersWhenLocked;
private boolean mPauseRefreshUsers;
@@ -318,6 +319,10 @@
return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
}
+ public void setResumeUserOnGuestLogout(boolean resume) {
+ mResumeUserOnGuestLogout = resume;
+ }
+
public void logoutCurrentUser() {
int currentUser = ActivityManager.getCurrentUser();
if (currentUser != UserHandle.USER_SYSTEM) {
@@ -420,7 +425,7 @@
private void exitGuest(int id) {
int newId = UserHandle.USER_SYSTEM;
- if (mLastNonGuestUser != UserHandle.USER_SYSTEM) {
+ if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
newId = info.id;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index b4d0ffd..839a20b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -668,30 +668,74 @@
public void setStackHeight(float height) {
mLastSetStackHeight = height;
setIsExpanded(height > 0.0f);
- int newStackHeight = (int) height;
- int minStackHeight = getLayoutMinHeight();
int stackHeight;
- float paddingOffset;
- boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
- int normalUnfoldPositionStart = trackingHeadsUp
- ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
- : minStackHeight;
- if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart
- || getNotGoneChildCount() == 0) {
- paddingOffset = mTopPaddingOverflow;
- stackHeight = newStackHeight;
+ float translationY;
+ float appearEndPosition = getAppearEndPosition();
+ float appearStartPosition = getAppearStartPosition();
+ if (height >= appearEndPosition) {
+ translationY = mTopPaddingOverflow;
+ stackHeight = (int) height;
} else {
- int translationY;
- translationY = newStackHeight - normalUnfoldPositionStart;
- paddingOffset = translationY - mTopPadding;
- stackHeight = (int) (height - (translationY - mTopPadding));
+ float appearFraction = getAppearFraction(height);
+ if (appearFraction >= 0) {
+ translationY = NotificationUtils.interpolate(getExpandTranslationStart(), 0,
+ appearFraction);
+ } else {
+ // This may happen when pushing up a heads up. We linearly push it up from the
+ // start
+ translationY = height - appearStartPosition + getExpandTranslationStart();
+ }
+ stackHeight = (int) (height - translationY);
}
if (stackHeight != mCurrentStackHeight) {
mCurrentStackHeight = stackHeight;
updateAlgorithmHeightAndPadding();
requestChildrenUpdate();
}
- setStackTranslation(paddingOffset);
+ setStackTranslation(translationY);
+ }
+
+ /**
+ * @return The translation at the beginning when expanding.
+ * Measured relative to the resting position.
+ */
+ private float getExpandTranslationStart() {
+ int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
+ ? 0 : -getFirstChildMinHeight();
+ return startPosition - mTopPadding;
+ }
+
+ /**
+ * @return the position from where the appear transition starts when expanding.
+ * Measured in absolute height.
+ */
+ private float getAppearStartPosition() {
+ return mTrackingHeadsUp
+ ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
+ : 0;
+ }
+
+ /**
+ * @return the position from where the appear transition ends when expanding.
+ * Measured in absolute height.
+ */
+ private float getAppearEndPosition() {
+ int firstItemHeight = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
+ ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
+ + mBottomStackSlowDownHeight
+ : getLayoutMinHeight();
+ return firstItemHeight + mTopPadding + mTopPaddingOverflow;
+ }
+
+ /**
+ * @param height the height of the panel
+ * @return the fraction of the appear animation that has been performed
+ */
+ public float getAppearFraction(float height) {
+ float appearEndPosition = getAppearEndPosition();
+ float appearStartPosition = getAppearStartPosition();
+ return (height - appearStartPosition)
+ / (appearEndPosition - appearStartPosition);
}
public float getStackTranslation() {
@@ -2098,6 +2142,12 @@
}
public int getLayoutMinHeight() {
+ int firstChildMinHeight = getFirstChildMinHeight();
+ return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
+ mMaxLayoutHeight - mTopPadding);
+ }
+
+ private int getFirstChildMinHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
int firstChildMinHeight = firstChild != null
? firstChild.getIntrinsicHeight()
@@ -2107,8 +2157,7 @@
if (mOwnScrollY > 0) {
firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
}
- return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
- mMaxLayoutHeight - mTopPadding);
+ return firstChildMinHeight;
}
public float getTopPaddingOverflow() {
@@ -2349,6 +2398,7 @@
if (hasAddEvent) {
// This child was just added lets remove all events.
mHeadsUpChangeAnimations.removeAll(mTmpList);
+ ((ExpandableNotificationRow ) child).setHeadsupDisappearRunning(false);
}
mTmpList.clear();
return hasAddEvent;
@@ -2606,6 +2656,10 @@
type = row.wasJustClicked()
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
: AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+ if (row.isChildInGroup()) {
+ // We can otherwise get stuck in there if it was just isolated
+ row.setHeadsupDisappearRunning(false);
+ }
} else {
StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
if (viewState == null) {
@@ -3099,6 +3153,22 @@
requestChildrenUpdate();
runAnimationFinishedRunnables();
clearViewOverlays();
+ clearHeadsUpDisappearRunning();
+ }
+
+ private void clearHeadsUpDisappearRunning() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ row.setHeadsupDisappearRunning(false);
+ if (row.isSummaryWithChildren()) {
+ for (ExpandableNotificationRow child : row.getNotificationChildren()) {
+ child.setHeadsupDisappearRunning(false);
+ }
+ }
+ }
+ }
}
private void clearViewOverlays() {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
index cc0ffb0..1ea23bb 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
@@ -54,7 +54,6 @@
mHeaderSwitch = findViewById(R.id.tuner_zen_switch);
mHeaderSwitch.setVisibility(View.VISIBLE);
mHeaderSwitch.setOnClickListener(this);
- mHeaderSwitch.findViewById(com.android.internal.R.id.up).setVisibility(View.GONE);
((TextView) mHeaderSwitch.findViewById(android.R.id.title)).setText(
R.string.quick_settings_dnd_label);
mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index f01e95f..995ecae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -124,12 +124,8 @@
: null;
Util.setText(mSummaryLine1, line1);
- final boolean isForever = mConfig != null && mConfig.manualRule != null
- && mConfig.manualRule.conditionId == null;
- final CharSequence line2 =
- isForever ? mContext.getString(com.android.internal.R.string.zen_mode_forever_dnd)
- : ZenModeConfig.getConditionSummary(mContext, mConfig, mController.getCurrentUser(),
- true /*shortVersion*/);
+ final CharSequence line2 = ZenModeConfig.getConditionSummary(mContext, mConfig,
+ mController.getCurrentUser(), true /*shortVersion*/);
Util.setText(mSummaryLine2, line2);
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 6c39e35..2020abb 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -15,6 +15,7 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := tests
LOCAL_JACK_FLAGS := --multi-dex native
@@ -23,37 +24,31 @@
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
-LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview \
- --extra-packages android.support.v17.leanback
+LOCAL_PACKAGE_NAME := SystemUITests
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
$(call all-java-files-under, ../src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
- frameworks/support/v7/preference/res \
- frameworks/support/v14/preference/res \
- frameworks/support/v7/appcompat/res \
- frameworks/support/v7/recyclerview/res \
- frameworks/support/v17/leanback/res \
frameworks/base/packages/SystemUI/res \
- frameworks/base/packages/Keyguard/res
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
-
-LOCAL_PACKAGE_NAME := SystemUITests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- mockito-target \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
Keyguard \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
- android-support-v17-leanback \
+ android-support-v17-leanback
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ mockito-target \
SystemUI-proto-tags
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
+
+LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui
+
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
LOCAL_CERTIFICATE := platform
diff --git a/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java b/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java
new file mode 100644
index 0000000..07334f3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.phone;
+
+import com.android.systemui.statusbar.phone.DozeParameters.IntInOutMatcher;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class DozeParametersTests extends AndroidTestCase {
+
+ public void test_inOutMatcher_defaultIn() {
+ IntInOutMatcher intInOutMatcher = new IntInOutMatcher("*");
+
+ assertTrue(intInOutMatcher.isIn(1));
+ assertTrue(intInOutMatcher.isIn(-1));
+ assertTrue(intInOutMatcher.isIn(0));
+ }
+
+ public void test_inOutMatcher_defaultOut() {
+ IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!*");
+
+ assertFalse(intInOutMatcher.isIn(1));
+ assertFalse(intInOutMatcher.isIn(-1));
+ assertFalse(intInOutMatcher.isIn(0));
+ }
+
+ public void test_inOutMatcher_someIn() {
+ IntInOutMatcher intInOutMatcher = new IntInOutMatcher("1,2,3,!*");
+
+ assertTrue(intInOutMatcher.isIn(1));
+ assertTrue(intInOutMatcher.isIn(2));
+ assertTrue(intInOutMatcher.isIn(3));
+
+ assertFalse(intInOutMatcher.isIn(0));
+ assertFalse(intInOutMatcher.isIn(4));
+ }
+
+ public void test_inOutMatcher_someOut() {
+ IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,!2,!3,*");
+
+ assertFalse(intInOutMatcher.isIn(1));
+ assertFalse(intInOutMatcher.isIn(2));
+ assertFalse(intInOutMatcher.isIn(3));
+
+ assertTrue(intInOutMatcher.isIn(0));
+ assertTrue(intInOutMatcher.isIn(4));
+ }
+
+ public void test_inOutMatcher_mixed() {
+ IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,2,!3,*");
+
+ assertFalse(intInOutMatcher.isIn(1));
+ assertTrue(intInOutMatcher.isIn(2));
+ assertFalse(intInOutMatcher.isIn(3));
+
+ assertTrue(intInOutMatcher.isIn(0));
+ assertTrue(intInOutMatcher.isIn(4));
+ }
+
+ public void test_inOutMatcher_failEmpty() {
+ try {
+ new IntInOutMatcher("");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failNull() {
+ try {
+ new IntInOutMatcher(null);
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failEmptyClause() {
+ try {
+ new IntInOutMatcher("!1,*,");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failDuplicate() {
+ try {
+ new IntInOutMatcher("!1,*,!1");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failDuplicateDefault() {
+ try {
+ new IntInOutMatcher("!1,*,*");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failMalformedNot() {
+ try {
+ new IntInOutMatcher("!,*");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failText() {
+ try {
+ new IntInOutMatcher("!abc,*");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failContradiction() {
+ try {
+ new IntInOutMatcher("1,!1,*");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failContradictionDefault() {
+ try {
+ new IntInOutMatcher("1,*,!*");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void test_inOutMatcher_failMissingDefault() {
+ try {
+ new IntInOutMatcher("1");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
index c93377a..7703c58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -58,7 +58,7 @@
mHandler = new Handler(mThread.getLooper());
ComponentName component = new ComponentName(mContext, FakeTileService.class);
mStateManager = new TileLifecycleManager(mHandler, getContext(),
- Mockito.mock(IQSService.class), new Tile(component),
+ Mockito.mock(IQSService.class), new Tile(),
new Intent().setComponent(component),
new UserHandle(UserHandle.myUserId()));
mCallbacks.clear();
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 97efed0..05207b9 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -114,13 +114,17 @@
imageStage.delete();
lockImageStage.delete();
- Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
- fullBackupFile(infoStage, data);
- Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
- fullBackupFile(imageStage, data);
+ if (mWallpaperInfo.exists()) {
+ Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+ fullBackupFile(infoStage, data);
+ }
+ if (mWallpaperFile.exists()) {
+ Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+ fullBackupFile(imageStage, data);
+ }
// Don't try to store the lock image if we overran our quota last time
- if (!mQuotaExceeded) {
+ if (mLockWallpaperFile.exists() && !mQuotaExceeded) {
Os.link(mLockWallpaperFile.getCanonicalPath(), lockImageStage.getCanonicalPath());
fullBackupFile(lockImageStage, data);
}
@@ -130,7 +134,7 @@
}
}
} catch (Exception e) {
- Slog.e(TAG, "Unable to back up wallpaper: " + e.getMessage());
+ Slog.e(TAG, "Unable to back up wallpaper", e);
} finally {
if (DEBUG) {
Slog.v(TAG, "Removing backup stage links");
@@ -173,6 +177,9 @@
final File lockImageStage = new File (filesDir, LOCK_IMAGE_STAGE);
try {
+ // First off, revert to the factory state
+ mWm.clear(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+
// It is valid for the imagery to be absent; it means that we were not permitted
// to back up the original image on the source device, or there was no user-supplied
// wallpaper image present.
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0fc9da0..cfb18b7 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -33,73 +33,61 @@
// OPEN: Settings > Accessibility
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCESSIBILITY = 2;
// OPEN: Settings > Accessibility > Captions
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCESSIBILITY_CAPTION_PROPERTIES = 3;
// OPEN: Settings > Accessibility > [Service]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCESSIBILITY_SERVICE = 4;
// OPEN: Settings > Accessibility > Color correction
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
// OPEN: Settings > Accessibility > Accessibility shortcut
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
// OPEN: Settings > Accessibility > Magnification gestures
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
// OPEN: Settings > Accounts
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCOUNT = 8;
// OPEN: Settings > Accounts > [Single Account Sync Settings]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCOUNTS_ACCOUNT_SYNC = 9;
// OPEN: Settings > Accounts > Add an account
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
// OPEN: Settings > Accounts > [List of accounts when more than one]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACCOUNTS_MANAGE_ACCOUNTS = 11;
// OPEN: Settings > Cellular network settings > APNs
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APN = 12;
// OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APN_EDITOR = 13;
// OBSOLETE
@@ -114,7 +102,6 @@
// OPEN: Settings > Apps > Configure apps > App links > [App]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_APP_LAUNCH = 17;
// OBSOLETE
@@ -123,19 +110,16 @@
// OPEN: Settings > Internal storage > Apps storage > [App]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_APP_STORAGE = 19;
// OPEN: Settings > Apps > [App info]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_INSTALLED_APP_DETAILS = 20;
// OPEN: Settings > Memory > App usage > [App Memory usage]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_PROCESS_STATS_DETAIL = 21;
// OBSOLETE
@@ -144,19 +128,16 @@
// OPEN: Settings > Memory > App usage
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_PROCESS_STATS_UI = 23;
// OPEN: Settings > Bluetooth
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
BLUETOOTH = 24;
// OPEN: Choose Bluetooth device (ex: when sharing)
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
BLUETOOTH_DEVICE_PICKER = 25;
// OBSOLETE
@@ -165,55 +146,46 @@
// OPEN: Settings > Security > Choose screen lock
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CHOOSE_LOCK_GENERIC = 27;
// OPEN: Settings > Security > Choose screen lock > Choose your password
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CHOOSE_LOCK_PASSWORD = 28;
// OPEN: Settings > Security > Choose screen lock > Choose your pattern
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CHOOSE_LOCK_PATTERN = 29;
// OPEN: Settings > Security > Choose screen lock > Confirm your password
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CONFIRM_LOCK_PASSWORD = 30;
// OPEN: Settings > Security > Choose screen lock > Confirm your pattern
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CONFIRM_LOCK_PATTERN = 31;
// OPEN: Settings > Security > Encrypt phone
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CRYPT_KEEPER = 32;
// OPEN: Settings > Security > Encrypt phone > Confirm
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
CRYPT_KEEPER_CONFIRM = 33;
// OPEN: Settings > Search results
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DASHBOARD_SEARCH_RESULTS = 34;
// OPEN: Settings (Root page)
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DASHBOARD_SUMMARY = 35;
// OBSOLETE
@@ -222,49 +194,41 @@
// OPEN: Settings > Data usage
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DATA_USAGE_SUMMARY = 37;
// OPEN: Settings > Date & time
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DATE_TIME = 38;
// OPEN: Settings > Developer options
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DEVELOPMENT = 39;
// OPEN: Settings > About phone
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DEVICEINFO = 40;
// OPEN: Settings > About phone > Status > IMEI information
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DEVICEINFO_IMEI_INFORMATION = 41;
// OPEN: Settings > Internal storage
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DEVICEINFO_STORAGE = 42;
// OPEN: Settings > About phone > Status > SIM status
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DEVICEINFO_SIM_STATUS = 43;
// OPEN: Settings > About phone > Status
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DEVICEINFO_STATUS = 44;
// OBSOLETE
@@ -273,25 +237,21 @@
// OPEN: Settings > Display
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DISPLAY = 46;
// OPEN: Settings > Display > Daydream
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
DREAM = 47;
// OPEN: Settings > Security > Screen lock > Secure start-up
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ENCRYPTION = 48;
// OPEN: Settings > Security > Nexus Imprint
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
FINGERPRINT = 49;
// OBSOLETE
@@ -300,55 +260,46 @@
// OPEN: Settings > Battery > History details
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
// OPEN: Settings > Battery > Battery saver
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
FUELGAUGE_BATTERY_SAVER = 52;
// OPEN: Settings > Battery > [App Use details]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
FUELGAUGE_POWER_USAGE_DETAIL = 53;
// OPEN: Settings > Battery
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
FUELGAUGE_POWER_USAGE_SUMMARY = 54;
// OPEN: Settings > Home
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
HOME = 55;
// OPEN: Settings > Security > SIM card lock settings
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ICC_LOCK = 56;
// OPEN: Settings > Language & input
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
INPUTMETHOD_LANGUAGE = 57;
// OPEN: Settings > Language & input > Physical keyboard
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
INPUTMETHOD_KEYBOARD = 58;
// OPEN: Settings > Language & input > Spell checker
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
INPUTMETHOD_SPELL_CHECKERS = 59;
// OBSOLETE
@@ -357,79 +308,66 @@
// OPEN: Settings > Language & input > Personal dictionary
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
INPUTMETHOD_USER_DICTIONARY = 61;
// OPEN: Settings > Language & input > Add word
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
// OPEN: Settings > Location
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
LOCATION = 63;
// OPEN: Settings > Location > Location mode
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
LOCATION_MODE = 64;
// OPEN: Settings > Apps
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
MANAGE_APPLICATIONS = 65;
// OPEN: Settings > Backup & reset > Factory data reset
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
MASTER_CLEAR = 66;
// OPEN: Settings > Backup & reset > Factory data reset > Confirm
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
MASTER_CLEAR_CONFIRM = 67;
// OPEN: Settings > Data usage > Network restrictions
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NET_DATA_USAGE_METERED = 68;
// OPEN: Settings > More > Android Beam
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NFC_BEAM = 69;
// OPEN: Settings > Tap & pay
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NFC_PAYMENT = 70;
// OPEN: Settings > Sound & notification
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION = 71;
// OPEN: Settings > Sound & notification > App notifications > [App]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_APP_NOTIFICATION = 72;
// OPEN: Settings > Sound & notification > Other sounds
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_OTHER_SOUND = 73;
// OBSOLETE
@@ -438,13 +376,11 @@
// OPEN: Settings Widget > Notification log
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_STATION = 75;
// OPEN: Settings > Sound & notification > Do not disturb
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE = 76;
// OPEN: OBSOLETE
@@ -453,25 +389,21 @@
// OPEN: Print job notification > Print job settings
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
PRINT_JOB_SETTINGS = 78;
// OPEN: Settings > Printing > [Print Service]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
PRINT_SERVICE_SETTINGS = 79;
// OPEN: Settings > Printing
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
PRINT_SETTINGS = 80;
// OPEN: Settings > Backup & reset
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
PRIVACY = 81;
//OBSOLETE
@@ -480,37 +412,31 @@
// OPEN: Settings > Backup & reset > Network settings reset
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
RESET_NETWORK = 83;
// OPEN: Settings > Backup & reset > Network settings reset > Confirm
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
RESET_NETWORK_CONFIRM = 84;
// OPEN: Settings > Developer Options > Running Services
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
RUNNING_SERVICE_DETAILS = 85;
// OPEN: Settings > Security > Screen pinning
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
SCREEN_PINNING = 86;
// OPEN: Settings > Security
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
SECURITY = 87;
// OPEN: Settings > SIM cards
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
SIM = 88;
// OBSOLETE
@@ -519,55 +445,46 @@
// OPEN: Settings > More > Tethering & portable hotspot
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TETHER = 90;
// OPEN: Settings > Security > Trust agents
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TRUST_AGENT = 91;
// OPEN: Settings > Security > Trusted credentials
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TRUSTED_CREDENTIALS = 92;
// OPEN: Settings > Language & input > TTS output > [Engine] > Settings
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TTS_ENGINE_SETTINGS = 93;
// OPEN: Settings > Language & input > Text-to-speech output
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TTS_TEXT_TO_SPEECH = 94;
// OPEN: Settings > Security > Apps with usage access
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
USAGE_ACCESS = 95;
// OPEN: Settings > Users
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
USER = 96;
// OPEN: Settings > Users > [Restricted profile app & content access]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
USERS_APP_RESTRICTIONS = 97;
// OPEN: Settings > Users > [User settings]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
USER_DETAILS = 98;
// OBSOLETE
@@ -576,43 +493,36 @@
// OPEN: Settings > More > VPN
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
VPN = 100;
// OPEN: Settings > Display > Choose wallpaper from
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WALLPAPER_TYPE = 101;
// OPEN: Settings > Display > Cast
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WFD_WIFI_DISPLAY = 102;
// OPEN: Settings > Wi-Fi
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WIFI = 103;
// OPEN: Settings > Wi-Fi > Advanced Wi-Fi
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WIFI_ADVANCED = 104;
// OPEN: Settings > More > Wi-Fi Calling
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WIFI_CALLING = 105;
// OPEN: Settings > Wi-Fi > Saved networks
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WIFI_SAVED_ACCESS_POINTS = 106;
// OBSOLETE
@@ -624,19 +534,16 @@
// OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WIFI_P2P = 109;
// OPEN: Settings > More
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
WIRELESS = 110;
// OPEN: Quick Settings Panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_PANEL = 111;
// OPEN: QS Airplane mode tile shown
@@ -644,7 +551,6 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_AIRPLANEMODE = 112;
// OPEN: QS Bluetooth tile shown
@@ -652,21 +558,18 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_BLUETOOTH = 113;
// OPEN: QS Cast tile shown
// ACTION: QS Cast tile tapped
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_CAST = 114;
// OPEN: QS Cellular tile shown
// ACTION: QS Cellular tile tapped
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_CELLULAR = 115;
// OPEN: QS Color inversion tile shown
@@ -674,13 +577,11 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_COLORINVERSION = 116;
// OPEN: QS Cellular tile > Cellular detail panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_DATAUSAGEDETAIL = 117;
// OPEN: QS Do not disturb tile shown
@@ -688,7 +589,6 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_DND = 118;
// OPEN: QS Flashlight tile shown
@@ -696,7 +596,6 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_FLASHLIGHT = 119;
// OPEN: QS Hotspot tile shown
@@ -704,14 +603,12 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_HOTSPOT = 120;
// OPEN: QS 3P tile shown
// ACTION: QS 3P tile tapped
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_INTENT = 121;
// OPEN: QS Location tile shown
@@ -719,7 +616,6 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_LOCATION = 122;
// OPEN: QS Rotation tile shown
@@ -727,7 +623,6 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_ROTATIONLOCK = 123;
// OBSOLETE
@@ -736,7 +631,6 @@
// OPEN: QS User list panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_USERDETAIL = 125;
// OPEN: QS WiFi tile shown
@@ -744,13 +638,11 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.46
QS_WIFI = 126;
// OPEN: Notification Panel (including lockscreen)
// CATEGORY: NOTIFICATION
// OS: 5.1.1
- // GMS: 7.5.26
NOTIFICATION_PANEL = 127;
// OPEN: Notification in panel became visible.
@@ -764,7 +656,6 @@
// SUBTYPE: Dismiss reason from NotificationManagerService.java
// CATEGORY: NOTIFICATION
// OS: 5.1.1
- // GMS: 7.5.26
NOTIFICATION_ITEM = 128;
// ACTION: User tapped notification action
@@ -772,19 +663,16 @@
// SUBTYPE: Index of action on notification
// CATEGORY: NOTIFICATION
// OS: 5.0
- // GMS: 7.5.26
NOTIFICATION_ITEM_ACTION = 129;
// OPEN: Settings > Apps > Configure apps > App permissions
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_ADVANCED = 130;
// OPEN: Settings > Location > Scanning
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
LOCATION_SCANNING = 131;
// OBSOLETE
@@ -793,43 +681,36 @@
// OPEN: Settings > Sound & notification > App notifications
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
// ACTION: Settings > Wi-Fi > Overflow > Add Network
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_WIFI_ADD_NETWORK = 134;
// ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_WIFI_CONNECT = 135;
// ACTION: Settings > Wi-Fi > Overflow > Refresh
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_WIFI_FORCE_SCAN = 136;
// ACTION: Settings > Wi-Fi > [Long press network] > Forget network
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_WIFI_FORGET = 137;
// ACTION: Settings > Wi-Fi > Toggle off
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_WIFI_OFF = 138;
// ACTION: Settings > Wi-Fi > Toggle on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_WIFI_ON = 139;
// OBSOLETE
@@ -838,280 +719,236 @@
// OPEN: Settings > Sound & notification > DND > Priority only allows
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_PRIORITY = 141;
// OPEN: Settings > Sound & notification > DND > Automatic rules
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
// OPEN: Settings > Apps > Configure apps > App links
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
MANAGE_DOMAIN_URLS = 143;
// OPEN: Settings > Sound & notification > DND > [Time based rule]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
// OPEN: Settings > Sound & notification > DND > [External rule]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
// OPEN: Settings > Sound & notification > DND > [Event rule]
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
// ACTION: App notification settings > Block Notifications
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BAN_APP_NOTES = 147;
// ACTION: Notification shade > Dismiss all button
// CATEGORY: NOTIFICATION
// OS: 6.0
- // GMS: 7.5.26
ACTION_DISMISS_ALL_NOTES = 148;
// OPEN: QS Do Not Disturb detail panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_DND_DETAILS = 149;
// OPEN: QS Bluetooth detail panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_BLUETOOTH_DETAILS = 150;
// OPEN: QS Cast detail panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_CAST_DETAILS = 151;
// OPEN: QS Wi-Fi detail panel
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_WIFI_DETAILS = 152;
// ACTION: QS Wi-Fi detail panel > Wi-Fi toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_WIFI_TOGGLE = 153;
// ACTION: QS Bluetooth detail panel > Bluetooth toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_BLUETOOTH_TOGGLE = 154;
// ACTION: QS Cellular detail panel > Cellular toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_CELLULAR_TOGGLE = 155;
// ACTION: QS User list panel > Select different user
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_SWITCH_USER = 156;
// ACTION: QS Cast detail panel > Select cast device
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_CAST_SELECT = 157;
// ACTION: QS Cast detail panel > Disconnect cast device
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_CAST_DISCONNECT = 158;
// ACTION: Settings > Bluetooth > Toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BLUETOOTH_TOGGLE = 159;
// ACTION: Settings > Bluetooth > Overflow > Refresh
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BLUETOOTH_SCAN = 160;
// ACTION: Settings > Bluetooth > Overflow > Rename this device
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BLUETOOTH_RENAME = 161;
// ACTION: Settings > Bluetooth > Overflow > Show received files
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BLUETOOTH_FILES = 162;
// ACTION: QS DND details panel > Increase / Decrease exit time
// SUBTYPE: true is increase, false is decrease
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_DND_TIME = 163;
// ACTION: QS DND details panel > [Exit condition]
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_DND_CONDITION_SELECT = 164;
// ACTION: QS DND details panel > [DND mode]
// SUBTYPE: 1 is priority, 2 is silence, 3 is alarms only
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_DND_ZEN_SELECT = 165;
// ACTION: QS DND detail panel > DND toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
QS_DND_TOGGLE = 166;
// ACTION: DND Settings > Priority only allows > Reminder toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ALLOW_REMINDERS = 167;
// ACTION: DND Settings > Priority only allows > Event toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ALLOW_EVENTS = 168;
// ACTION: DND Settings > Priority only allows > Messages
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ALLOW_MESSAGES = 169;
// ACTION: DND Settings > Priority only allows > Calls
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ALLOW_CALLS = 170;
// ACTION: DND Settings > Priority only allows > Repeat callers toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
// ACTION: DND Settings > Automatic rules > Add rule
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ADD_RULE = 172;
// ACTION: DND Settings > Automatic rules > Add rule > OK
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ADD_RULE_OK = 173;
// ACTION: DND Settings > Automatic rules > [Rule] > Delete rule
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_DELETE_RULE = 174;
// ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_DELETE_RULE_OK = 175;
// ACTION: DND Settings > Automatic rules > [Rule] > Toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ZEN_ENABLE_RULE = 176;
// ACTION: Settings > More > Airplane mode toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_AIRPLANE_TOGGLE = 177;
// ACTION: Settings > Data usage > Cellular data toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_CELL_DATA_TOGGLE = 178;
// OPEN: Settings > Sound & notification > Notification access
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ACCESS = 179;
// OPEN: Settings > Sound & notification > Do Not Disturb access
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_ACCESS = 180;
// OPEN: Settings > Apps > Configure apps > Default Apps
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_DEFAULT_APPS = 181;
// OPEN: Settings > Internal storage > Apps storage
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_STORAGE_APPS = 182;
// OPEN: Settings > Security > Usage access
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
// OPEN: Settings > Battery > Battery optimization
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_HIGH_POWER_APPS = 184;
// OBSOLETE
@@ -1120,448 +957,377 @@
// ACTION: Lockscreen > Unlock gesture
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_UNLOCK = 186;
// ACTION: Lockscreen > Pull shade open
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_SHADE = 187;
// ACTION: Lockscreen > Tap on lock, shows hint
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_HINT = 188;
// ACTION: Lockscreen > Camera
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_CAMERA = 189;
// ACTION: Lockscreen > Dialer
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_DIALER = 190;
// ACTION: Lockscreen > Tap on lock, locks phone
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_LOCK = 191;
// ACTION: Lockscreen > Tap on notification, false touch rejection
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
ACTION_LS_NOTE = 192;
// ACTION: Lockscreen > Swipe down to open quick settings
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.8.22
ACTION_LS_QS = 193;
// ACTION: Swipe down to open quick settings when unlocked
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.8.22
ACTION_SHADE_QS_PULL = 194;
// ACTION: Notification shade > Tap to open quick settings
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.8.22
ACTION_SHADE_QS_TAP = 195;
// OPEN: Lockscreen
// SUBTYPE: 0 is unsecure, 1 is secured by password / pattern / PIN
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
LOCKSCREEN = 196;
// OPEN: Lockscreen > Screen to enter password / pattern / PIN
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
BOUNCER = 197;
// OPEN: Screen turned on
// SUBTYPE: 2 is user action
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.8.22
SCREEN = 198;
// OPEN: Notification caused sound, vibration, and/or LED blink
// SUBTYPE: 1 is buzz, 2 is beep, blink is 4, or'd together
// CATEGORY: NOTIFICATION
// OS: 5.1.1
- // GMS: 7.8.53
NOTIFICATION_ALERT = 199;
// ACTION: Lockscreen > Emergency Call button
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 5.1.1
- // GMS: 7.5.26
ACTION_EMERGENCY_CALL = 200;
// OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
APPLICATIONS_MANAGE_ASSIST = 201;
// OPEN: Settings > Memory
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
PROCESS_STATS_SUMMARY = 202;
// ACTION: Settings > Display > When device is rotated
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_ROTATION_LOCK = 203;
// ACTION: Long press on notification to view controls
// CATEGORY: NOTIFICATION
// OS: 6.0
- // GMS: 7.5.26
ACTION_NOTE_CONTROLS = 204;
// ACTION: Notificatoin controls > Info button
// CATEGORY: NOTIFICATION
// OS: 6.0
- // GMS: 7.5.26
ACTION_NOTE_INFO = 205;
// ACTION: Notification controls > Settings button
// CATEGORY: NOTIFICATION
// OS: 6.0
- // GMS: 7.5.26
ACTION_APP_NOTE_SETTINGS = 206;
// OPEN: Volume Dialog (with hardware buttons)
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
VOLUME_DIALOG = 207;
// OPEN: Volume dialog > Expanded volume dialog (multiple sliders)
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
VOLUME_DIALOG_DETAILS = 208;
// ACTION: Volume dialog > Adjust volume slider
// SUBTYPE: volume level (0-7)
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_VOLUME_SLIDER = 209;
// ACTION: Volume dialog > Select non-active stream
// SUBTYPE: stream (defined in AudioSystem.java)
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_VOLUME_STREAM = 210;
// ACTION: Adjust volume with hardware key
// SUBTYPE: volume level (0-7)
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_VOLUME_KEY = 211;
// ACTION: Volume dialog > Mute a stream by tapping icon
// SUBTYPE: mute is 1, audible is 2
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_VOLUME_ICON = 212;
// ACTION: Volume dialog > Change ringer mode by tapping icon
// SUBTYPE: 2 is audible, 3 is vibrate
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_RINGER_MODE = 213;
// ACTION: Chooser shown (share target, file open, etc.)
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
// ACTION: Chooser > User taps an app target
// SUBTYPE: Index of target
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
// ACTION: Chooser > User taps a service target
// SUBTYPE: Index of target
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
// ACTION: Chooser > User taps a standard target
// SUBTYPE: Index of target
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
// ACTION: QS Brightness Slider (with auto brightness disabled)
// SUBTYPE: slider value
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BRIGHTNESS = 218;
// ACTION: QS Brightness Slider (with auto brightness enabled)
// SUBTYPE: slider value
// CATEGORY: QUICK_SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_BRIGHTNESS_AUTO = 219;
// OPEN: Settings > Display > Brightness Slider
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
BRIGHTNESS_DIALOG = 220;
// OPEN: Settings > Apps > Configure Apps > Draw over other apps
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
SYSTEM_ALERT_WINDOW_APPS = 221;
// OPEN: Display has entered dream mode
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
DREAMING = 222;
// OPEN: Display has entered ambient notification mode
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
DOZING = 223;
// OPEN: Overview
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
OVERVIEW_ACTIVITY = 224;
// OPEN: Settings > About phone > Legal information
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ABOUT_LEGAL_SETTINGS = 225;
// OPEN: Settings > Search > Perform search
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
ACTION_SEARCH_RESULTS = 226;
// OPEN: Settings > System UI Tuner
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER = 227;
// OPEN: Settings > System UI Tuner > Quick Settings
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_QS = 228;
// OPEN: Settings > System UI Tuner > Demo mode
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_DEMO_MODE = 229;
// ACTION: Settings > System UI Tuner > Quick Settings > Move tile
// PACKAGE: Tile
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_QS_REORDER = 230;
// ACTION: Settings > System UI Tuner > Quick Settings > Add tile
// PACKAGE: Tile
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_QS_ADD = 231;
// ACTION: Settings > System UI Tuner > Quick Settings > Remove tile
// PACKAGE: Tile
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_QS_REMOVE = 232;
// ACTION: Settings > System UI Tuner > Status bar > Enable icon
// PACKAGE: Icon
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_STATUS_BAR_ENABLE = 233;
// ACTION: Settings > System UI Tuner > Status bar > Disable icon
// PACKAGE: Icon
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_STATUS_BAR_DISABLE = 234;
// ACTION: Settings > System UI Tuner > Demo mode > Enable demo mode
// SUBTYPE: false is disabled, true is enabled
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_DEMO_MODE_ENABLED = 235;
// ACTION: Settings > System UI Tuner > Demo mode > Show demo mode
// SUBTYPE: false is disabled, true is enabled
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_DEMO_MODE_ON = 236;
// ACTION: Settings > System UI Tuner > Show embedded battery percentage
// SUBTYPE: 0 is disabled, 1 is enabled
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
TUNER_BATTERY_PERCENTAGE = 237;
// OPEN: Settings > Developer options > Inactive apps
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.5.26
FUELGAUGE_INACTIVE_APPS = 238;
// ACTION: Long press home to bring up assistant
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.5.26
ACTION_ASSIST_LONG_PRESS = 239;
// OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLLING = 240;
// OPEN: Fingerprint Enroll > Find Sensor
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_FIND_SENSOR = 241;
// OPEN: Fingerprint Enroll > Fingerprint Enrolled!
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_FINISH = 242;
// OPEN: Fingerprint Enroll introduction
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_INTRO = 243;
// OPEN: Fingerprint Enroll onboarding
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_ONBOARD = 244;
// OPEN: Fingerprint Enroll > Let's Start!
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_SIDECAR = 245;
// OPEN: Fingerprint Enroll SUW > Let's Start!
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLLING_SETUP = 246;
// OPEN: Fingerprint Enroll SUW > Find Sensor
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_FIND_SENSOR_SETUP = 247;
// OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_FINISH_SETUP = 248;
// OPEN: Fingerprint Enroll SUW introduction
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_INTRO_SETUP = 249;
// OPEN: Fingerprint Enroll SUW onboarding
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
// ACTION: Add fingerprint > Enroll fingerprint
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
ACTION_FINGERPRINT_ENROLL = 251;
// ACTION: Authenticate using fingerprint
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
ACTION_FINGERPRINT_AUTH = 252;
// ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
ACTION_FINGERPRINT_DELETE = 253;
// ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
// CATEGORY: SETTINGS
// OS: 6.0
- // GMS: 7.8.99
ACTION_FINGERPRINT_RENAME = 254;
// ACTION: Double tap camera shortcut
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.8.99
ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
// ACTION: Double twist camera shortcut
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: 6.0
- // GMS: 7.8.99
ACTION_WIGGLE_CAMERA_GESTURE = 256;
// OPEN: QS Work Mode tile shown
@@ -1569,13 +1335,11 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: N
- // GMS: 7.8.99
QS_WORKMODE = 257;
// OPEN: Settings > Developer Options > Background Check
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
BACKGROUND_CHECK_SUMMARY = 258;
// OPEN: QS Lock tile shown
@@ -1583,52 +1347,44 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: N
- // GMS: 7.8.99
QS_LOCK_TILE = 259;
// OPEN: QS User Tile shown
// CATEGORY: QUICK_SETTINGS
// OS: N
- // GMS: 7.8.99
QS_USER_TILE = 260;
// OPEN: QS Battery tile shown
// CATEGORY: QUICK_SETTINGS
// OS: N
- // GMS: 7.8.99
QS_BATTERY_TILE = 261;
// OPEN: Settings > Sound > Do not disturb > Visual interruptions
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262;
// ACTION: Visual interruptions > No screen interuptions toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF = 263;
// ACTION: Visual interruptions > No notification light toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_ZEN_ALLOW_LIGHTS = 264;
// OPEN: Settings > Notifications > [App] > Topic Notifications
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
NOTIFICATION_TOPIC_NOTIFICATION = 265;
// ACTION: Settings > Apps > Default Apps > Select different SMS app
// PACKAGE: Selected SMS app
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_DEFAULT_SMS_APP_CHANGED = 266;
// OPEN: QS Color modification tile shown
@@ -1636,105 +1392,88 @@
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: QUICK_SETTINGS
// OS: N
- // GMS: 7.8.99
QS_COLOR_MATRIX = 267;
// OPEN: QS Custom tile shown
// ACTION: QS Work Mode tile tapped
// CATEGORY: QUICK_SETTINGS
// OS: N
- // GMS: 7.8.99
QS_CUSTOM = 268;
// ACTION: Visual interruptions > Never turn off the screen toggle
// SUBTYPE: 0 is off, 1 is on
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_ZEN_ALLOW_WHEN_SCREEN_ON = 269;
// ACTION: Overview > Long-press task, drag to enter split-screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_WINDOW_DOCK_DRAG_DROP = 270;
// ACTION: In App > Long-press Overview button to enter split-screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_WINDOW_DOCK_LONGPRESS = 271;
// ACTION: In App > Swipe Overview button to enter split-screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_WINDOW_DOCK_SWIPE = 272;
// ACTION: Launch profile-specific app > Confirm credentials
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
PROFILE_CHALLENGE = 273;
// OPEN: QS Battery detail panel
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
QS_BATTERY_DETAIL = 274;
// OPEN: Overview > History
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
OVERVIEW_HISTORY = 275;
// ACTION: Overview > Page by tapping Overview button
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_OVERVIEW_PAGE = 276;
// ACTION: Overview > Select app
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_OVERVIEW_SELECT = 277;
// ACTION: View emergency info
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_VIEW_EMERGENCY_INFO = 278;
// ACTION: Edit emergency info activity
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_EDIT_EMERGENCY_INFO = 279;
// ACTION: Edit emergency info field
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_EDIT_EMERGENCY_INFO_FIELD = 280;
// ACTION: Add emergency contact
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_ADD_EMERGENCY_CONTACT = 281;
// ACTION: Delete emergency contact
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_DELETE_EMERGENCY_CONTACT = 282;
// ACTION: Call emergency contact
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
ACTION_CALL_EMERGENCY_CONTACT = 283;
// OPEN: QS Data Saver tile shown
@@ -1745,13 +1484,11 @@
// OPEN: Settings > Security > User credentials
// CATEGORY: Settings
// OS: N
- // GMS: 7.8.99
USER_CREDENTIALS = 285;
// ACTION: In App (splitscreen) > Long-press Overview to exit split-screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_WINDOW_UNDOCK_LONGPRESS = 286;
// Logged when the user scrolls through overview manually
@@ -1773,81 +1510,68 @@
// ACTION: Long-press power button, then tap "Take bug report" option.
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292;
// ACTION: Long-press power button, then long-press "Take bug report" option.
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293;
// ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
// Interactive bug report initiated from Settings.
ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
// ACTION: Settings -> Developer Options -> Take bug report -> Full report
// CATEGORY: SETTINGS
// OS: N
- // GMS: 7.8.99
// Interactive bug report initiated from Settings.
ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
// ACTION: User tapped notification action to cancel a bug report
// CATEGORY: NOTIFICATION
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
// ACTION: User tapped notification action to launch bug report details screen
// CATEGORY: NOTIFICATION
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297;
// ACTION: User tapped notification action to take adition screenshot on bug report
// CATEGORY: NOTIFICATION
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298;
// ACTION: User tapped notification to share bug report
// CATEGORY: NOTIFICATION
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
// ACTION: User changed bug report name using the details screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300;
// ACTION: User changed bug report title using the details screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301;
// ACTION: User changed bug report description using the details screen
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302;
// ACTION: User tapped Save in the bug report details screen.
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_SAVED = 303;
// ACTION: User tapped Cancel in the bug report details screen.
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: N
- // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_CANCELED = 304;
// Tuner: Open/close calibrate dialog.
@@ -1920,79 +1644,140 @@
// the transition was executed.
APP_TRANSITION_DEVICE_UPTIME_SECONDS = 325;
- // User granted access to the request folder; action takes an integer
- // representing the folder's index on Environment.STANDARD_DIRECTORIES
- // (or -2 for root access, or -1 or unknown directory).
+ // ACTION: app requested access to a scoped directory, user granted it.
+ // SUBTYPE: directory's index on Environment.STANDARD_DIRECTORIES
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER = 326;
- // User denied access to the request folder; action takes an integer
- // representing the folder's index on Environment.STANDARD_DIRECTORIES
- // (or -2 for root access, or -1 or unknown directory).
+ // ACTION: app requested access to a scoped directory, user denied it.
+ // SUBTYPE: directory's index on Environment.STANDARD_DIRECTORIES
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER = 327;
- // User granted access to the request folder; action pass package name
- // of calling package.
+ // ACTION: app requested access to a scoped directory, user granted it.
+ // PACKAGE: app that requested access
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE = 328;
- // User denied access to the request folder; action pass package name
- // of calling package.
+ // ACTION: app requested access to a scoped directory, user denied it.
+ // PACKAGE: app that requested access.
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE = 329;
- // App requested access to a directory it has already been granted
- // access before; action takes an integer representing the folder's
- // index on Environment.STANDARD_DIRECTORIES
- // (or -2 for root access, or -1 or unknown directory).
+ // ACTION: app requested access to a directory user has already been granted
+ // access before.
+ // SUBTYPE: directory's index on Environment.STANDARD_DIRECTORIES.
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER = 330;
- // App requested access to a directory it has already been granted
- // access before; action pass package name of calling package.
+ // ACTION: app requested access to a directory user has already been granted
+ // access before.
+ // PACKAGE: app that requested access.
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE = 331;
- // Logged when the user slides a notification and
- // reveals the gear beneath it.
+ // ACTION: Logged when the user slides a notification and reveals the gear
+ // beneath it.
+ // CATEGORY: NOTIFICATION
+ // OS: N
ACTION_REVEAL_GEAR = 332;
- // Logged when the user taps on the gear beneath
- // a notification.
+ // ACTION: Logged when the user taps on the gear beneath a notification.
+ // CATEGORY: NOTIFICATION
+ // OS: N
ACTION_TOUCH_GEAR = 333;
// Logs that the user has edited the enabled VR listeners.
+ // CATEGORY: SETTINGS
+ // OS: N
VR_MANAGE_LISTENERS = 334;
// Settings -> Accessibility -> Click after pointer stops moving
+ // CATEGORY: SETTINGS
+ // OS: N
ACCESSIBILITY_TOGGLE_AUTOCLICK = 335;
+
// Settings -> Sound
+ // CATEGORY: SETTINGS
+ // OS: N
SOUND = 336;
+
// Settings -> Notifications -> Gear
+ // CATEGORY: SETTINGS
+ // OS: N
CONFIGURE_NOTIFICATION = 337;
+
// Settings -> Wi-Fi -> Gear
+ // CATEGORY: SETTINGS
+ // OS: N
CONFIGURE_WIFI = 338;
+
// Settings -> Display -> Display size
+ // OS: N
DISPLAY_SCREEN_ZOOM = 339;
+
// Settings -> Display -> Font size
+ // CATEGORY: SETTINGS
+ // OS: N
ACCESSIBILITY_FONT_SIZE = 340;
+
// Settings -> Data usage -> Cellular/Wi-Fi data usage
+ // CATEGORY: SETTINGS
+ // OS: N
DATA_USAGE_LIST = 341;
+
// Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear
+ // CATEGORY: SETTINGS
+ // OS: N
BILLING_CYCLE = 342;
+
// DATA_USAGE_LIST -> Any item or App info -> Data usage
+ // CATEGORY: SETTINGS
+ // OS: N
APP_DATA_USAGE = 343;
+
// Settings -> Language & input -> Language
+ // CATEGORY: SETTINGS
+ // OS: N
USER_LOCALE_LIST = 344;
+
// Settings -> Language & input -> Virtual keyboard
+ // CATEGORY: SETTINGS
+ // OS: N
VIRTUAL_KEYBOARDS = 345;
+
// Settings -> Language & input -> Physical keyboard
+ // CATEGORY: SETTINGS
+ // OS: N
PHYSICAL_KEYBOARDS = 346;
+
// Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard
+ // CATEGORY: SETTINGS
+ // OS: N
ENABLE_VIRTUAL_KEYBOARDS = 347;
+
// Settings -> Data usage -> Data Saver
+ // CATEGORY: SETTINGS
+ // OS: N
DATA_SAVER_SUMMARY = 348;
+
// Settings -> Data usage -> Data Saver -> Unrestricted data access
+ // CATEGORY: SETTINGS
+ // OS: N
DATA_USAGE_UNRESTRICTED_ACCESS = 349;
// Used for generic logging of Settings Preference Persistence, should not be used
// outside SharedPreferencesLogger.
+ // CATEGORY: SETTINGS
+ // OS: N
ACTION_GENERIC_PACKAGE = 350;
+
// Settings -> Apps -> Gear -> Special access
SPECIAL_ACCESS = 351;
@@ -2158,15 +1943,28 @@
// System UI Tuner > Other > Power notification controls > Toggle on/off
ACTION_TUNER_POWER_NOTIFICATION_CONTROLS = 393;
- // Action: user enable / disabled data saver using Settings. Arguments:
- // 0: Data Saver mode is disabled.
- // 1: Data Saver mode is enabled.
+ // Action: user enable / disabled data saver using Settings
+ // OPEN: Settings -> Data Usage -> Data saver -> On/off toggle
+ // VALUE: 1 for enabled, 0 for disabled
+ // CATEGORY: SETTINGS
+ // OS: N
ACTION_DATA_SAVER_MODE = 394;
- // User whitelisted an app for Data Saver mode; action pass package name of app.
+ // User whitelisted an app for Data Saver mode; action pass package name of app
+ // Action: user enable / disabled data saver using Settings
+ // OPEN: Settings -> Data Usage -> Data saver -> Unrestricted data access > APP toggle turned on
+ // or
+ // Settings -> Apps -> APP -> Data usage -> Unrestricted data usage toggle turned on
+ // VALUE: package name of APP
+ // CATEGORY: SETTINGS
+ // OS: N
ACTION_DATA_SAVER_WHITELIST = 395;
- // User blacklisted an app for Data Saver mode; action pass package name of app.
+ // User blacklisted an app for Data Saver mode; action pass package name of app
+ // OPEN: Settings -> Apps -> APP -> Data usage -> Background data toggle turned off
+ // VALUE: package name of APP
+ // CATEGORY: SETTINGS
+ // OS: N
ACTION_DATA_SAVER_BLACKLIST = 396;
// User opened a remote input view associated with a notification. Passes package name of app
@@ -2332,45 +2130,70 @@
SUPPORT_FRAGMENT = 475;
// ACTION: Settings -> Select summary tab.
+ // CATEGORY: SETTINGS
ACTION_SELECT_SUMMARY=476;
// ACTION: Settings -> Select support tab.
+ // CATEGORY: SETTINGS
ACTION_SELECT_SUPPORT_FRAGMENT = 477;
// ACTION: Settings -> Support -> Tips & tricks
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_TIPS_AND_TRICKS = 478;
// ACTION: Settings -> Support -> Help & feedback
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_HELP_AND_FEEDBACK = 479;
// ACTION: Settings -> Support -> Sign in
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_SIGN_IN = 480;
// ACTION: Settings -> Support -> Phone
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_PHONE = 481;
// ACTION: Settings -> Support -> Chat
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_CHAT = 482;
// ACTION: Settings -> Support -> Phone/Chat -> Disclaimer Cancel
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_DISCLAIMER_CANCEL = 483;
// ACTION: Settings -> Support -> Phone/Chat -> Disclaimer OK
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_DISCLAIMER_OK = 484;
// ACTION: Settings -> Support -> Toll-Free Phone
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_DAIL_TOLLFREE = 485;
// ACTION: Settings -> Support -> "Travel Abroad" Button
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_VIEW_TRAVEL_ABROAD_DIALOG = 486;
// ACTION: Settings -> Support -> "Travel Abroad" Button -> Tolled Phone
+ // CATEGORY: SETTINGS
ACTION_SUPPORT_DIAL_TOLLED = 487;
// OPEN: Settings > Display > Night display
// CATEGORY: SETTINGS
NIGHT_DISPLAY_SETTINGS = 488;
+ // ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager
+ // SUBTYPE: false is off, true is on
+ ACTION_TOGGLE_STORAGE_MANAGER = 489;
+
+ // Settings launched from collapsed quick settings.
+ ACTION_QS_COLLAPSED_SETTINGS_LAUNCH = 490;
+
+ // OPEN: QS Night mode tile shown
+ // ACTION: QS Night mode tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ QS_NIGHT_DISPLAY = 491;
+
// ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
// ------- Begin N Keyboard Shortcuts Helper -----
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7a12289..ba426b3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1422,7 +1422,8 @@
updateTouchExplorationLocked(userState);
updatePerformGesturesLocked(userState);
updateEnhancedWebAccessibilityLocked(userState);
- updateDisplayColorAdjustmentSettingsLocked(userState);
+ updateDisplayDaltonizerLocked(userState);
+ updateDisplayInversionLocked(userState);
updateMagnificationLocked(userState);
updateSoftKeyboardShowModeLocked(userState);
scheduleUpdateInputFilter(userState);
@@ -1539,7 +1540,6 @@
somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
somethingChanged |= readAutoclickEnabledSettingLocked(userState);
- somethingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
return somethingChanged;
}
@@ -1602,18 +1602,6 @@
return false;
}
- private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) {
- final boolean displayAdjustmentsEnabled = DisplayAdjustmentUtils.hasAdjustments(mContext,
- userState.mUserId);
- if (displayAdjustmentsEnabled != userState.mHasDisplayColorAdjustment) {
- userState.mHasDisplayColorAdjustment = displayAdjustmentsEnabled;
- return true;
- }
- // If display adjustment is enabled, always assume there was a change in
- // the adjustment settings.
- return displayAdjustmentsEnabled;
- }
-
private boolean readHighTextContrastEnabledSettingLocked(UserState userState) {
final boolean highTextContrastEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
@@ -1730,8 +1718,12 @@
return false;
}
- private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) {
- DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
+ private void updateDisplayDaltonizerLocked(UserState userState) {
+ DisplayAdjustmentUtils.applyDaltonizerSetting(mContext, userState.mUserId);
+ }
+
+ private void updateDisplayInversionLocked(UserState userState) {
+ DisplayAdjustmentUtils.applyInversionSetting(mContext, userState.mUserId);
}
private void updateMagnificationLocked(UserState userState) {
@@ -4201,7 +4193,6 @@
public boolean mIsAutoclickEnabled;
public boolean mIsPerformGesturesEnabled;
public boolean mIsFilterKeyEventsEnabled;
- public boolean mHasDisplayColorAdjustment;
public boolean mAccessibilityFocusOnlyInActiveWindow;
private Service mUiAutomationService;
@@ -4317,9 +4308,6 @@
private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
- private final Uri mDisplayColorMatrixUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
-
private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
@@ -4351,8 +4339,6 @@
contentResolver.registerContentObserver(
mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
mHighTextContrastUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
@@ -4394,14 +4380,11 @@
if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
onUserStateChangedLocked(userState);
}
- } else if (mDisplayInversionEnabledUri.equals(uri)
- || mDisplayDaltonizerEnabledUri.equals(uri)
+ } else if (mDisplayDaltonizerEnabledUri.equals(uri)
|| mDisplayDaltonizerUri.equals(uri)) {
- if (readDisplayColorAdjustmentSettingsLocked(userState)) {
- updateDisplayColorAdjustmentSettingsLocked(userState);
- }
- } else if (mDisplayColorMatrixUri.equals(uri)) {
- updateDisplayColorAdjustmentSettingsLocked(userState);
+ updateDisplayDaltonizerLocked(userState);
+ } else if (mDisplayInversionEnabledUri.equals(uri)) {
+ updateDisplayInversionLocked(userState);
} else if (mHighTextContrastUri.equals(uri)) {
if (readHighTextContrastEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index e1f3cd8..1532946 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -18,23 +18,23 @@
import android.content.ContentResolver;
import android.content.Context;
-import android.opengl.Matrix;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.util.Slog;
+import android.provider.Settings.Secure;
import android.view.accessibility.AccessibilityManager;
+import com.android.server.LocalServices;
+import com.android.server.display.DisplayTransformManager;
+
/**
* Utility methods for performing accessibility display adjustments.
*/
class DisplayAdjustmentUtils {
- private static final String LOG_TAG = DisplayAdjustmentUtils.class.getSimpleName();
+
+ /** Default inversion mode for display color correction. */
+ private static final int DEFAULT_DISPLAY_DALTONIZER =
+ AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
/** Matrix and offset used for converting color to gray-scale. */
- private static final float[] GRAYSCALE_MATRIX = new float[] {
+ private static final float[] MATRIX_GRAYSCALE = new float[] {
.2126f, .2126f, .2126f, 0,
.7152f, .7152f, .7152f, 0,
.0722f, .0722f, .0722f, 0,
@@ -48,150 +48,44 @@
* represents a non-multiplied addition, see surfaceflinger's ProgramCache
* for full implementation details.
*/
- private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
+ private static final float[] MATRIX_INVERT_COLOR = new float[] {
0.402f, -0.598f, -0.599f, 0,
-1.174f, -0.174f, -1.175f, 0,
-0.228f, -0.228f, 0.772f, 0,
1, 1, 1, 1
};
- /** Default inversion mode for display color correction. */
- private static final int DEFAULT_DISPLAY_DALTONIZER =
- AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
-
- /**
- * Returns whether the specified user with has any display color
- * adjustments.
- */
- public static boolean hasAdjustments(Context context, int userId) {
+ public static void applyDaltonizerSetting(Context context, int userId) {
final ContentResolver cr = context.getContentResolver();
+ final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
- if (Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
- return true;
+ int daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
+ if (Secure.getIntForUser(cr,
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
+ daltonizerMode = Secure.getIntForUser(cr,
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, userId);
}
- if (Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
- return true;
+ float[] grayscaleMatrix = null;
+ if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
+ // Monochromacy isn't supported by the native Daltonizer.
+ grayscaleMatrix = MATRIX_GRAYSCALE;
+ daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
}
-
- return false;
+ dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, grayscaleMatrix);
+ dtm.setDaltonizerMode(daltonizerMode);
}
/**
* Applies the specified user's display color adjustments.
*/
- public static void applyAdjustments(Context context, int userId) {
+ public static void applyInversionSetting(Context context, int userId) {
final ContentResolver cr = context.getContentResolver();
- float[] colorMatrix = null;
+ final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
- if (Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
- colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY);
- }
-
- if (Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
- final int daltonizerMode = Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER,
- userId);
- // Monochromacy isn't supported by the native Daltonizer.
- if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
- colorMatrix = multiply(colorMatrix, GRAYSCALE_MATRIX);
- setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
- } else {
- setDaltonizerMode(daltonizerMode);
- }
- } else {
- setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
- }
-
- String matrix = Settings.Secure.getStringForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, userId);
- if (matrix != null) {
- final float[] userMatrix = get4x4Matrix(matrix);
- if (userMatrix != null) {
- colorMatrix = multiply(colorMatrix, userMatrix);
- }
- }
-
- setColorTransform(colorMatrix);
+ final boolean invertColors = Secure.getIntForUser(cr,
+ Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0;
+ dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
+ invertColors ? MATRIX_INVERT_COLOR : null);
}
-
- private static float[] get4x4Matrix(String matrix) {
- String[] strValues = matrix.split(",");
- if (strValues.length != 16) {
- return null;
- }
- float[] values = new float[strValues.length];
- try {
- for (int i = 0; i < values.length; i++) {
- values[i] = Float.parseFloat(strValues[i]);
- }
- } catch (java.lang.NumberFormatException ex) {
- return null;
- }
- return values;
- }
-
- private static float[] multiply(float[] matrix, float[] other) {
- if (matrix == null) {
- return other;
- }
- float[] result = new float[16];
- Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
- return result;
- }
-
- /**
- * Sets the surface flinger's Daltonization mode. This adjusts the color
- * space to correct for or simulate various types of color blindness.
- *
- * @param mode new Daltonization mode
- */
- private static void setDaltonizerMode(int mode) {
- try {
- final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
- if (flinger != null) {
- final Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- data.writeInt(mode);
- flinger.transact(1014, data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex);
- }
- }
-
- /**
- * Sets the surface flinger's color transformation as a 4x4 matrix. If the
- * matrix is null, color transformations are disabled.
- *
- * @param m the float array that holds the transformation matrix, or null to
- * disable transformation
- */
- private static void setColorTransform(float[] m) {
- try {
- final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
- if (flinger != null) {
- final Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- if (m != null) {
- data.writeInt(1);
- for (int i = 0; i < 16; i++) {
- data.writeFloat(m[i]);
- }
- } else {
- data.writeInt(0);
- }
- flinger.transact(1015, data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(LOG_TAG, "Failed to set color transform", ex);
- }
- }
-
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 294280b..497eac9 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -4328,7 +4328,10 @@
Slog.e(TAG, "Internal exception during full backup", e);
} finally {
try {
- if (out != null) out.close();
+ if (out != null) {
+ out.flush();
+ out.close();
+ }
mOutputFile.close();
} catch (IOException e) {
/* nothing we can do about this */
@@ -5498,11 +5501,11 @@
// If the policy is satisfied, go ahead and set up to pipe the
// data to the agent.
- if (DEBUG && okay && mAgent != null) {
+ if (MORE_DEBUG && okay && mAgent != null) {
Slog.i(TAG, "Reusing existing agent instance");
}
if (okay && mAgent == null) {
- if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
+ if (MORE_DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
try {
mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
@@ -5704,16 +5707,21 @@
}
void tearDownPipes() {
- if (mPipes != null) {
- try {
- mPipes[0].close();
- mPipes[0] = null;
- mPipes[1].close();
- mPipes[1] = null;
- } catch (IOException e) {
- Slog.w(TAG, "Couldn't close agent pipes", e);
+ // Teardown might arise from the inline restore processing or from the asynchronous
+ // timeout mechanism, and these might race. Make sure we don't try to close and
+ // null out the pipes twice.
+ synchronized (this) {
+ if (mPipes != null) {
+ try {
+ mPipes[0].close();
+ mPipes[0] = null;
+ mPipes[1].close();
+ mPipes[1] = null;
+ } catch (IOException e) {
+ Slog.w(TAG, "Couldn't close agent pipes", e);
+ }
+ mPipes = null;
}
- mPipes = null;
}
}
diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java
index a8ae914d..f93c716 100644
--- a/services/core/java/com/android/server/AnyMotionDetector.java
+++ b/services/core/java/com/android/server/AnyMotionDetector.java
@@ -70,6 +70,9 @@
/** The interval between accelerometer orientation measurements. */
private static final long ORIENTATION_MEASUREMENT_INTERVAL_MILLIS = 5000;
+ /** The maximum duration we will hold a wakelock to determine stationary status. */
+ private static final long WAKELOCK_TIMEOUT_MILLIS = 30000;
+
/**
* The duration in milliseconds after which an orientation measurement is considered
* too stale to be used.
@@ -141,25 +144,30 @@
mCurrentGravityVector = null;
mPreviousGravityVector = null;
mWakeLock.acquire();
+ Message wakelockTimeoutMsg = Message.obtain(mHandler, mWakelockTimeout);
+ mHandler.sendMessageDelayed(wakelockTimeoutMsg, WAKELOCK_TIMEOUT_MILLIS);
startOrientationMeasurementLocked();
}
}
}
public void stop() {
- if (mState == STATE_ACTIVE) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mState == STATE_ACTIVE) {
mState = STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE.");
- if (mMeasurementInProgress) {
- mMeasurementInProgress = false;
- mSensorManager.unregisterListener(mListener);
- }
- mHandler.removeCallbacks(mMeasurementTimeout);
- mHandler.removeCallbacks(mSensorRestart);
- mCurrentGravityVector = null;
- mPreviousGravityVector = null;
+ }
+ if (mMeasurementInProgress) {
+ mMeasurementInProgress = false;
+ mSensorManager.unregisterListener(mListener);
+ }
+ mHandler.removeCallbacks(mMeasurementTimeout);
+ mHandler.removeCallbacks(mSensorRestart);
+ mCurrentGravityVector = null;
+ mPreviousGravityVector = null;
+ if (mWakeLock.isHeld()) {
mWakeLock.release();
+ mHandler.removeCallbacks(mWakelockTimeout);
}
}
}
@@ -173,9 +181,8 @@
mMeasurementInProgress = true;
mRunningStats.reset();
}
- Message msg = Message.obtain(mHandler, mMeasurementTimeout);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, ACCELEROMETER_DATA_TIMEOUT_MILLIS);
+ Message measurementTimeoutMsg = Message.obtain(mHandler, mMeasurementTimeout);
+ mHandler.sendMessageDelayed(measurementTimeoutMsg, ACCELEROMETER_DATA_TIMEOUT_MILLIS);
}
}
@@ -186,10 +193,12 @@
if (mMeasurementInProgress) {
mSensorManager.unregisterListener(mListener);
mHandler.removeCallbacks(mMeasurementTimeout);
- long detectionEndTime = SystemClock.elapsedRealtime();
mMeasurementInProgress = false;
mPreviousGravityVector = mCurrentGravityVector;
mCurrentGravityVector = mRunningStats.getRunningAverage();
+ if (mRunningStats.getSampleCount() == 0) {
+ Slog.w(TAG, "No accelerometer data acquired for orientation measurement.");
+ }
if (DEBUG) {
Slog.d(TAG, "mRunningStats = " + mRunningStats.toString());
String currentGravityVectorString = (mCurrentGravityVector == null) ?
@@ -203,7 +212,10 @@
status = getStationaryStatus();
if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status);
if (status != RESULT_UNKNOWN) {
- mWakeLock.release();
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ mHandler.removeCallbacks(mWakelockTimeout);
+ }
if (DEBUG) {
Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE. status = " + status);
}
@@ -217,7 +229,6 @@
" scheduled in " + ORIENTATION_MEASUREMENT_INTERVAL_MILLIS +
" milliseconds.");
Message msg = Message.obtain(mHandler, mSensorRestart);
- msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ORIENTATION_MEASUREMENT_INTERVAL_MILLIS);
}
}
@@ -271,6 +282,7 @@
}
}
if (status != RESULT_UNKNOWN) {
+ mHandler.removeCallbacks(mWakelockTimeout);
mCallback.onAnyMotionResult(status);
}
}
@@ -290,20 +302,30 @@
};
private final Runnable mMeasurementTimeout = new Runnable() {
- @Override
- public void run() {
- int status = RESULT_UNKNOWN;
- synchronized (mLock) {
- if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
+ @Override
+ public void run() {
+ int status = RESULT_UNKNOWN;
+ synchronized (mLock) {
+ if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
"data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
"orientation measurement.");
- status = stopOrientationMeasurementLocked();
- }
- if (status != RESULT_UNKNOWN) {
- mCallback.onAnyMotionResult(status);
- }
- }
- };
+ status = stopOrientationMeasurementLocked();
+ }
+ if (status != RESULT_UNKNOWN) {
+ mHandler.removeCallbacks(mWakelockTimeout);
+ mCallback.onAnyMotionResult(status);
+ }
+ }
+ };
+
+ private final Runnable mWakelockTimeout = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ stop();
+ }
+ }
+ };
/**
* A timestamped three dimensional vector and some vector operations.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1e95a93..c32fc78 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2286,7 +2286,7 @@
if (VDBG) log("NetworkFactory connected");
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (!nri.request.isRequest()) continue;
+ if (nri.request.isListen()) continue;
NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
@@ -2428,7 +2428,7 @@
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
mNetworkRequests.put(nri.request, nri);
mNetworkRequestInfoLogs.log("REGISTER " + nri);
- if (!nri.request.isRequest()) {
+ if (nri.request.isListen()) {
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
if (nri.request.networkCapabilities.hasSignalStrength() &&
network.satisfiesImmutableCapabilitiesOf(nri.request)) {
@@ -4576,7 +4576,7 @@
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
// Don't send listening requests to factories. b/17393458
- if (!nr.isRequest()) continue;
+ if (nr.isListen()) continue;
sendUpdatedScoreToFactories(nr, nai.getCurrentScore());
}
}
@@ -4670,7 +4670,7 @@
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
// Ignore listening requests.
- if (!nr.isRequest()) continue;
+ if (nr.isListen()) continue;
loge("Dead network still had at least " + nr);
break;
}
@@ -4762,7 +4762,7 @@
// check if it satisfies the NetworkCapabilities
if (VDBG) log(" checking if request is satisfied: " + nri.request);
if (satisfies) {
- if (!nri.request.isRequest()) {
+ if (nri.request.isListen()) {
// This is not a request, it's a callback listener.
// Add it to newNetwork regardless of score.
if (newNetwork.addRequest(nri.request)) addedRequests.add(nri);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index afed5ef..488f0e7 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -973,13 +973,12 @@
cancelSensingTimeoutAlarmLocked();
}
}
- if (result == AnyMotionDetector.RESULT_MOVED) {
- if (DEBUG) Slog.d(TAG, "RESULT_MOVED received.");
+ if ((result == AnyMotionDetector.RESULT_MOVED) ||
+ (result == AnyMotionDetector.RESULT_UNKNOWN)) {
synchronized (this) {
- handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "sense_motion");
+ handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "non_stationary");
}
} else if (result == AnyMotionDetector.RESULT_STATIONARY) {
- if (DEBUG) Slog.d(TAG, "RESULT_STATIONARY received.");
if (mState == STATE_SENSING) {
// If we are currently sensing, it is time to move to locating.
synchronized (this) {
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 5a90488..553cb07 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -33,6 +33,7 @@
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.MutableBoolean;
import android.util.Slog;
@@ -284,8 +285,8 @@
* @return true if camera was launched, false otherwise.
*/
private boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
- boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
+ boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
if (!userSetupComplete) {
if (DBG) Slog.d(TAG, String.format(
"userSetupComplete = %s, ignoring camera launch gesture.",
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index e28fa73..0cce2a2 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -584,6 +584,18 @@
Slog.e(TAG, "Invalid tied profile lock type: " + quality);
}
}
+ try {
+ final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
+ java.security.KeyStore keyStore =
+ java.security.KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ if (keyStore.containsAlias(alias)) {
+ keyStore.deleteEntry(alias);
+ }
+ } catch (KeyStoreException | NoSuchAlgorithmException |
+ CertificateException | IOException e) {
+ Slog.e(TAG, "Unable to remove tied profile key", e);
+ }
}
} catch (RemoteException re) {
Slog.e(TAG, "Unable to migrate old data", re);
@@ -1027,37 +1039,38 @@
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
-
java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
- keyStore.setEntry(
- LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
- new java.security.KeyStore.SecretKeyEntry(secretKey),
- new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
- .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
- .build());
- keyStore.setEntry(
- LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
- new java.security.KeyStore.SecretKeyEntry(secretKey),
- new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
- .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
- .setUserAuthenticationRequired(true)
- .setUserAuthenticationValidityDurationSeconds(30)
- .build());
-
- // Key imported, obtain a reference to it.
- SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
- LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
- // The original key can now be discarded.
-
- Cipher cipher = Cipher.getInstance(
- KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
- + KeyProperties.ENCRYPTION_PADDING_NONE);
- cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
- encryptionResult = cipher.doFinal(randomLockSeed);
- iv = cipher.getIV();
+ try {
+ keyStore.setEntry(
+ LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
+ new java.security.KeyStore.SecretKeyEntry(secretKey),
+ new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ keyStore.setEntry(
+ LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
+ new java.security.KeyStore.SecretKeyEntry(secretKey),
+ new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationValidityDurationSeconds(30)
+ .build());
+ // Key imported, obtain a reference to it.
+ SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
+ LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
+ Cipher cipher = Cipher.getInstance(
+ KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
+ + KeyProperties.ENCRYPTION_PADDING_NONE);
+ cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
+ encryptionResult = cipher.doFinal(randomLockSeed);
+ iv = cipher.getIV();
+ } finally {
+ // The original key can now be discarded.
+ keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
+ }
} catch (CertificateException | UnrecoverableKeyException
| IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
| NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index e233b1c..080b46c 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -157,11 +157,10 @@
}
}
- private void enforceFactoryResetAllowed() {
- final boolean isOemUnlockRestricted = UserManager.get(mContext)
- .hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET);
- if (isOemUnlockRestricted) {
- throw new SecurityException("OEM unlock is disallowed by DISALLOW_FACTORY_RESET");
+ private void enforceUserRestriction(String userRestriction) {
+ if (UserManager.get(mContext).hasUserRestriction(userRestriction)) {
+ throw new SecurityException(
+ "OEM unlock is disallowed by user restriction: " + userRestriction);
}
}
@@ -467,13 +466,9 @@
enforceIsAdmin();
if (enabled) {
- // Do not allow oem unlock to be enabled if it has been disallowed.
- if (Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.OEM_UNLOCK_DISALLOWED, 0) == 1) {
- throw new SecurityException(
- "OEM unlock has been disallowed by OEM_UNLOCK_DISALLOWED.");
- }
- enforceFactoryResetAllowed();
+ // Do not allow oem unlock to be enabled if it's disallowed by a user restriction.
+ enforceUserRestriction(UserManager.DISALLOW_OEM_UNLOCK);
+ enforceUserRestriction(UserManager.DISALLOW_FACTORY_RESET);
}
synchronized (mLock) {
doSetOemUnlockEnabledLocked(enabled);
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index eaf317a..7ea8f1f 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -41,6 +41,7 @@
import com.android.internal.app.ResolverActivity;
import com.android.internal.os.BackgroundThread;
+import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import java.util.ArrayList;
@@ -240,12 +241,6 @@
}
mPinnedCameraFiles.add(pf);
- //find the location of the odex based on the location of the APK
- int lastPeriod = camAPK.lastIndexOf('.');
- int lastSlash = camAPK.lastIndexOf('/', lastPeriod);
- String base = camAPK.substring(0, lastSlash);
- String appName = camAPK.substring(lastSlash + 1, lastPeriod);
-
// determine the ABI from either ApplicationInfo or Build
String arch = "arm";
if (cameraInfo.primaryCpuAbi != null
@@ -256,8 +251,18 @@
arch = arch + "64";
}
}
- String odex = base + "/oat/" + arch + "/" + appName + ".odex";
- //not all apps have odex files, so not pinning the odex is not a fatal error
+
+ // get the path to the odex or oat file
+ String baseCodePath = cameraInfo.getBaseCodePath();
+ String odex = null;
+ try {
+ odex = DexFile.getDexFileOutputPath(baseCodePath, arch);
+ } catch (IOException ioe) {}
+ if (odex == null) {
+ return true;
+ }
+
+ //not pinning the oat/odex is not a fatal error
pf = pinFile(odex, 0, 0, MAX_CAMERA_PIN_SIZE);
if (pf != null) {
mPinnedCameraFiles.add(pf);
@@ -265,6 +270,7 @@
Slog.i(TAG, "Pinned " + pf.mFilename);
}
}
+
return true;
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 5b7f99c..42d17f8 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1233,11 +1233,13 @@
} finally {
db.endTransaction();
}
- sendAccountsChangedBroadcast(accounts.userId);
}
if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
addAccountToLinkedRestrictedUsers(account, accounts.userId);
}
+
+ // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
+ sendAccountsChangedBroadcast(accounts.userId);
return true;
}
@@ -1420,7 +1422,6 @@
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
- boolean isSuccessful = false;
Account renamedAccount = new Account(newName, accountToRename.type);
try {
final long accountId = getAccountIdLocked(db, accountToRename);
@@ -1433,54 +1434,51 @@
values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
db.setTransactionSuccessful();
- isSuccessful = true;
logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_ACCOUNTS, accountId,
accounts);
}
} finally {
db.endTransaction();
- if (isSuccessful) {
- /*
- * Database transaction was successful. Clean up cached
- * data associated with the account in the user profile.
- */
- insertAccountIntoCacheLocked(accounts, renamedAccount);
- /*
- * Extract the data and token caches before removing the
- * old account to preserve the user data associated with
- * the account.
- */
- HashMap<String, String> tmpData = accounts.userDataCache.get(accountToRename);
- HashMap<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
- removeAccountFromCacheLocked(accounts, accountToRename);
- /*
- * Update the cached data associated with the renamed
- * account.
- */
- accounts.userDataCache.put(renamedAccount, tmpData);
- accounts.authTokenCache.put(renamedAccount, tmpTokens);
- accounts.previousNameCache.put(
- renamedAccount,
- new AtomicReference<String>(accountToRename.name));
- resultAccount = renamedAccount;
+ }
+ /*
+ * Database transaction was successful. Clean up cached
+ * data associated with the account in the user profile.
+ */
+ insertAccountIntoCacheLocked(accounts, renamedAccount);
+ /*
+ * Extract the data and token caches before removing the
+ * old account to preserve the user data associated with
+ * the account.
+ */
+ HashMap<String, String> tmpData = accounts.userDataCache.get(accountToRename);
+ HashMap<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
+ removeAccountFromCacheLocked(accounts, accountToRename);
+ /*
+ * Update the cached data associated with the renamed
+ * account.
+ */
+ accounts.userDataCache.put(renamedAccount, tmpData);
+ accounts.authTokenCache.put(renamedAccount, tmpTokens);
+ accounts.previousNameCache.put(
+ renamedAccount,
+ new AtomicReference<String>(accountToRename.name));
+ resultAccount = renamedAccount;
- int parentUserId = accounts.userId;
- if (canHaveProfile(parentUserId)) {
- /*
- * Owner or system user account was renamed, rename the account for
- * those users with which the account was shared.
- */
- List<UserInfo> users = getUserManager().getUsers(true);
- for (UserInfo user : users) {
- if (user.isRestricted()
- && (user.restrictedProfileParentId == parentUserId)) {
- renameSharedAccountAsUser(accountToRename, newName, user.id);
- }
- }
+ int parentUserId = accounts.userId;
+ if (canHaveProfile(parentUserId)) {
+ /*
+ * Owner or system user account was renamed, rename the account for
+ * those users with which the account was shared.
+ */
+ List<UserInfo> users = getUserManager().getUsers(true);
+ for (UserInfo user : users) {
+ if (user.isRestricted()
+ && (user.restrictedProfileParentId == parentUserId)) {
+ renameSharedAccountAsUser(accountToRename, newName, user.id);
}
- sendAccountsChangedBroadcast(accounts.userId);
}
}
+ sendAccountsChangedBroadcast(accounts.userId);
}
return resultAccount;
}
@@ -1661,7 +1659,7 @@
}
private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
- int deleted;
+ boolean isChanged = false;
boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
if (!userUnlocked) {
Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
@@ -1671,25 +1669,38 @@
final SQLiteDatabase db = userUnlocked
? accounts.openHelper.getWritableDatabaseUserIsUnlocked()
: accounts.openHelper.getWritableDatabase();
- final long accountId = getAccountIdLocked(db, account);
db.beginTransaction();
+ // Set to a dummy value, this will only be used if the database
+ // transaction succeeds.
+ long accountId = -1;
try {
- deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
- + "=?", new String[]{account.name, account.type});
- if (userUnlocked) {
- // Delete from CE table
- deleted = db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
- + "=?", new String[]{account.name, account.type});
+ accountId = getAccountIdLocked(db, account);
+ if (accountId >= 0) {
+ db.delete(
+ TABLE_ACCOUNTS,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{ account.name, account.type });
+ if (userUnlocked) {
+ // Delete from CE table
+ db.delete(
+ CE_TABLE_ACCOUNTS,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{ account.name, account.type });
+ }
+ db.setTransactionSuccessful();
+ isChanged = true;
}
- db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
- removeAccountFromCacheLocked(accounts, account);
- sendAccountsChangedBroadcast(accounts.userId);
- String action = userUnlocked ? DebugDbHelper.ACTION_ACCOUNT_REMOVE
- : DebugDbHelper.ACTION_ACCOUNT_REMOVE_DE;
- logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts);
+ if (isChanged) {
+ removeAccountFromCacheLocked(accounts, account);
+ // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
+ sendAccountsChangedBroadcast(accounts.userId);
+ String action = userUnlocked ? DebugDbHelper.ACTION_ACCOUNT_REMOVE
+ : DebugDbHelper.ACTION_ACCOUNT_REMOVE_DE;
+ logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts);
+ }
}
long id = Binder.clearCallingIdentity();
try {
@@ -1706,7 +1717,7 @@
} finally {
Binder.restoreCallingIdentity(id);
}
- return (deleted > 0);
+ return isChanged;
}
@Override
@@ -1930,6 +1941,7 @@
if (account == null) {
return;
}
+ boolean isChanged = false;
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
@@ -1939,12 +1951,17 @@
final long accountId = getAccountIdLocked(db, account);
if (accountId >= 0) {
final String[] argsAccountId = {String.valueOf(accountId)};
- db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
- db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+ db.update(
+ CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ db.delete(
+ CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
accounts.authTokenCache.remove(account);
accounts.accountTokenCaches.remove(account);
db.setTransactionSuccessful();
-
+ // If there is an account whose password will be updated and the database
+ // transactions succeed, then we say that a change has occured. Even if the
+ // new password is the same as the old and there were no authtokens to delete.
+ isChanged = true;
String action = (password == null || password.length() == 0) ?
DebugDbHelper.ACTION_CLEAR_PASSWORD
: DebugDbHelper.ACTION_SET_PASSWORD;
@@ -1952,8 +1969,11 @@
}
} finally {
db.endTransaction();
+ if (isChanged) {
+ // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
+ sendAccountsChangedBroadcast(accounts.userId);
+ }
}
- sendAccountsChangedBroadcast(accounts.userId);
}
}
@@ -3879,7 +3899,12 @@
ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
int targetUid = targetActivityInfo.applicationInfo.uid;
- if (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid, targetUid)) {
+ if (!GrantCredentialsPermissionActivity.class.getName().equals(
+ targetActivityInfo.getClass().getName())
+ && !CantAddAccountActivity.class
+ .equals(targetActivityInfo.getClass().getName())
+ && PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
+ targetUid)) {
String pkgName = targetActivityInfo.packageName;
String activityName = targetActivityInfo.name;
String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 49bfd56..1a45e96 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -140,7 +140,6 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.ShortcutServiceInternal;
import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -591,14 +590,11 @@
}
/**
- * Activity we have told the window manager to have key focus.
+ * The last resumed activity. This is identical to the current resumed activity most
+ * of the time but could be different when we're pausing one activity before we resume
+ * another activity.
*/
- ActivityRecord mFocusedActivity = null;
-
- /**
- * User id of the last activity mFocusedActivity was set to.
- */
- private int mLastFocusedUserId;
+ private ActivityRecord mLastResumedActivity;
/**
* If non-null, we are tracking the time the user spends in the currently focused app.
@@ -639,36 +635,45 @@
final AppErrors mAppErrors;
- boolean mDoingSetFocusedActivity;
-
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown;
}
- // it's a semaphore; boost when 0->1, reset when 1->0
- static ThreadLocal<Integer> sIsBoosted = new ThreadLocal<Integer>() {
- @Override protected Integer initialValue() {
- return 0;
+ private static final class PriorityState {
+ // Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
+ // the current thread is currently in. When it drops down to zero, we will no longer boost
+ // the thread's priority.
+ private int regionCounter = 0;
+
+ // The thread's previous priority before boosting.
+ private int prevPriority = Integer.MIN_VALUE;
+ }
+
+ static ThreadLocal<PriorityState> sThreadPriorityState = new ThreadLocal<PriorityState>() {
+ @Override protected PriorityState initialValue() {
+ return new PriorityState();
}
};
static void boostPriorityForLockedSection() {
- if (sIsBoosted.get() == 0) {
- // boost to prio 118 while holding a global lock
- Process.setThreadPriority(Process.myTid(), -2);
- //Log.e(TAG, "PRIORITY BOOST: set priority on TID " + Process.myTid());
+ int tid = Process.myTid();
+ int prevPriority = Process.getThreadPriority(tid);
+ PriorityState state = sThreadPriorityState.get();
+ if (state.regionCounter == 0 && prevPriority > -2) {
+ state.prevPriority = prevPriority;
+ Process.setThreadPriority(tid, -2);
}
- int cur = sIsBoosted.get();
- sIsBoosted.set(cur + 1);
+ state.regionCounter++;
}
static void resetPriorityAfterLockedSection() {
- sIsBoosted.set(sIsBoosted.get() - 1);
- if (sIsBoosted.get() == 0) {
- //Log.e(TAG, "PRIORITY BOOST: reset priority on TID " + Process.myTid());
- Process.setThreadPriority(Process.myTid(), 0);
+ PriorityState state = sThreadPriorityState.get();
+ state.regionCounter--;
+ if (state.regionCounter == 0 && state.prevPriority > -2) {
+ Process.setThreadPriority(Process.myTid(), state.prevPriority);
}
}
+
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
public final Bundle extras;
@@ -2952,25 +2957,13 @@
return mAppBindArgs;
}
- boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
- if (r == null || mFocusedActivity == r) {
- return false;
- }
+ /**
+ * Update AMS states when an activity is resumed. This should only be called by
+ * {@link ActivityStack#setResumedActivityLocked} when an activity is resumed.
+ */
+ void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
+ r.state = ActivityState.RESUMED;
- if (!r.isFocusable()) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: unfocusable r=" + r);
- return false;
- }
-
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
-
- final boolean wasDoingSetFocusedActivity = mDoingSetFocusedActivity;
- if (wasDoingSetFocusedActivity) Slog.w(TAG,
- "setFocusedActivityLocked: called recursively, r=" + r + ", reason=" + reason);
- mDoingSetFocusedActivity = true;
-
- final ActivityRecord last = mFocusedActivity;
- mFocusedActivity = r;
if (r.task.isApplicationTask()) {
if (mCurAppTimeTracker != r.appTimeTracker) {
// We are switching app tracking. Complete the current one.
@@ -2999,8 +2992,9 @@
} else {
finishRunningVoiceLocked();
IVoiceInteractionSession session;
- if (last != null && ((session = last.task.voiceSession) != null
- || (session = last.voiceSession) != null)) {
+ if (mLastResumedActivity != null
+ && ((session = mLastResumedActivity.task.voiceSession) != null
+ || (session = mLastResumedActivity.voiceSession) != null)) {
// We had been in a voice interaction session, but now focused has
// move to something different. Just finish the session, we can't
// return to it and retain the proper state and synchronization with
@@ -3008,57 +3002,23 @@
finishVoiceTask(session);
}
}
- if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
- mWindowManager.setFocusedApp(r.appToken, true);
- }
+
+ mWindowManager.setFocusedApp(r.appToken, true);
+
applyUpdateLockStateLocked(r);
applyUpdateVrModeLocked(r);
- if (mFocusedActivity.userId != mLastFocusedUserId) {
+ if (mLastResumedActivity != null && r.userId != mLastResumedActivity.userId) {
mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
mHandler.obtainMessage(
- FOREGROUND_PROFILE_CHANGED_MSG, mFocusedActivity.userId, 0).sendToTarget();
- mLastFocusedUserId = mFocusedActivity.userId;
+ FOREGROUND_PROFILE_CHANGED_MSG, r.userId, 0).sendToTarget();
}
- // Log a warning if the focused app is changed during the process. This could
- // indicate a problem of the focus setting logic!
- if (mFocusedActivity != r) Slog.w(TAG,
- "setFocusedActivityLocked: r=" + r + " but focused to " + mFocusedActivity);
- mDoingSetFocusedActivity = wasDoingSetFocusedActivity;
+ mLastResumedActivity = r;
- EventLogTags.writeAmFocusedActivity(
- mFocusedActivity == null ? -1 : mFocusedActivity.userId,
- mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
+ EventLogTags.writeAmSetResumedActivity(
+ r == null ? -1 : r.userId,
+ r == null ? "NULL" : r.shortComponentName,
reason);
- return true;
- }
-
- final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
- if (mFocusedActivity != goingAway) {
- return;
- }
-
- final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
- if (focusedStack != null) {
- final ActivityRecord top = focusedStack.topActivity();
- if (top != null && top.userId != mLastFocusedUserId) {
- mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
- mHandler.sendMessage(
- mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
- mLastFocusedUserId = top.userId;
- }
- }
-
- // Try to move focus to another activity if possible.
- if (setFocusedActivityLocked(
- focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
- return;
- }
-
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
- + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
- mFocusedActivity = null;
- EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
}
@Override
@@ -3073,7 +3033,7 @@
return;
}
final ActivityRecord r = stack.topRunningActivityLocked();
- if (setFocusedActivityLocked(r, "setFocusedStack")) {
+ if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, "setFocusedStack")) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
@@ -3094,7 +3054,7 @@
return;
}
final ActivityRecord r = task.topRunningActivityLocked();
- if (setFocusedActivityLocked(r, "setFocusedTask")) {
+ if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, "setFocusedTask")) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
@@ -6722,7 +6682,7 @@
// Some stack visibility might change (e.g. docked stack)
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- applyVrModeIfNeededLocked(mFocusedActivity, true);
+ applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(), true);
}
}
} finally {
@@ -9386,16 +9346,6 @@
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return;
}
- int stackId = task.stack.mStackId;
- // We allow the task to scroll instead of resizing if this is a non-resizeable task
- // in crop windows resize mode or if the task size is affected by the docked stack
- // changing size. No need to update configuration.
- if (bounds != null && task.inCropWindowsResizeMode()
- && mStackSupervisor.isStackDockedInEffect(stackId)) {
- mWindowManager.scrollTask(task.taskId, bounds);
- return;
- }
-
// Place the task in the right stack if it isn't there already based on
// the requested bounds.
// The stack transition logic is:
@@ -9403,6 +9353,7 @@
// - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
// that task to freeform
// - otherwise the task is not moved
+ int stackId = task.stack.mStackId;
if (!StackId.isTaskResizeAllowed(stackId)) {
throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
}
@@ -11585,8 +11536,9 @@
}
void startTimeTrackingFocusedActivityLocked() {
- if (!mSleeping && mCurAppTimeTracker != null && mFocusedActivity != null) {
- mCurAppTimeTracker.start(mFocusedActivity.packageName);
+ final ActivityRecord resumedActivity = mStackSupervisor.getResumedActivityLocked();
+ if (!mSleeping && mCurAppTimeTracker != null && resumedActivity != null) {
+ mCurAppTimeTracker.start(resumedActivity.packageName);
}
}
@@ -12059,6 +12011,9 @@
case ActivityManager.BUGREPORT_OPTION_REMOTE:
service = "bugreportremote";
break;
+ case ActivityManager.BUGREPORT_OPTION_WEAR:
+ service = "bugreportwear";
+ break;
}
if (service == null) {
throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
@@ -12527,7 +12482,7 @@
r.immersive = immersive;
// update associated state if we're frontmost
- if (r == mFocusedActivity) {
+ if (r == mStackSupervisor.getResumedActivityLocked()) {
if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
applyUpdateLockStateLocked(r);
}
@@ -12638,7 +12593,7 @@
r.requestedVrComponent = (enabled) ? packageName : null;
// Update associated state if this activity is currently focused
- if (r == mFocusedActivity) {
+ if (r == mStackSupervisor.getResumedActivityLocked()) {
applyUpdateVrModeLocked(r);
}
return 0;
@@ -14316,8 +14271,9 @@
dumpPackage);
boolean needSep = printedAnything;
- boolean printed = ActivityStackSupervisor.printThisActivity(pw, mFocusedActivity,
- dumpPackage, needSep, " mFocusedActivity: ");
+ boolean printed = ActivityStackSupervisor.printThisActivity(pw,
+ mStackSupervisor.getResumedActivityLocked(),
+ dumpPackage, needSep, " ResumedActivity: ");
if (printed) {
printedAnything = true;
needSep = false;
@@ -18696,7 +18652,7 @@
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
- updateConfigurationLocked(values, null, false, true, userId);
+ updateConfigurationLocked(values, null, false, true, userId, false /* deferResume */);
Binder.restoreCallingIdentity(origId);
}
}
@@ -18764,11 +18720,16 @@
updateConfigurationLocked(configuration, null, false);
}
- boolean updateConfigurationLocked(Configuration values,
- ActivityRecord starting, boolean initLocale) {
+ boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale) {
+ return updateConfigurationLocked(values, starting, initLocale, false /* deferResume */);
+ }
+
+ boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean deferResume) {
// pass UserHandle.USER_NULL as userId because we don't persist configuration for any user
- return updateConfigurationLocked(values, starting, initLocale, false,
- UserHandle.USER_NULL);
+ return updateConfigurationLocked(values, starting, initLocale, false /* persistent */,
+ UserHandle.USER_NULL, deferResume);
}
// To cache the list of supported system locales
@@ -18784,8 +18745,8 @@
* @param userId is only used when persistent parameter is set to true to persist configuration
* for that particular user
*/
- private boolean updateConfigurationLocked(Configuration values,
- ActivityRecord starting, boolean initLocale, boolean persistent, int userId) {
+ private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean persistent, int userId, boolean deferResume) {
int changes = 0;
if (mWindowManager != null) {
@@ -18884,15 +18845,6 @@
null, AppOpsManager.OP_NONE, null, false, false,
MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
- // Tell the shortcut manager that the system locale changed. It needs to know
- // it before any other apps receive ACTION_LOCALE_CHANGED, which is why
- // we "push" from here, rather than having the service listen to the broadcast.
- final ShortcutServiceInternal shortcutService =
- LocalServices.getService(ShortcutServiceInternal.class);
- if (shortcutService != null) {
- shortcutService.onSystemLocaleChangedNoLock();
- }
-
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
if (!mProcessesReady) {
@@ -18913,7 +18865,7 @@
for (int stackId : resizedStacks) {
final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
mStackSupervisor.resizeStackLocked(
- stackId, newBounds, null, null, false, false, !DEFER_RESUME);
+ stackId, newBounds, null, null, false, false, deferResume);
}
}
}
@@ -20596,7 +20548,7 @@
}
private final ActivityRecord resumedAppLocked() {
- ActivityRecord act = mStackSupervisor.resumedAppLocked();
+ ActivityRecord act = mStackSupervisor.getResumedActivityLocked();
String pkg;
int uid;
if (act != null) {
@@ -21680,10 +21632,11 @@
ComponentName callingVrActivity = null;
int userId = -1;
synchronized (ActivityManagerService.this) {
- if (mFocusedActivity != null) {
- requestedVrService = mFocusedActivity.requestedVrComponent;
- callingVrActivity = mFocusedActivity.info.getComponentName();
- userId = mFocusedActivity.userId;
+ final ActivityRecord resumedActivity = mStackSupervisor.getResumedActivityLocked();
+ if (resumedActivity != null) {
+ requestedVrService = resumedActivity.requestedVrComponent;
+ callingVrActivity = resumedActivity.info.getComponentName();
+ userId = resumedActivity.userId;
}
}
@@ -21810,7 +21763,8 @@
Preconditions.checkNotNull(values, "Configuration must not be null");
Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported");
synchronized (ActivityManagerService.this) {
- updateConfigurationLocked(values, null, false, true, userId);
+ updateConfigurationLocked(values, null, false, true, userId,
+ false /* deferResume */);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a102664..e4c7c8b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -895,14 +895,10 @@
}
void minimalResumeActivityLocked(ActivityRecord r) {
- r.state = ActivityState.RESUMED;
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
+ " callers=" + Debug.getCallers(5));
- mResumedActivity = r;
- r.task.touchActiveTime();
- mRecentTasks.addLocked(r.task);
+ setResumedActivityLocked(r, "minimalResumeActivityLocked");
completeResumeLocked(r);
- mStackSupervisor.checkReadyForSleepLocked();
setLaunchTime(r);
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
"Launch completed; removing icicle of " + r.icicle);
@@ -1431,6 +1427,7 @@
// When resuming an activity, require it to call requestVisibleBehind() again.
setVisibleBehindActivity(null);
}
+ mStackSupervisor.checkReadyForSleepLocked();
}
private void setVisible(ActivityRecord r, boolean visible) {
@@ -2051,6 +2048,14 @@
// We don't want to clear starting window for activities that aren't behind fullscreen
// activities as we need to display their starting window until they are done initializing.
boolean behindFullscreenActivity = false;
+
+ if (getStackVisibilityLocked(null) == STACK_INVISIBLE) {
+ // The stack is not visible, so no activity in it should be displaying a starting
+ // window. Mark all activities below top and behind fullscreen.
+ aboveTop = false;
+ behindFullscreenActivity = true;
+ }
+
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -2113,6 +2118,15 @@
return result;
}
+ void setResumedActivityLocked(ActivityRecord r, String reason) {
+ // TODO: move mResumedActivity to stack supervisor,
+ // there should only be 1 global copy of resumed activity.
+ mResumedActivity = r;
+ mService.setResumedActivityUncheckLocked(r, reason);
+ r.task.touchActiveTime();
+ mRecentTasks.addLocked(r.task);
+ }
+
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
@@ -2420,10 +2434,9 @@
mService.updateCpuStats();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + " (in existing)");
- next.state = ActivityState.RESUMED;
- mResumedActivity = next;
- next.task.touchActiveTime();
- mRecentTasks.addLocked(next.task);
+
+ setResumedActivityLocked(next, "resumeTopActivityInnerLocked");
+
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
mService.updateOomAdjLocked();
@@ -2496,8 +2509,6 @@
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
- mStackSupervisor.checkReadyForSleepLocked();
-
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next);
} catch (Exception e) {
// Whoops, need to restart this activity!
@@ -3165,8 +3176,8 @@
r.addResultLocked(null, resultWho, requestCode, resultCode, data);
}
- private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
- if (!mStackSupervisor.isFocusedStack(this) || mService.mFocusedActivity != r) {
+ private void adjustFocusedActivityStackLocked(ActivityRecord r, String reason) {
+ if (!mStackSupervisor.isFocusedStack(this) || mResumedActivity != r) {
return;
}
@@ -3175,9 +3186,7 @@
if (next != r) {
if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
// For freeform, docked, and pinned stacks we always keep the focus within the
- // stack as long as there is a running activity in the stack that we can adjust
- // focus to.
- mService.setFocusedActivityLocked(next, myReason);
+ // stack as long as there is a running activity.
return;
} else {
final TaskRecord task = r.task;
@@ -3201,7 +3210,8 @@
}
}
- mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
+ mStackSupervisor.moveFocusableActivityStackToFrontLocked(
+ mStackSupervisor.topRunningActivityLocked(), myReason);
}
private boolean adjustFocusToNextFocusableStackLocked(int taskToReturnTo, String reason) {
@@ -3218,7 +3228,9 @@
// visible, then use the task return to value to determine the home task to display next.
return mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, reason);
}
- return mService.setFocusedActivityLocked(top, myReason);
+
+ stack.moveToFront(myReason);
+ return true;
}
final void stopActivityLocked(ActivityRecord r) {
@@ -3231,7 +3243,7 @@
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
// Activity was finished, no need to continue trying to schedule stop.
- adjustFocusedActivityLocked(r, "stopActivityFinished");
+ adjustFocusedActivityStackLocked(r, "stopActivityFinished");
r.resumeKeyDispatchingLocked();
return;
}
@@ -3243,7 +3255,7 @@
}
if (r.app != null && r.app.thread != null) {
- adjustFocusedActivityLocked(r, "stopActivity");
+ adjustFocusedActivityStackLocked(r, "stopActivity");
r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
@@ -3470,7 +3482,7 @@
r.pauseKeyDispatchingLocked();
- adjustFocusedActivityLocked(r, "finishActivity");
+ adjustFocusedActivityStackLocked(r, "finishActivity");
finishActivityResultsLocked(r, resultCode, resultData);
@@ -3731,7 +3743,6 @@
if (mPausingActivity == r) {
mPausingActivity = null;
}
- mService.resetFocusedActivityIfNeededLocked(r);
r.deferRelaunchUntilPaused = false;
r.frozenBeforeDestroy = false;
@@ -4290,7 +4301,7 @@
// Set focus to the top running activity of this stack.
ActivityRecord r = topRunningActivityLocked();
- mService.setFocusedActivityLocked(r, reason);
+ mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, reason);
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
@@ -4365,7 +4376,7 @@
mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
- mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
+ mStackSupervisor.moveFocusableActivityStackToFrontLocked(visibleBehind, "moveTaskToBack");
mStackSupervisor.resumeFocusedStackTopActivityLocked();
return true;
}
@@ -4750,6 +4761,7 @@
// code in resumeTopActivityInnerLocked to complete the resume might be skipped.
if (!r.visible || r.stopped) {
mWindowManager.setAppVisibility(r.appToken, true);
+ setResumedActivityLocked(r, "relaunchActivityLocked");
completeResumeLocked(r);
} else {
r.results = null;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index fc56b5c..6368f5d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -128,6 +128,7 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
@@ -140,6 +141,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
@@ -180,6 +182,7 @@
public final class ActivityStackSupervisor implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
+ private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
@@ -613,12 +616,6 @@
}
final ActivityRecord r = topRunningActivityLocked();
- if (!mService.mDoingSetFocusedActivity && mService.mFocusedActivity != r) {
- // The focus activity should always be the top activity in the focused stack.
- // There will be chaos and anarchy if it isn't...
- mService.setFocusedActivityLocked(r, reason + " setFocusStack");
- }
-
if (mService.mBooting || !mService.mBooted) {
if (r != null && r.idle) {
checkFinishBootingLocked();
@@ -643,7 +640,7 @@
if (top == null) {
return false;
}
- mService.setFocusedActivityLocked(top, reason);
+ moveFocusableActivityStackToFrontLocked(top, reason);
return true;
}
@@ -668,7 +665,7 @@
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
- mService.setFocusedActivityLocked(r, myReason);
+ moveFocusableActivityStackToFrontLocked(r, myReason);
return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser, myReason);
@@ -807,7 +804,7 @@
return candidateTaskId;
}
- ActivityRecord resumedAppLocked() {
+ ActivityRecord getResumedActivityLocked() {
ActivityStack stack = mFocusedStack;
if (stack == null) {
return null;
@@ -1189,7 +1186,10 @@
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
r.mayFreezeScreenLocked(app) ? r.appToken : null);
- mService.updateConfigurationLocked(config, r, false);
+ // Deferring resume here because we're going to launch new activity shortly.
+ // We don't want to perform a redundant launch of the same record while ensuring
+ // configurations and trying to resume top activity of focused stack.
+ mService.updateConfigurationLocked(config, r, false, true /* deferResume */);
}
r.app = app;
@@ -1539,20 +1539,6 @@
return ACTIVITY_RESTRICTION_NONE;
}
- boolean moveActivityStackToFront(ActivityRecord r, String reason) {
- if (r == null) {
- // Not sure what you are trying to do, but it is not going to work...
- return false;
- }
- final TaskRecord task = r.task;
- if (task == null || task.stack == null) {
- Slog.w(TAG, "Can't move stack to front for r=" + r + " task=" + task);
- return false;
- }
- task.stack.moveToFront(reason, task);
- return true;
- }
-
void setLaunchSource(int uid) {
mLaunchingActivity.setWorkSource(new WorkSource(uid));
}
@@ -2004,7 +1990,7 @@
boolean preserveWindows, boolean allowResizeInDockedMode, boolean deferResume) {
if (stackId == DOCKED_STACK_ID) {
resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null,
- preserveWindows);
+ preserveWindows, deferResume);
return;
}
final ActivityStack stack = getStack(stackId);
@@ -2154,8 +2140,16 @@
}
void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
- Rect tempDockedTaskInsetBounds,
- Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) {
+ Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
+ boolean preserveWindows) {
+ resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+ tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows,
+ false /* deferResume */);
+ }
+
+ void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
+ boolean preserveWindows, boolean deferResume) {
if (!mAllowDockedStackResize) {
// Docked stack resize currently disabled.
@@ -2198,11 +2192,13 @@
if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
resizeStackLocked(i, tempRect, tempOtherTaskBounds,
tempOtherTaskInsetBounds, preserveWindows,
- true /* allowResizeInDockedMode */, !DEFER_RESUME);
+ true /* allowResizeInDockedMode */, deferResume);
}
}
}
- stack.ensureVisibleActivitiesConfigurationLocked(r, preserveWindows);
+ if (!deferResume) {
+ stack.ensureVisibleActivitiesConfigurationLocked(r, preserveWindows);
+ }
} finally {
mAllowDockedStackResize = true;
mWindowManager.continueSurfaceLayout();
@@ -2591,6 +2587,34 @@
mService.notifyActivityPinnedLocked();
}
+ boolean moveFocusableActivityStackToFrontLocked(ActivityRecord r, String reason) {
+ if (r == null || !r.isFocusable()) {
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
+ "moveActivityStackToFront: unfocusable r=" + r);
+ return false;
+ }
+
+ final TaskRecord task = r.task;
+ if (task == null || task.stack == null) {
+ Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
+ + r + " task=" + task);
+ return false;
+ }
+
+ final ActivityStack stack = task.stack;
+ if (stack == mFocusedStack && stack.topRunningActivityLocked() == r) {
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
+ "moveActivityStackToFront: already on top, r=" + r);
+ return false;
+ }
+
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
+ "moveActivityStackToFront: r=" + r);
+
+ stack.moveToFront(reason, task);
+ return true;
+ }
+
void positionTaskInStackLocked(int taskId, int stackId, int position) {
final TaskRecord task = anyTaskForIdLocked(taskId);
if (task == null) {
@@ -3061,7 +3085,7 @@
final boolean nowVisible = allResumedActivitiesVisible();
for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord s = mStoppingActivities.get(activityNdx);
- final boolean waitingVisible = mWaitingVisibleActivities.contains(s);
+ boolean waitingVisible = mWaitingVisibleActivities.contains(s);
if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+ " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
if (waitingVisible && nowVisible) {
@@ -3074,6 +3098,7 @@
// hidden by the activities in front of it.
if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
mWindowManager.setAppVisibility(s.appToken, false);
+ waitingVisible = false;
}
}
if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 92d07ed..399ca9e 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1112,49 +1112,24 @@
? mSourceRecord.task : null;
// Should this be considered a new task?
+ int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
- setTaskFromReuseOrCreateNewTask(taskToAffiliate);
-
- if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (!mMovedOtherTask) {
- // If stack id is specified in activity options, usually it means that activity is
- // launched not from currently focused stack (e.g. from SysUI or from shell) - in
- // that case we check the target stack.
- updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
- preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
- }
+ result = setTaskFromReuseOrCreateNewTask(
+ taskToAffiliate, preferredLaunchStackId, topStack);
} else if (mSourceRecord != null) {
- if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
-
- final int result = setTaskFromSourceRecord();
- if (result != START_SUCCESS) {
- return result;
- }
+ result = setTaskFromSourceRecord();
} else if (mInTask != null) {
- // The caller is asking that the new activity be started in an explicit
- // task it has provided to us.
- if (mSupervisor.isLockTaskModeViolation(mInTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
-
- final int result = setTaskFromInTask();
- if (result != START_SUCCESS) {
- return result;
- }
+ result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
+ if (result != START_SUCCESS) {
+ return result;
+ }
mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
@@ -1174,12 +1149,6 @@
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
if (mDoResume) {
- if (!mLaunchTaskBehind) {
- // TODO(b/26381750): Remove this code after verification that all the decision
- // points above moved targetStack to the front which will also set the focus
- // activity.
- mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
- }
final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
@@ -1654,9 +1623,13 @@
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
}
- private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
- mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
- mOptions);
+ private int setTaskFromReuseOrCreateNewTask(
+ TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
+ mTargetStack = computeStackFocus(
+ mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
+
+ // Do no move the target stack to front yet, as we might bail if
+ // isLockTaskModeViolation fails below.
if (mReuseTask == null) {
final TaskRecord task = mTargetStack.createTaskRecord(
@@ -1680,9 +1653,31 @@
} else {
mStartActivity.setTask(mReuseTask, taskToAffiliate);
}
+
+ if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ if (!mMovedOtherTask) {
+ // If stack id is specified in activity options, usually it means that activity is
+ // launched not from currently focused stack (e.g. from SysUI or from shell) - in
+ // that case we check the target stack.
+ updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
+ preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
+ }
+ if (mDoResume) {
+ mTargetStack.moveToFront("reuseOrNewTask");
+ }
+ return START_SUCCESS;
}
private int setTaskFromSourceRecord() {
+ if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
final TaskRecord sourceTask = mSourceRecord.task;
// We only want to allow changing stack if the target task is not the top one,
// otherwise we would move the launching task to the other side, rather than show
@@ -1699,14 +1694,15 @@
mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
}
- if (mDoResume) {
- mTargetStack.moveToFront("sourceStackToFront");
- }
+
final TaskRecord topTask = mTargetStack.topTask();
if (topTask != sourceTask && !mAvoidMoveToFront) {
mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "sourceTaskToFront");
+ } else if (mDoResume) {
+ mTargetStack.moveToFront("sourceStackToFront");
}
+
if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing task, but the caller has
// asked to clear that task if the activity is already running.
@@ -1751,6 +1747,13 @@
}
private int setTaskFromInTask() {
+ // The caller is asking that the new activity be started in an explicit
+ // task it has provided to us.
+ if (mSupervisor.isLockTaskModeViolation(mInTask)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
if (mLaunchBounds != null) {
mInTask.updateOverrideConfiguration(mLaunchBounds);
int stackId = mInTask.getLaunchStackId();
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 49106f4..5807502 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -58,6 +58,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Set;
import java.util.concurrent.Semaphore;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
@@ -386,8 +387,8 @@
} catch (IllegalArgumentException e) {
// Hmm, that didn't work, app might have crashed before creating a
// recents entry. Let's see if we have a safe-to-restart intent.
- if (task.intent.getCategories().contains(
- Intent.CATEGORY_LAUNCHER)) {
+ final Set<String> cats = task.intent.getCategories();
+ if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) {
mService.startActivityInPackage(task.mCallingUid,
task.mCallingPackage, task.intent,
null, null, null, 0, 0,
@@ -742,6 +743,12 @@
mService.updateCpuStatsNow();
}
+ // Unless configured otherwise, swallow ANRs in background processes & kill the process.
+ boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+
+ boolean isSilentANR;
+
synchronized (mService) {
// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
if (mService.mShuttingDown) {
@@ -766,25 +773,29 @@
// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(app.pid);
- int parentPid = app.pid;
- if (parent != null && parent.app != null && parent.app.pid > 0) {
- parentPid = parent.app.pid;
- }
- if (parentPid != app.pid) firstPids.add(parentPid);
+ // Don't dump other PIDs if it's a background ANR
+ isSilentANR = !showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID;
+ if (!isSilentANR) {
+ int parentPid = app.pid;
+ if (parent != null && parent.app != null && parent.app.pid > 0) {
+ parentPid = parent.app.pid;
+ }
+ if (parentPid != app.pid) firstPids.add(parentPid);
- if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
+ if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
- for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord r = mService.mLruProcesses.get(i);
- if (r != null && r.thread != null) {
- int pid = r.pid;
- if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
- if (r.persistent) {
- firstPids.add(pid);
- if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
- } else {
- lastPids.put(pid, Boolean.TRUE);
- if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
+ for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mService.mLruProcesses.get(i);
+ if (r != null && r.thread != null) {
+ int pid = r.pid;
+ if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
+ if (r.persistent) {
+ firstPids.add(pid);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
+ } else {
+ lastPids.put(pid, Boolean.TRUE);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
+ }
}
}
}
@@ -807,10 +818,18 @@
info.append("Parent: ").append(parent.shortComponentName).append("\n");
}
- final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
+ ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
- File tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
- NATIVE_STACKS_OF_INTEREST);
+ String[] nativeProcs = NATIVE_STACKS_OF_INTEREST;
+ // don't dump native PIDs for background ANRs
+ File tracesFile = null;
+ if (isSilentANR) {
+ tracesFile = mService.dumpStackTraces(true, firstPids, null, lastPids,
+ null);
+ } else {
+ tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
+ nativeProcs);
+ }
String cpuInfo = null;
if (ActivityManagerService.MONITOR_CPU_USAGE) {
@@ -854,14 +873,10 @@
}
}
- // Unless configured otherwise, swallow ANRs in background processes & kill the process.
- boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-
synchronized (mService) {
mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
- if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
+ if (isSilentANR) {
app.kill("bg anr", true);
return;
}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 2762df6..722974b 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -90,8 +90,8 @@
# Activity fully drawn time
30042 am_activity_fully_drawn_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
-# Activity focused
-30043 am_focused_activity (User|1|5),(Component Name|3),(Reason|3)
+# Activity set to resumed
+30043 am_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3)
# Stack focus
30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6f67b6f..b6c8d5d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -69,6 +69,7 @@
import com.android.internal.util.StateMachine;
import com.android.server.IoThread;
import com.android.server.connectivity.tethering.IControlsTethering;
+import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.net.BaseNetworkObserver;
@@ -449,8 +450,6 @@
private int setWifiTethering(final boolean enable) {
synchronized (mPublicSync) {
- // Note that we're maintaining a predicate that mWifiTetherRequested always matches
- // our last request to WifiManager re: its AP enabled status.
mWifiTetherRequested = enable;
final WifiManager wifiManager =
(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
@@ -590,13 +589,13 @@
synchronized (mPublicSync) {
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
- Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
+ Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
// Ignore the error status of the interface. If the interface is available,
// the errors are referring to past tethering attempts anyway.
if (tetherState.mLastState != IControlsTethering.STATE_AVAILABLE) {
- Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
+ Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
}
tetherState.mStateMachine.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
@@ -793,10 +792,6 @@
}
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
synchronized (Tethering.this.mPublicSync) {
- if (!mWifiTetherRequested) {
- // We only care when we're trying to tether via our WiFi interface.
- return;
- }
int curState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
WifiManager.WIFI_AP_STATE_DISABLED);
switch (curState) {
@@ -804,8 +799,10 @@
// We can see this state on the way to both enabled and failure states.
break;
case WifiManager.WIFI_AP_STATE_ENABLED:
- // Tell an appropriate interface state machine that it should tether.
- tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
+ // When the AP comes up and we've been requested to tether it, do so.
+ if (mWifiTetherRequested) {
+ tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
+ }
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
case WifiManager.WIFI_AP_STATE_DISABLING:
@@ -815,10 +812,20 @@
Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" +
curState);
}
- // Tell an appropriate interface state machine that
- // it needs to tear itself down.
- tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_WIFI);
- setWifiTethering(false);
+ // Tell appropriate interface state machines that they should tear
+ // themselves down.
+ for (int i = 0; i < mTetherStates.size(); i++) {
+ TetherInterfaceStateMachine tism =
+ mTetherStates.valueAt(i).mStateMachine;
+ if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ tism.sendMessage(
+ TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+ break; // There should be at most one of these.
+ }
+ }
+ // Regardless of whether we requested this transition, the AP has gone
+ // down. Don't try to tether again unless we're requested to do so.
+ mWifiTetherRequested = false;
break;
}
}
@@ -1017,15 +1024,29 @@
*/
class UpstreamNetworkCallback extends NetworkCallback {
@Override
+ public void onAvailable(Network network) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ UpstreamNetworkMonitor.EVENT_ON_AVAILABLE, 0, network);
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES, 0,
+ new NetworkState(null, null, newNc, network, null, null));
+ }
+
+ @Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
- mTetherMasterSM.sendMessage(
- TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED,
+ mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, 0,
new NetworkState(null, newLp, null, network, null, null));
}
@Override
public void onLost(Network network) {
- mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network);
+ mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ UpstreamNetworkMonitor.EVENT_ON_LOST, 0, network);
}
}
@@ -1044,6 +1065,11 @@
* could/should be moved here.
*/
class UpstreamNetworkMonitor {
+ static final int EVENT_ON_AVAILABLE = 1;
+ static final int EVENT_ON_CAPABILITIES = 2;
+ static final int EVENT_ON_LINKPROPERTIES = 3;
+ static final int EVENT_ON_LOST = 4;
+
final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
NetworkCallback mDefaultNetworkCallback;
NetworkCallback mDunTetheringCallback;
@@ -1078,33 +1104,107 @@
mNetworkMap.clear();
}
- // Returns true if these updated LinkProperties pertain to the current
- // upstream network interface, false otherwise (or if there is not
- // currently any upstream tethering interface).
- boolean processLinkPropertiesChanged(NetworkState networkState) {
- if (networkState == null ||
- networkState.network == null ||
- networkState.linkProperties == null) {
- return false;
- }
+ NetworkState lookup(Network network) {
+ return (network != null) ? mNetworkMap.get(network) : null;
+ }
- mNetworkMap.put(networkState.network, networkState);
-
- if (mCurrentUpstreamIface != null) {
- for (String ifname : networkState.linkProperties.getAllInterfaceNames()) {
- if (mCurrentUpstreamIface.equals(ifname)) {
- return true;
+ NetworkState processCallback(int arg1, Object obj) {
+ switch (arg1) {
+ case EVENT_ON_AVAILABLE: {
+ final Network network = (Network) obj;
+ if (VDBG) {
+ Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
}
+ if (!mNetworkMap.containsKey(network)) {
+ mNetworkMap.put(network,
+ new NetworkState(null, null, null, network, null, null));
+ }
+
+ final ConnectivityManager cm = getConnectivityManager();
+
+ if (mDefaultNetworkCallback != null) {
+ cm.requestNetworkCapabilities(mDefaultNetworkCallback);
+ cm.requestLinkProperties(mDefaultNetworkCallback);
+ }
+
+ // Requesting updates for mDunTetheringCallback is not
+ // necessary. Because it's a listen, it will already have
+ // heard all NetworkCapabilities and LinkProperties updates
+ // since UpstreamNetworkMonitor was started. Because we
+ // start UpstreamNetworkMonitor before chooseUpstreamType()
+ // is ever invoked (it can register a DUN request) this is
+ // mostly safe. However, if a DUN network is already up for
+ // some reason (unlikely, because DUN is restricted and,
+ // unless the DUN network is shared with another APN, only
+ // the system can request it and this is the only part of
+ // the system that requests it) we won't know its
+ // LinkProperties or NetworkCapabilities.
+
+ return mNetworkMap.get(network);
+ }
+ case EVENT_ON_CAPABILITIES: {
+ final NetworkState ns = (NetworkState) obj;
+ if (!mNetworkMap.containsKey(ns.network)) {
+ // Ignore updates for networks for which we have not yet
+ // received onAvailable() - which should never happen -
+ // or for which we have already received onLost().
+ return null;
+ }
+ if (VDBG) {
+ Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
+ ns.network, ns.networkCapabilities));
+ }
+
+ final NetworkState prev = mNetworkMap.get(ns.network);
+ mNetworkMap.put(ns.network,
+ new NetworkState(null, prev.linkProperties, ns.networkCapabilities,
+ ns.network, null, null));
+ return mNetworkMap.get(ns.network);
+ }
+ case EVENT_ON_LINKPROPERTIES: {
+ final NetworkState ns = (NetworkState) obj;
+ if (!mNetworkMap.containsKey(ns.network)) {
+ // Ignore updates for networks for which we have not yet
+ // received onAvailable() - which should never happen -
+ // or for which we have already received onLost().
+ return null;
+ }
+ if (VDBG) {
+ Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
+ ns.network, ns.linkProperties));
+ }
+
+ final NetworkState prev = mNetworkMap.get(ns.network);
+ mNetworkMap.put(ns.network,
+ new NetworkState(null, ns.linkProperties, prev.networkCapabilities,
+ ns.network, null, null));
+ return mNetworkMap.get(ns.network);
+ }
+ case EVENT_ON_LOST: {
+ final Network network = (Network) obj;
+ if (VDBG) {
+ Log.d(TAG, "EVENT_ON_LOST for " + network);
+ }
+ return mNetworkMap.remove(network);
+ }
+ default:
+ return null;
+ }
+ }
+ }
+
+ // Needed because the canonical source of upstream truth is just the
+ // upstream interface name, |mCurrentUpstreamIface|. This is ripe for
+ // future simplification, once the upstream Network is canonical.
+ boolean pertainsToCurrentUpstream(NetworkState ns) {
+ if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) {
+ for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
+ if (mCurrentUpstreamIface.equals(ifname)) {
+ return true;
}
}
- return false;
}
-
- void processNetworkLost(Network network) {
- if (network != null) {
- mNetworkMap.remove(network);
- }
- }
+ return false;
}
class TetherMasterSM extends StateMachine {
@@ -1119,8 +1219,7 @@
static final int CMD_RETRY_UPSTREAM = BASE_MASTER + 4;
// Events from NetworkCallbacks that we process on the master state
// machine thread on behalf of the UpstreamNetworkMonitor.
- static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED = BASE_MASTER + 5;
- static final int EVENT_UPSTREAM_LOST = BASE_MASTER + 6;
+ static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
private State mInitialState;
private State mTetherModeAliveState;
@@ -1143,7 +1242,8 @@
// Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
// so that the garbage collector does not clean up the state machine before it has a chance
// to tear itself down.
- private ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
private NetworkCallback mMobileUpstreamCallback;
@@ -1171,6 +1271,7 @@
addState(mSetDnsForwardersErrorState);
mNotifyList = new ArrayList<>();
+ mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList);
setInitialState(mInitialState);
}
@@ -1275,6 +1376,7 @@
}
protected void chooseUpstreamType(boolean tryCell) {
+ final ConnectivityManager cm = getConnectivityManager();
int upType = ConnectivityManager.TYPE_NONE;
String iface = null;
@@ -1289,8 +1391,7 @@
}
for (Integer netType : mUpstreamIfaceTypes) {
- NetworkInfo info =
- getConnectivityManager().getNetworkInfo(netType.intValue());
+ NetworkInfo info = cm.getNetworkInfo(netType.intValue());
if ((info != null) && info.isConnected()) {
upType = netType.intValue();
break;
@@ -1331,9 +1432,9 @@
break;
}
+ Network network = null;
if (upType != ConnectivityManager.TYPE_NONE) {
- LinkProperties linkProperties =
- getConnectivityManager().getLinkProperties(upType);
+ LinkProperties linkProperties = cm.getLinkProperties(upType);
if (linkProperties != null) {
// Find the interface with the default IPv4 route. It may be the
// interface described by linkProperties, or one of the interfaces
@@ -1350,7 +1451,7 @@
}
if (iface != null) {
- Network network = getConnectivityManager().getNetworkForType(upType);
+ network = cm.getNetworkForType(upType);
if (network == null) {
Log.e(TAG, "No Network for upstream type " + upType + "!");
}
@@ -1358,6 +1459,13 @@
}
}
notifyTetheredOfNewUpstreamIface(iface);
+ NetworkState ns = mUpstreamNetworkMonitor.lookup(network);
+ if (ns != null && pertainsToCurrentUpstream(ns)) {
+ // If we already have NetworkState for this network examine
+ // it immediately, because there likely will be no second
+ // EVENT_ON_AVAILABLE (it was already received).
+ handleNewUpstreamNetworkState(ns);
+ }
}
protected void setDnsForwarders(final Network network, final LinkProperties lp) {
@@ -1390,6 +1498,10 @@
ifaceName);
}
}
+
+ protected void handleNewUpstreamNetworkState(NetworkState ns) {
+ mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
+ }
}
private final AtomicInteger mSimBcastGenerationNumber = new AtomicInteger(0);
@@ -1579,24 +1691,55 @@
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
break;
- case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED:
- NetworkState state = (NetworkState) message.obj;
- if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) {
- setDnsForwarders(state.network, state.linkProperties);
- } else if (mCurrentUpstreamIface == null) {
- // If we have no upstream interface, try to run through upstream
- // selection again. If, for example, IPv4 connectivity has shown up
- // after IPv6 (e.g., 464xlat became available) we want the chance to
- // notice and act accordingly.
- chooseUpstreamType(false);
+ case EVENT_UPSTREAM_CALLBACK: {
+ // First: always update local state about every network.
+ final NetworkState ns = mUpstreamNetworkMonitor.processCallback(
+ message.arg1, message.obj);
+
+ if (ns == null || !pertainsToCurrentUpstream(ns)) {
+ // TODO: In future, this is where upstream evaluation and selection
+ // could be handled for notifications which include sufficient data.
+ // For example, after CONNECTIVITY_ACTION listening is removed, here
+ // is where we could observe a Wi-Fi network becoming available and
+ // passing validation.
+ if (mCurrentUpstreamIface == null) {
+ // If we have no upstream interface, try to run through upstream
+ // selection again. If, for example, IPv4 connectivity has shown up
+ // after IPv6 (e.g., 464xlat became available) we want the chance to
+ // notice and act accordingly.
+ chooseUpstreamType(false);
+ }
+ break;
+ }
+
+ switch (message.arg1) {
+ case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
+ // The default network changed, or DUN connected
+ // before this callback was processed. Updates
+ // for the current NetworkCapabilities and
+ // LinkProperties have been requested (default
+ // request) or are being sent shortly (DUN). Do
+ // nothing until they arrive; if no updates
+ // arrive there's nothing to do.
+ break;
+ case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
+ handleNewUpstreamNetworkState(ns);
+ break;
+ case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
+ setDnsForwarders(ns.network, ns.linkProperties);
+ handleNewUpstreamNetworkState(ns);
+ break;
+ case UpstreamNetworkMonitor.EVENT_ON_LOST:
+ // TODO: Re-evaluate possible upstreams. Currently upstream
+ // reevaluation is triggered via received CONNECTIVITY_ACTION
+ // broadcasts that result in being passed a
+ // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+ break;
+ default:
+ break;
}
break;
- case EVENT_UPSTREAM_LOST:
- // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation
- // is triggered via received CONNECTIVITY_ACTION broadcasts that result
- // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED.
- mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj);
- break;
+ }
default:
retValue = false;
break;
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
new file mode 100644
index 0000000..8254397
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.net.ConnectivityManager;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkState;
+import android.net.RouteInfo;
+import android.util.Log;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
+
+/**
+ * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
+ * This coordinator is responsible for evaluating the dedicated prefixes
+ * assigned to the device and deciding how to divvy them up among downstream
+ * interfaces.
+ *
+ * @hide
+ */
+public class IPv6TetheringCoordinator {
+ private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private NetworkState mUpstreamNetworkState;
+
+ public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList) {
+ mNotifyList = notifyList;
+ }
+
+ public void updateUpstreamNetworkState(NetworkState ns) {
+ if (VDBG) {
+ Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
+ }
+ if (ns == null || ns.network == null) {
+ stopIPv6TetheringOnAllInterfaces();
+ setUpstreamNetworkState(null);
+ return;
+ }
+
+ if (mUpstreamNetworkState != null &&
+ !ns.network.equals(mUpstreamNetworkState.network)) {
+ stopIPv6TetheringOnAllInterfaces();
+ }
+ setUpstreamNetworkState(ns);
+ maybeUpdateIPv6TetheringInterfaces();
+ }
+
+ private void stopIPv6TetheringOnAllInterfaces() {
+ for (TetherInterfaceStateMachine sm : mNotifyList) {
+ sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE,
+ 0, 0, null);
+ }
+ }
+
+ private void setUpstreamNetworkState(NetworkState ns) {
+ if (!canTetherIPv6(ns)) {
+ mUpstreamNetworkState = null;
+ } else {
+ mUpstreamNetworkState = new NetworkState(
+ null,
+ new LinkProperties(ns.linkProperties),
+ new NetworkCapabilities(ns.networkCapabilities),
+ new Network(ns.network),
+ null,
+ null);
+ }
+
+ if (DBG) {
+ Log.d(TAG, "setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
+ }
+ }
+
+ private void maybeUpdateIPv6TetheringInterfaces() {
+ if (mUpstreamNetworkState == null) return;
+
+ for (TetherInterfaceStateMachine sm : mNotifyList) {
+ final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType());
+ if (lp != null) {
+ sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
+ }
+ break;
+ }
+ }
+
+ private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) {
+ // NOTE: Here, in future, we would have policies to decide how to divvy
+ // up the available dedicated prefixes among downstream interfaces.
+ // At this time we have no such mechanism--we only support tethering
+ // IPv6 toward Wi-Fi interfaces.
+
+ switch (interfaceType) {
+ case ConnectivityManager.TETHERING_WIFI:
+ final LinkProperties lp = getIPv6OnlyLinkProperties(
+ mUpstreamNetworkState.linkProperties);
+ if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
+ return lp;
+ }
+ break;
+ }
+
+ return null;
+ }
+
+ private static boolean canTetherIPv6(NetworkState ns) {
+ // Broadly speaking:
+ //
+ // [1] does the upstream have an IPv6 default route?
+ //
+ // and
+ //
+ // [2] does the upstream have one or more global IPv6 /64s
+ // dedicated to this device?
+ //
+ // In lieu of Prefix Delegation and other evaluation of whether a
+ // prefix may or may not be dedicated to this device, for now just
+ // check whether the upstream is TRANSPORT_CELLULAR. This works
+ // because "[t]he 3GPP network allocates each default bearer a unique
+ // /64 prefix", per RFC 6459, Section 5.2.
+
+ final boolean canTether =
+ (ns != null) && (ns.network != null) &&
+ (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
+ // At least one upstream DNS server:
+ ns.linkProperties.isProvisioned() &&
+ // Minimal amount of IPv6 provisioning:
+ ns.linkProperties.hasIPv6DefaultRoute() &&
+ ns.linkProperties.hasGlobalIPv6Address() &&
+ // Temporary approximation of "dedicated prefix":
+ ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+
+ // For now, we do not support separate IPv4 and IPv6 upstreams (e.g.
+ // tethering with 464xlat involved). TODO: Rectify this shortcoming,
+ // likely by calling NetworkManagementService#startInterfaceForwarding()
+ // for all upstream interfaces.
+ RouteInfo v4default = null;
+ RouteInfo v6default = null;
+ if (canTether) {
+ for (RouteInfo r : ns.linkProperties.getAllRoutes()) {
+ if (r.isIPv4Default()) {
+ v4default = r;
+ } else if (r.isIPv6Default()) {
+ v6default = r;
+ }
+
+ if (v4default != null && v6default != null) {
+ break;
+ }
+ }
+ }
+
+ final boolean supportedConfiguration =
+ (v4default != null) && (v6default != null) &&
+ (v4default.getInterface() != null) &&
+ v4default.getInterface().equals(v6default.getInterface());
+
+ final boolean outcome = canTether && supportedConfiguration;
+
+ if (VDBG) {
+ if (ns == null) {
+ Log.d(TAG, "No available upstream.");
+ } else {
+ Log.d(TAG, String.format("IPv6 tethering is %s for upstream: %s",
+ (outcome ? "available" : "not available"), toDebugString(ns)));
+ }
+ }
+
+ return outcome;
+ }
+
+ private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
+ final LinkProperties v6only = new LinkProperties();
+ if (lp == null) {
+ return v6only;
+ }
+
+ // NOTE: At this time we don't copy over any information about any
+ // stacked links. No current stacked link configuration has IPv6.
+
+ v6only.setInterfaceName(lp.getInterfaceName());
+
+ v6only.setMtu(lp.getMtu());
+
+ for (LinkAddress linkAddr : lp.getLinkAddresses()) {
+ if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
+ v6only.addLinkAddress(linkAddr);
+ }
+ }
+
+ for (RouteInfo routeInfo : lp.getRoutes()) {
+ final IpPrefix destination = routeInfo.getDestination();
+ if ((destination.getAddress() instanceof Inet6Address) &&
+ (destination.getPrefixLength() <= 64)) {
+ v6only.addRoute(routeInfo);
+ }
+ }
+
+ for (InetAddress dnsServer : lp.getDnsServers()) {
+ if (isIPv6GlobalAddress(dnsServer)) {
+ // For now we include ULAs.
+ v6only.addDnsServer(dnsServer);
+ }
+ }
+
+ v6only.setDomains(lp.getDomains());
+
+ return v6only;
+ }
+
+ // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
+ // announce our own IPv6 address as DNS server.
+ private static boolean isIPv6GlobalAddress(InetAddress ip) {
+ return (ip instanceof Inet6Address) &&
+ !ip.isAnyLocalAddress() &&
+ !ip.isLoopbackAddress() &&
+ !ip.isLinkLocalAddress() &&
+ !ip.isSiteLocalAddress() &&
+ !ip.isMulticastAddress();
+ }
+
+ private static String toDebugString(NetworkState ns) {
+ if (ns == null) {
+ return "NetworkState{null}";
+ }
+ return String.format("NetworkState{%s, %s, %s}",
+ ns.network,
+ ns.networkCapabilities,
+ ns.linkProperties);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
new file mode 100644
index 0000000..b742838
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.NetworkState;
+import android.net.RouteInfo;
+import android.net.ip.RouterAdvertisementDaemon;
+import android.net.ip.RouterAdvertisementDaemon.RaParams;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+
+/**
+ * @hide
+ */
+class IPv6TetheringInterfaceServices {
+ private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
+
+ private final String mIfName;
+ private final INetworkManagementService mNMService;
+
+ private NetworkInterface mNetworkInterface;
+ private byte[] mHwAddr;
+ private ArrayList<RouteInfo> mLastLocalRoutes;
+ private RouterAdvertisementDaemon mRaDaemon;
+ private RaParams mLastRaParams;
+
+ IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
+ mIfName = ifname;
+ mNMService = nms;
+ }
+
+ public boolean start() {
+ try {
+ mNetworkInterface = NetworkInterface.getByName(mIfName);
+ } catch (SocketException e) {
+ Log.e(TAG, "Failed to find NetworkInterface for " + mIfName, e);
+ stop();
+ return false;
+ }
+
+ try {
+ mHwAddr = mNetworkInterface.getHardwareAddress();
+ } catch (SocketException e) {
+ Log.e(TAG, "Failed to find hardware address for " + mIfName, e);
+ stop();
+ return false;
+ }
+
+ final int ifindex = mNetworkInterface.getIndex();
+ mRaDaemon = new RouterAdvertisementDaemon(mIfName, ifindex, mHwAddr);
+ if (!mRaDaemon.start()) {
+ stop();
+ return false;
+ }
+
+ return true;
+ }
+
+ public void stop() {
+ mNetworkInterface = null;
+ mHwAddr = null;
+ updateLocalRoutes(null);
+ updateRaParams(null);
+
+ if (mRaDaemon != null) {
+ mRaDaemon.stop();
+ mRaDaemon = null;
+ }
+ }
+
+ // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
+ // LinkProperties. These have extraneous data filtered out and only the
+ // necessary prefixes included (per its prefix distribution policy).
+ //
+ // TODO: Evaluate using a data structure than is more directly suited to
+ // communicating only the relevant information.
+ public void updateUpstreamIPv6LinkProperties(LinkProperties v6only) {
+ if (mRaDaemon == null) return;
+
+ if (v6only == null) {
+ updateLocalRoutes(null);
+ updateRaParams(null);
+ return;
+ }
+
+ RaParams params = new RaParams();
+ params.mtu = v6only.getMtu();
+ params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
+
+ ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>();
+ for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
+ final IpPrefix prefix = new IpPrefix(linkAddr.getAddress(),
+ linkAddr.getPrefixLength());
+
+ // Accumulate routes representing "prefixes to be assigned to the
+ // local interface", for subsequent addition to the local network
+ // in the routing rules.
+ localRoutes.add(new RouteInfo(prefix, null, mIfName));
+
+ params.prefixes.add(prefix);
+ }
+
+ // We need to be able to send unicast RAs, and clients might like to
+ // ping the default router's link-local address, so add that as well.
+ localRoutes.add(new RouteInfo(new IpPrefix("fe80::/64"), null, mIfName));
+
+ // TODO: Add a local interface address, update dnsmasq to listen on the
+ // new address, and use only that address as a DNS server.
+ for (InetAddress dnsServer : v6only.getDnsServers()) {
+ if (dnsServer instanceof Inet6Address) {
+ params.dnses.add((Inet6Address) dnsServer);
+ }
+ }
+
+ updateLocalRoutes(localRoutes);
+ updateRaParams(params);
+ }
+
+ private void updateLocalRoutes(ArrayList<RouteInfo> localRoutes) {
+ if (localRoutes != null) {
+ // TODO: Compare with mLastLocalRoutes and take appropriate
+ // appropriate action on the difference between the two.
+
+ if (!localRoutes.isEmpty()) {
+ try {
+ mNMService.addInterfaceToLocalNetwork(mIfName, localRoutes);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to add IPv6 routes to local table: ", e);
+ }
+ }
+ } else {
+ if (mLastLocalRoutes != null && !mLastLocalRoutes.isEmpty()) {
+ // TODO: Remove only locally added network routes.
+ // mNMSwervice.removeInterfaceFromLocalNetwork(mIfName);
+ }
+ }
+
+ mLastLocalRoutes = localRoutes;
+ }
+
+ private void updateRaParams(RaParams params) {
+ if (mRaDaemon != null) {
+ // Currently, we send spurious RAs (5) whenever there's any update.
+ // TODO: Compare params with mLastParams to avoid spurious updates.
+ mRaDaemon.buildNewRa(params);
+ }
+
+ mLastRaParams = params;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index aebeb69..9e7cb93 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -20,6 +20,7 @@
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.os.INetworkManagementService;
import android.os.Looper;
@@ -73,6 +74,8 @@
public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11;
// the upstream connection has changed
public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12;
+ // new IPv6 tethering parameters need to be processed
+ public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13;
private final State mInitialState;
private final State mTetheredState;
@@ -84,6 +87,7 @@
private final String mIfaceName;
private final int mInterfaceType;
+ private final IPv6TetheringInterfaceServices mIPv6TetherSvc;
private int mLastError;
private String mMyUpstreamIfaceName; // may change over time
@@ -97,6 +101,7 @@
mTetherController = tetherController;
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
+ mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService);
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
mInitialState = new InitialState();
@@ -109,6 +114,10 @@
setInitialState(mInitialState);
}
+ public int interfaceType() {
+ return mInterfaceType;
+ }
+
// configured when we start tethering and unconfig'd on error or conclusion
private boolean configureIfaceIp(boolean enabled) {
if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
@@ -175,6 +184,10 @@
case CMD_INTERFACE_DOWN:
transitionTo(mUnavailableState);
break;
+ case CMD_IPV6_TETHER_UPDATE:
+ mIPv6TetherSvc.updateUpstreamIPv6LinkProperties(
+ (LinkProperties) message.obj);
+ break;
default:
retValue = false;
break;
@@ -200,6 +213,11 @@
transitionTo(mInitialState);
return;
}
+
+ if (!mIPv6TetherSvc.start()) {
+ Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices");
+ }
+
if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
mTetherController.notifyInterfaceStateChange(
mIfaceName, TetherInterfaceStateMachine.this,
@@ -211,6 +229,7 @@
// Note that at this point, we're leaving the tethered state. We can fail any
// of these operations, but it doesn't really change that we have to try them
// all in sequence.
+ mIPv6TetherSvc.stop();
cleanupUpstream();
try {
@@ -287,6 +306,10 @@
}
mMyUpstreamIfaceName = newUpstreamIfaceName;
break;
+ case CMD_IPV6_TETHER_UPDATE:
+ mIPv6TetherSvc.updateUpstreamIPv6LinkProperties(
+ (LinkProperties) message.obj);
+ break;
case CMD_IP_FORWARDING_ENABLE_ERROR:
case CMD_IP_FORWARDING_DISABLE_ERROR:
case CMD_START_TETHERING_ERROR:
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6a6570b..fec7ed1 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -244,6 +244,7 @@
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);
publishLocalService(DisplayManagerInternal.class, new LocalService());
+ publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
new file mode 100644
index 0000000..cfeae7b
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.opengl.Matrix;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import android.util.SparseArray;
+
+/**
+ * Manager for applying color transformations to the display.
+ */
+public class DisplayTransformManager {
+
+ private static final String TAG = "DisplayTransformManager";
+
+ /**
+ * Color transform level used by Night display to tint the display red.
+ */
+ public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100;
+ /**
+ * Color transform level used by A11y services to make the display monochromatic.
+ */
+ public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
+ /**
+ * Color transform level used by A11y services to invert the display colors.
+ */
+ public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300;
+
+ private final SparseArray<float[]> mColorMatrix = new SparseArray<>(3);
+
+ private int mDaltonizerMode = -1;
+
+ /* package */ DisplayTransformManager() {
+ }
+
+ /**
+ * Returns the color transform matrix set for a given level.
+ */
+ public float[] getColorMatrix(int key) {
+ synchronized (mColorMatrix) {
+ return mColorMatrix.get(key);
+ }
+ }
+
+ /**
+ * Sets and applies a current color transform matrix for a given level.
+ * <p>
+ * Note: all color transforms are first composed to a single matrix in ascending order based
+ * on level before being applied to the display.
+ *
+ * @param key the level used to identify and compose the color transform (low -> high)
+ * @param value the 4x4 color transform matrix (in column-major order), or {@code null} to
+ * remove the color transform matrix associated with the provided level
+ */
+ public void setColorMatrix(int key, float[] value) {
+ if (value != null && value.length != 16) {
+ throw new IllegalArgumentException("Expected length: 16 (4x4 matrix)"
+ + ", actual length: " + value.length);
+ }
+
+ synchronized (mColorMatrix) {
+ if (value != null) {
+ mColorMatrix.put(key, value);
+ } else {
+ mColorMatrix.remove(key);
+ }
+
+ // Update the current color transform.
+ applyColorMatrix(computeColorMatrix());
+ }
+ }
+
+ /**
+ * Returns the composition of all current color matrices, or {@code null} if there are none.
+ */
+ private float[] computeColorMatrix() {
+ synchronized (mColorMatrix) {
+ final int count = mColorMatrix.size();
+ if (count == 0) {
+ return null;
+ }
+
+ final float[][] result = new float[2][16];
+ Matrix.setIdentityM(result[0], 0);
+ for (int i = 0; i < count; i++) {
+ float[] rhs = mColorMatrix.valueAt(i);
+ Matrix.multiplyMM(result[(i + 1) % 2], 0, result[i % 2], 0, rhs, 0);
+ }
+ return result[count % 2];
+ }
+ }
+
+ /**
+ * Returns the current Daltonization mode.
+ */
+ public int getDaltonizerMode() {
+ return mDaltonizerMode;
+ }
+
+ /**
+ * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate
+ * various types of color blindness.
+ *
+ * @param mode the new Daltonization mode, or -1 to disable
+ */
+ public void setDaltonizerMode(int mode) {
+ if (mDaltonizerMode != mode) {
+ mDaltonizerMode = mode;
+ applyDaltonizerMode(mode);
+ }
+ }
+
+ /**
+ * Propagates the provided color transformation matrix to the SurfaceFlinger.
+ */
+ private static void applyColorMatrix(float[] m) {
+ final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ if (m != null) {
+ data.writeInt(1);
+ for (int i = 0; i < 16; i++) {
+ data.writeFloat(m[i]);
+ }
+ } else {
+ data.writeInt(0);
+ }
+ try {
+ flinger.transact(1015, data, null, 0);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to set color transform", ex);
+ } finally {
+ data.recycle();
+ }
+ }
+ }
+
+ /**
+ * Propagates the provided Daltonization mode to the SurfaceFlinger.
+ */
+ private static void applyDaltonizerMode(int mode) {
+ final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ data.writeInt(mode);
+ try {
+ flinger.transact(1014, data, null, 0);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to set Daltonizer mode", ex);
+ } finally {
+ data.recycle();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 27abd1e..1f4ee9b 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -22,6 +22,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -47,11 +49,19 @@
private static final boolean DEBUG = false;
/**
- * Night mode ~= 3400 K.
+ * Night display ~= 3400 K.
*/
- private static final String MATRIX_NIGHT = "1,0,0,0,0,.754,0,0,0,0,.516,0,0,0,0,1";
+ private static final float[] MATRIX_NIGHT = new float[] {
+ 1, 0, 0, 0,
+ 0, 0.754f, 0, 0,
+ 0, 0, 0.516f, 0,
+ 0, 0, 0, 1
+ };
+
+ private final Handler mHandler;
private int mCurrentUser = UserHandle.USER_NULL;
+ private ContentObserver mUserSetupObserver;
private boolean mBootCompleted;
private NightDisplayController mController;
@@ -60,6 +70,7 @@
public NightDisplayService(Context context) {
super(context);
+ mHandler = new Handler(Looper.getMainLooper());
}
@Override
@@ -68,15 +79,23 @@
}
@Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ mBootCompleted = true;
+
+ // Register listeners now that boot is complete.
+ if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) {
+ setUp();
+ }
+ }
+ }
+
+ @Override
public void onStartUser(int userHandle) {
super.onStartUser(userHandle);
- // Register listeners for the new user.
if (mCurrentUser == UserHandle.USER_NULL) {
- mCurrentUser = userHandle;
- if (mBootCompleted) {
- setUpNightMode();
- }
+ onUserChanged(userHandle);
}
}
@@ -84,44 +103,60 @@
public void onSwitchUser(int userHandle) {
super.onSwitchUser(userHandle);
- // Unregister listeners for the old user.
- if (mBootCompleted && mCurrentUser != UserHandle.USER_NULL) {
- tearDownNightMode();
- }
-
- // Register listeners for the new user.
- mCurrentUser = userHandle;
- if (mBootCompleted) {
- setUpNightMode();
- }
+ onUserChanged(userHandle);
}
@Override
public void onStopUser(int userHandle) {
super.onStopUser(userHandle);
- // Unregister listeners for the old user.
if (mCurrentUser == userHandle) {
- if (mBootCompleted) {
- tearDownNightMode();
- }
- mCurrentUser = UserHandle.USER_NULL;
+ onUserChanged(UserHandle.USER_NULL);
}
}
- @Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_BOOT_COMPLETED) {
- mBootCompleted = true;
+ private void onUserChanged(int userHandle) {
+ final ContentResolver cr = getContext().getContentResolver();
- // Register listeners now that boot is complete.
- if (mCurrentUser != UserHandle.USER_NULL) {
- setUpNightMode();
+ if (mCurrentUser != UserHandle.USER_NULL) {
+ if (mUserSetupObserver != null) {
+ cr.unregisterContentObserver(mUserSetupObserver);
+ mUserSetupObserver = null;
+ } else if (mBootCompleted) {
+ tearDown();
+ }
+ }
+
+ mCurrentUser = userHandle;
+
+ if (mCurrentUser != UserHandle.USER_NULL) {
+ if (!isUserSetupCompleted(cr, mCurrentUser)) {
+ mUserSetupObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (isUserSetupCompleted(cr, mCurrentUser)) {
+ cr.unregisterContentObserver(this);
+ mUserSetupObserver = null;
+
+ if (mBootCompleted) {
+ setUp();
+ }
+ }
+ }
+ };
+ cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
+ false /* notifyForDescendents */, mUserSetupObserver, mCurrentUser);
+ } else if (mBootCompleted) {
+ setUp();
}
}
}
- private void setUpNightMode() {
+ private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) {
+ return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
+ }
+
+ private void setUp() {
// Create a new controller for the current user and start listening for changes.
mController = new NightDisplayController(getContext(), mCurrentUser);
mController.setListener(this);
@@ -135,8 +170,11 @@
}
}
- private void tearDownNightMode() {
- mController.setListener(null);
+ private void tearDown() {
+ if (mController != null) {
+ mController.setListener(null);
+ mController = null;
+ }
if (mAutoMode != null) {
mAutoMode.onStop();
@@ -144,7 +182,6 @@
}
mIsActivated = null;
- mController = null;
}
@Override
@@ -159,9 +196,9 @@
}
// Update the current color matrix.
- final ContentResolver cr = getContext().getContentResolver();
- Secure.putStringForUser(cr, Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- activated ? MATRIX_NIGHT : null, mCurrentUser);
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY,
+ activated ? MATRIX_NIGHT : null);
}
}
@@ -319,13 +356,11 @@
private class TwilightAutoMode extends AutoMode implements TwilightListener {
private final TwilightManager mTwilightManager;
- private final Handler mHandler;
private boolean mIsNight;
public TwilightAutoMode() {
mTwilightManager = getLocalService(TwilightManager.class);
- mHandler = new Handler(Looper.getMainLooper());
}
private void updateActivated() {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 8589de1..8f212db 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1556,6 +1556,11 @@
}
}
+ if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
+ }
+
long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.schedule(job, uid);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 8aef471..4b39bf9 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -491,6 +491,7 @@
+ ":[" + job.getService()
+ ",jId=" + job.getId()
+ ",u" + getUserId()
+ + ",suid=" + getSourceUid()
+ ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
+ "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
+ ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 29c54e9..88d6c14 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -454,7 +454,7 @@
@Override
public String toString() {
- return mPackageName + "/" + mTag;
+ return mPackageName + "/" + mTag + " (uid=" + mUserId + ")";
}
private void postAdjustLocalVolume(final int stream, final int direction, final int flags,
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 2446f6a..d02424b 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -47,10 +47,12 @@
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.TextUtils;
@@ -67,6 +69,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -97,7 +100,9 @@
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
- private int mCurrentUserId = -1;
+ // List of user IDs running in the foreground.
+ // Multiple users can be in the foreground if the work profile is on.
+ private final List<Integer> mCurrentUserIdList = new ArrayList<>();
// Used to notify system UI when remote volume was changed. TODO find a
// better way to handle this.
@@ -181,22 +186,26 @@
}
@Override
- public void onStartUser(int userHandle) {
+ public void onStartUser(int userId) {
+ if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
updateUser();
}
@Override
- public void onSwitchUser(int userHandle) {
+ public void onSwitchUser(int userId) {
+ if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
updateUser();
}
@Override
- public void onStopUser(int userHandle) {
+ public void onStopUser(int userId) {
+ if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
synchronized (mLock) {
- UserRecord user = mUserRecords.get(userHandle);
+ UserRecord user = mUserRecords.get(userId);
if (user != null) {
destroyUserLocked(user);
}
+ updateUser();
}
}
@@ -227,19 +236,24 @@
}
private void updateUser() {
- int userId = ActivityManager.getCurrentUser();
synchronized (mLock) {
- if (mCurrentUserId != userId) {
- final int oldUserId = mCurrentUserId;
- mCurrentUserId = userId; // do this first
-
- UserRecord oldUser = mUserRecords.get(oldUserId);
- if (oldUser != null) {
- oldUser.stopLocked();
+ UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+ int currentUser = ActivityManager.getCurrentUser();
+ int[] userIds = manager.getEnabledProfileIds(currentUser);
+ mCurrentUserIdList.clear();
+ if (userIds != null && userIds.length > 0) {
+ for (int userId : userIds) {
+ mCurrentUserIdList.add(userId);
}
-
- UserRecord newUser = getOrCreateUser(userId);
- newUser.startLocked();
+ } else {
+ // This shouldn't happen.
+ Log.w(TAG, "Failed to get enabled profiles.");
+ mCurrentUserIdList.add(currentUser);
+ }
+ for (int userId : mCurrentUserIdList) {
+ if (mUserRecords.get(userId) == null) {
+ mUserRecords.put(userId, new UserRecord(getContext(), userId));
+ }
}
}
}
@@ -272,7 +286,6 @@
* @param user The user to dispose of
*/
private void destroyUserLocked(UserRecord user) {
- user.stopLocked();
user.destroyLocked();
mUserRecords.remove(user.mUserId);
}
@@ -436,9 +449,9 @@
}
mAllSessions.add(session);
- mPriorityStack.addSession(session);
+ mPriorityStack.addSession(session, mCurrentUserIdList.contains(userId));
- UserRecord user = getOrCreateUser(userId);
+ UserRecord user = mUserRecords.get(userId);
user.addSessionLocked(session);
mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
@@ -449,15 +462,6 @@
return session;
}
- private UserRecord getOrCreateUser(int userId) {
- UserRecord user = mUserRecords.get(userId);
- if (user == null) {
- user = new UserRecord(getContext(), userId);
- mUserRecords.put(userId, user);
- }
- return user;
- }
-
private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
if (mSessionsListeners.get(i).mListener.asBinder() == listener.asBinder()) {
@@ -536,13 +540,6 @@
restoreMediaButtonReceiver();
}
- public void startLocked() {
- }
-
- public void stopLocked() {
- // nothing for now
- }
-
public void destroyLocked() {
for (int i = mSessions.size() - 1; i >= 0; i--) {
MediaSessionRecord session = mSessions.get(i);
@@ -578,7 +575,7 @@
private void restoreMediaButtonReceiver() {
String receiverName = Settings.Secure.getStringForUser(mContentResolver,
- Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
+ Settings.System.MEDIA_BUTTON_RECEIVER, mUserId);
if (!TextUtils.isEmpty(receiverName)) {
ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
if (eventReceiver == null) {
@@ -767,12 +764,22 @@
synchronized (mLock) {
// If we don't have a media button receiver to fall back on
// include non-playing sessions for dispatching
- UserRecord ur = mUserRecords.get(mCurrentUserId);
- boolean useNotPlayingSessions = (ur == null) ||
- (ur.mLastMediaButtonReceiver == null
- && ur.mRestoredMediaButtonReceiver == null);
- MediaSessionRecord session = mPriorityStack
- .getDefaultMediaButtonSession(mCurrentUserId, useNotPlayingSessions);
+ boolean useNotPlayingSessions = true;
+ for (int userId : mCurrentUserIdList) {
+ UserRecord ur = mUserRecords.get(userId);
+ if (ur.mLastMediaButtonReceiver != null
+ || ur.mRestoredMediaButtonReceiver != null) {
+ useNotPlayingSessions = false;
+ break;
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
+ + useNotPlayingSessions);
+ }
+ MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
+ mCurrentUserIdList, useNotPlayingSessions);
if (isVoiceKey(keyEvent.getKeyCode())) {
handleVoiceKeyEventLocked(keyEvent, needWakeLock, session);
} else {
@@ -786,13 +793,11 @@
@Override
public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
MediaSessionRecord session = mPriorityStack
- .getDefaultVolumeSession(mCurrentUserId);
+ .getDefaultVolumeSession(mCurrentUserIdList);
dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session);
}
} finally {
@@ -910,7 +915,7 @@
});
} else {
session.adjustVolume(direction, flags, getContext().getPackageName(),
- UserHandle.myUserId(), true);
+ Process.SYSTEM_UID, true);
}
}
@@ -957,13 +962,16 @@
// won't release it later
session.sendMediaButton(keyEvent,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
- mKeyEventReceiver, getContext().getApplicationInfo().uid,
+ mKeyEventReceiver, Process.SYSTEM_UID,
getContext().getPackageName());
} else {
// Launch the last PendingIntent we had with priority
- UserRecord user = mUserRecords.get(mCurrentUserId);
- if (user != null && (user.mLastMediaButtonReceiver != null
- || user.mRestoredMediaButtonReceiver != null)) {
+ for (int userId : mCurrentUserIdList) {
+ UserRecord user = mUserRecords.get(userId);
+ if (user.mLastMediaButtonReceiver == null
+ && user.mRestoredMediaButtonReceiver == null) {
+ continue;
+ }
if (DEBUG) {
Log.d(TAG, "Sending media key to last known PendingIntent "
+ user.mLastMediaButtonReceiver + " or restored Intent "
@@ -983,30 +991,30 @@
} else {
mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
getContext().sendBroadcastAsUser(mediaButtonIntent,
- new UserHandle(mCurrentUserId));
+ UserHandle.of(userId));
}
} catch (CanceledException e) {
Log.i(TAG, "Error sending key event to media button receiver "
+ user.mLastMediaButtonReceiver, e);
}
- } else {
- if (DEBUG) {
- Log.d(TAG, "Sending media key ordered broadcast");
- }
- if (needWakeLock) {
- mMediaEventWakeLock.acquire();
- }
- // Fallback to legacy behavior
- Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- keyIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
- if (needWakeLock) {
- keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
- WAKELOCK_RELEASE_ON_FINISHED);
- }
- getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.CURRENT,
- null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
+ return;
}
+ if (DEBUG) {
+ Log.d(TAG, "Sending media key ordered broadcast");
+ }
+ if (needWakeLock) {
+ mMediaEventWakeLock.acquire();
+ }
+ // Fallback to legacy behavior
+ Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ keyIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ if (needWakeLock) {
+ keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+ }
+ // Send broadcast only to the full user.
+ getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.CURRENT,
+ null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
}
}
@@ -1036,6 +1044,7 @@
if (voiceIntent != null) {
voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT);
}
} catch (ActivityNotFoundException e) {
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index cc007ef..3327b36 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -32,7 +32,7 @@
* Keeps track of media sessions and their priority for notifications, media
* button dispatch, etc.
*/
-public class MediaSessionStack {
+class MediaSessionStack {
/**
* These are states that usually indicate the user took an action and should
* bump priority regardless of the old state.
@@ -68,13 +68,10 @@
* Checks if a media session is created from the most recent app.
*
* @param record A media session record to be examined.
- * @return true if the media session's package name equals to the most recent app, false
- * otherwise.
+ * @return {@code true} if the media session's package name equals to the most recent app, false
+ * otherwise.
*/
private static boolean isFromMostRecentApp(MediaSessionRecord record) {
- if (ActivityManager.getCurrentUser() != record.getUserId()) {
- return false;
- }
try {
List<ActivityManager.RecentTaskInfo> tasks =
ActivityManagerNative.getDefault().getRecentTasks(1,
@@ -84,9 +81,10 @@
ActivityManager.RECENT_WITH_EXCLUDED, record.getUserId()).getList();
if (tasks != null && !tasks.isEmpty()) {
ActivityManager.RecentTaskInfo recentTask = tasks.get(0);
- if (recentTask.baseIntent != null)
+ if (recentTask.userId == record.getUserId() && recentTask.baseIntent != null) {
return recentTask.baseIntent.getComponent().getPackageName()
.equals(record.getPackageName());
+ }
}
} catch (RemoteException e) {
return false;
@@ -98,11 +96,12 @@
* Add a record to the priority tracker.
*
* @param record The record to add.
+ * @param fromForegroundUser {@code true} if the session is created by the foreground user.
*/
- public void addSession(MediaSessionRecord record) {
+ public void addSession(MediaSessionRecord record, boolean fromForegroundUser) {
mSessions.add(record);
clearCache();
- if (isFromMostRecentApp(record)) {
+ if (fromForegroundUser && isFromMostRecentApp(record)) {
mLastInterestingRecord = record;
}
}
@@ -210,12 +209,13 @@
/**
* Get the highest priority session that can handle media buttons.
*
- * @param userId The user to check.
+ * @param userIdList The user lists to check.
* @param includeNotPlaying Return a non-playing session if nothing else is
* available
* @return The default media button session or null.
*/
- public MediaSessionRecord getDefaultMediaButtonSession(int userId, boolean includeNotPlaying) {
+ public MediaSessionRecord getDefaultMediaButtonSession(
+ List<Integer> userIdList, boolean includeNotPlaying) {
if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
return mGlobalPrioritySession;
}
@@ -223,7 +223,7 @@
return mCachedButtonReceiver;
}
ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
- MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId);
+ MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userIdList);
if (records.size() > 0) {
MediaSessionRecord record = records.get(0);
if (record.isPlaybackActive(false)) {
@@ -248,14 +248,14 @@
return mCachedButtonReceiver;
}
- public MediaSessionRecord getDefaultVolumeSession(int userId) {
+ public MediaSessionRecord getDefaultVolumeSession(List<Integer> userIdList) {
if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
return mGlobalPrioritySession;
}
if (mCachedVolumeDefault != null) {
return mCachedVolumeDefault;
}
- ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
+ ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userIdList);
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
@@ -298,6 +298,13 @@
}
}
+ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
+ int userId) {
+ List<Integer> userIdList = new ArrayList<>();
+ userIdList.add(userId);
+ return getPriorityListLocked(activeOnly, withFlags, userIdList);
+ }
+
/**
* Get a priority sorted list of sessions. Can filter to only return active
* sessions or sessions with specific flags.
@@ -306,22 +313,23 @@
* all sessions.
* @param withFlags Only return sessions with all the specified flags set. 0
* returns all sessions.
- * @param userId The user to get sessions for. {@link UserHandle#USER_ALL}
+ * @param userIdList The user to get sessions for. {@link UserHandle#USER_ALL}
* will return sessions for all users.
* @return The priority sorted list of sessions.
*/
private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
- int userId) {
+ List<Integer> userIdList) {
ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
int lastLocalIndex = 0;
int lastActiveIndex = 0;
int lastPublishedIndex = 0;
+ boolean filterUser = !userIdList.contains(UserHandle.USER_ALL);
int size = mSessions.size();
for (int i = 0; i < size; i++) {
final MediaSessionRecord session = mSessions.get(i);
- if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
+ if (filterUser && !userIdList.contains(session.getUserId())) {
// Filter out sessions for the wrong user
continue;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 7f2b81e..8dcf653 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1241,6 +1241,24 @@
private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) {
// TODO: reach into ConnectivityManager to proactively disable bringing
// up this network, since we know that traffic will be blocked.
+
+ if (template.getMatchRule() == MATCH_MOBILE_ALL) {
+ // If mobile data usage hits the limit or if the user resumes the data, we need to
+ // notify telephony.
+ final SubscriptionManager sm = SubscriptionManager.from(mContext);
+ final TelephonyManager tm = TelephonyManager.from(mContext);
+
+ final int[] subIds = sm.getActiveSubscriptionIdList();
+ for (int subId : subIds) {
+ final String subscriberId = tm.getSubscriberId(subId);
+ final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
+ // Template is matched when subscriber id matches.
+ if (template.matches(probeIdent)) {
+ tm.setPolicyDataEnabled(enabled, subId);
+ }
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 03430e1..57cf713 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -58,7 +58,6 @@
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.app.StatusBarManager;
import android.app.backup.BackupManager;
import android.app.usage.UsageEvents;
@@ -93,7 +92,6 @@
import android.os.IInterface;
import android.os.Looper;
import android.os.Message;
-import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -122,6 +120,8 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import android.view.WindowManager;
+import android.view.WindowManagerInternal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
@@ -232,6 +232,7 @@
@Nullable StatusBarManagerInternal mStatusBar;
Vibrator mVibrator;
private VrManagerInternal mVrManagerInternal;
+ private WindowManagerInternal mWindowManagerInternal;
final IBinder mForegroundToken = new Binder();
private Handler mHandler;
@@ -452,13 +453,15 @@
final String pkg;
final ITransientNotification callback;
int duration;
+ Binder token;
- ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
- {
+ ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
+ Binder token) {
this.pid = pid;
this.pkg = pkg;
this.callback = callback;
this.duration = duration;
+ this.token = token;
}
void update(int duration) {
@@ -1125,6 +1128,7 @@
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mVrManagerInternal = getLocalService(VrManagerInternal.class);
+ mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mZenModeHelper.onSystemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
@@ -1325,10 +1329,13 @@
}
}
- record = new ToastRecord(callingPid, pkg, callback, duration);
+ Binder token = new Binder();
+ mWindowManagerInternal.addWindowToken(token,
+ WindowManager.LayoutParams.TYPE_TOAST);
+ record = new ToastRecord(callingPid, pkg, callback, duration, token);
mToastQueue.add(record);
index = mToastQueue.size() - 1;
- keepProcessAliveLocked(callingPid);
+ keepProcessAliveIfNeededLocked(callingPid);
}
// If it's at index 0, it's the current toast. It doesn't matter if it's
// new or just been updated. Call back and tell it to show itself.
@@ -1851,7 +1858,7 @@
enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
final long identity = Binder.clearCallingIdentity();
try {
- mZenModeHelper.setManualZenMode(mode, conditionId, reason);
+ mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1928,7 +1935,7 @@
if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
final long identity = Binder.clearCallingIdentity();
try {
- mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
+ mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2987,7 +2994,7 @@
while (record != null) {
if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
try {
- record.callback.show();
+ record.callback.show(record.token);
scheduleTimeoutLocked(record);
return;
} catch (RemoteException e) {
@@ -2998,7 +3005,7 @@
if (index >= 0) {
mToastQueue.remove(index);
}
- keepProcessAliveLocked(record.pid);
+ keepProcessAliveIfNeededLocked(record.pid);
if (mToastQueue.size() > 0) {
record = mToastQueue.get(0);
} else {
@@ -3018,8 +3025,11 @@
// don't worry about this, we're about to remove it from
// the list anyway
}
- mToastQueue.remove(index);
- keepProcessAliveLocked(record.pid);
+
+ ToastRecord lastToast = mToastQueue.remove(index);
+ mWindowManagerInternal.removeWindowToken(lastToast.token, true);
+
+ keepProcessAliveIfNeededLocked(record.pid);
if (mToastQueue.size() > 0) {
// Show the next one. If the callback fails, this will remove
// it from the list, so don't assume that the list hasn't changed
@@ -3063,7 +3073,7 @@
}
// lock on mToastQueue
- void keepProcessAliveLocked(int pid)
+ void keepProcessAliveIfNeededLocked(int pid)
{
int toastCount = 0; // toasts from this pid
ArrayList<ToastRecord> list = mToastQueue;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 41b78f6..e5abc30 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -54,7 +54,6 @@
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
-import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.util.SparseArray;
@@ -229,7 +228,7 @@
public void requestFromListener(ComponentName name, int filter) {
final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
if (newZen != -1) {
- setManualZenMode(newZen, null,
+ setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
"listener:" + (name != null ? name.flattenToShortString() : null));
}
}
@@ -452,11 +451,11 @@
rule.creationTime);
}
- public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
- setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/);
+ public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
+ setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
}
- private void setManualZenMode(int zenMode, Uri conditionId, String reason,
+ private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
boolean setRingerMode) {
ZenModeConfig newConfig;
synchronized (mConfig) {
@@ -478,6 +477,7 @@
newRule.enabled = true;
newRule.zenMode = zenMode;
newRule.conditionId = conditionId;
+ newRule.enabler = caller;
newConfig.manualRule = newRule;
}
setConfigLocked(newConfig, reason, setRingerMode);
@@ -950,7 +950,8 @@
break;
}
if (newZen != -1) {
- setManualZenMode(newZen, null, "ringerModeInternal", false /*setRingerMode*/);
+ setManualZenMode(newZen, null, "ringerModeInternal", null,
+ false /*setRingerMode*/);
}
if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
@@ -988,7 +989,8 @@
break;
}
if (newZen != -1) {
- setManualZenMode(newZen, null, "ringerModeExternal", false /*setRingerMode*/);
+ setManualZenMode(newZen, null, "ringerModeExternal", caller,
+ false /*setRingerMode*/);
}
ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
diff --git a/services/core/java/com/android/server/pm/AbstractStatsBase.java b/services/core/java/com/android/server/pm/AbstractStatsBase.java
new file mode 100644
index 0000000..612c476
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AbstractStatsBase.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.Environment;
+import android.os.SystemClock;
+import android.util.AtomicFile;
+
+import java.io.File;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A simple base class for statistics that need to be saved/restored from a dedicated file. This
+ * class provides a base implementation that:
+ * <ul>
+ * <li>Provide an AtomicFile to the actual read/write code
+ * <li>A background-thread write and a synchronous write
+ * <li>Write-limiting for the background-thread (by default writes are at least 30 minutes apart)
+ * <li>Can lock on the provided data object before writing
+ * </ul>
+ * For completion, a subclass needs to implement actual {@link #writeInternal(Object) writing} and
+ * {@link #readInternal(Object) reading}.
+ */
+public abstract class AbstractStatsBase<T> {
+
+ private static final int WRITE_INTERVAL_MS =
+ (PackageManagerService.DEBUG_DEXOPT) ? 0 : 30*60*1000;
+ private final Object mFileLock = new Object();
+ private final AtomicLong mLastTimeWritten = new AtomicLong(0);
+ private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
+ private final String mFileName;
+ private final String mBackgroundThreadName;
+ private final boolean mLock;
+
+ protected AbstractStatsBase(String fileName, String threadName, boolean lock) {
+ mFileName = fileName;
+ mBackgroundThreadName = threadName;
+ mLock = lock;
+ }
+
+ protected AtomicFile getFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, mFileName);
+ return new AtomicFile(fname);
+ }
+
+ void writeNow(final T data) {
+ writeImpl(data);
+ mLastTimeWritten.set(SystemClock.elapsedRealtime());
+ }
+
+ boolean maybeWriteAsync(final T data) {
+ if (SystemClock.elapsedRealtime() - mLastTimeWritten.get() < WRITE_INTERVAL_MS
+ && !PackageManagerService.DEBUG_DEXOPT) {
+ return false;
+ }
+
+ if (mBackgroundWriteRunning.compareAndSet(false, true)) {
+ new Thread(mBackgroundThreadName) {
+ @Override
+ public void run() {
+ try {
+ writeImpl(data);
+ mLastTimeWritten.set(SystemClock.elapsedRealtime());
+ } finally {
+ mBackgroundWriteRunning.set(false);
+ }
+ }
+ }.start();
+ return true;
+ }
+
+ return false;
+ }
+
+ private void writeImpl(T data) {
+ if (mLock) {
+ synchronized (data) {
+ synchronized (mFileLock) {
+ writeInternal(data);
+ }
+ }
+ } else {
+ synchronized (mFileLock) {
+ writeInternal(data);
+ }
+ }
+ }
+
+ protected abstract void writeInternal(T data);
+
+ void read(T data) {
+ if (mLock) {
+ synchronized (data) {
+ synchronized (mFileLock) {
+ readInternal(data);
+ }
+ }
+ } else {
+ synchronized (mFileLock) {
+ readInternal(data);
+ }
+ }
+ // We use the current time as last-written. read() is called on system server startup
+ // (current situation), and we want to postpone I/O at boot.
+ mLastTimeWritten.set(SystemClock.elapsedRealtime());
+ }
+
+ protected abstract void readInternal(T data);
+}
diff --git a/services/core/java/com/android/server/pm/CompilerStats.java b/services/core/java/com/android/server/pm/CompilerStats.java
new file mode 100644
index 0000000..8c2fc3e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CompilerStats.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Log;
+
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.IndentingPrintWriter;
+
+import libcore.io.IoUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class that collects, serializes and deserializes compiler-related statistics on a
+ * per-package per-code-path basis.
+ *
+ * Currently used to track compile times.
+ */
+class CompilerStats extends AbstractStatsBase<Void> {
+
+ private final static String COMPILER_STATS_VERSION_HEADER = "PACKAGE_MANAGER__COMPILER_STATS__";
+ private final static int COMPILER_STATS_VERSION = 1;
+
+ /**
+ * Class to collect all stats pertaining to one package.
+ */
+ static class PackageStats {
+
+ private final String packageName;
+
+ /**
+ * This map stores compile-times for all code paths in the package. The value
+ * is in milliseconds.
+ */
+ private final Map<String, Long> compileTimePerCodePath;
+
+ /**
+ * @param packageName
+ */
+ public PackageStats(String packageName) {
+ this.packageName = packageName;
+ // We expect at least one element in here, but let's make it minimal.
+ compileTimePerCodePath = new ArrayMap<>(2);
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ /**
+ * Return the recorded compile time for a given code path. Returns
+ * 0 if there is no recorded time.
+ */
+ public long getCompileTime(String codePath) {
+ String storagePath = getStoredPathFromCodePath(codePath);
+ synchronized (compileTimePerCodePath) {
+ Long l = compileTimePerCodePath.get(storagePath);
+ if (l == null) {
+ return 0;
+ }
+ return l;
+ }
+ }
+
+ public void setCompileTime(String codePath, long compileTimeInMs) {
+ String storagePath = getStoredPathFromCodePath(codePath);
+ synchronized (compileTimePerCodePath) {
+ if (compileTimeInMs <= 0) {
+ compileTimePerCodePath.remove(storagePath);
+ } else {
+ compileTimePerCodePath.put(storagePath, compileTimeInMs);
+ }
+ }
+ }
+
+ private static String getStoredPathFromCodePath(String codePath) {
+ int lastSlash = codePath.lastIndexOf(File.separatorChar);
+ return codePath.substring(lastSlash + 1);
+ }
+
+ public void dump(IndentingPrintWriter ipw) {
+ synchronized (compileTimePerCodePath) {
+ if (compileTimePerCodePath.size() == 0) {
+ ipw.println("(No recorded stats)");
+ } else {
+ for (Map.Entry<String, Long> e : compileTimePerCodePath.entrySet()) {
+ ipw.println(" " + e.getKey() + " - " + e.getValue());
+ }
+ }
+ }
+ }
+ }
+
+ private final Map<String, PackageStats> packageStats;
+
+ public CompilerStats() {
+ super("package-cstats.list", "CompilerStats_DiskWriter", /* lock */ false);
+ packageStats = new HashMap<>();
+ }
+
+ public PackageStats getPackageStats(String packageName) {
+ synchronized (packageStats) {
+ return packageStats.get(packageName);
+ }
+ }
+
+ public void setPackageStats(String packageName, PackageStats stats) {
+ synchronized (packageStats) {
+ packageStats.put(packageName, stats);
+ }
+ }
+
+ public PackageStats createPackageStats(String packageName) {
+ synchronized (packageStats) {
+ PackageStats newStats = new PackageStats(packageName);
+ packageStats.put(packageName, newStats);
+ return newStats;
+ }
+ }
+
+ public PackageStats getOrCreatePackageStats(String packageName) {
+ synchronized (packageStats) {
+ PackageStats existingStats = packageStats.get(packageName);
+ if (existingStats != null) {
+ return existingStats;
+ }
+
+ return createPackageStats(packageName);
+ }
+ }
+
+ public void deletePackageStats(String packageName) {
+ synchronized (packageStats) {
+ packageStats.remove(packageName);
+ }
+ }
+
+ // I/O
+
+ // The encoding is simple:
+ //
+ // 1) The first line is a line consisting of the version header and the version number.
+ //
+ // 2) The rest of the file is package data.
+ // 2.1) A package is started by any line not starting with "-";
+ // 2.2) Any line starting with "-" is code path data. The format is:
+ // '-'{code-path}':'{compile-time}
+
+ public void write(Writer out) {
+ @SuppressWarnings("resource")
+ FastPrintWriter fpw = new FastPrintWriter(out);
+
+ fpw.print(COMPILER_STATS_VERSION_HEADER);
+ fpw.println(COMPILER_STATS_VERSION);
+
+ synchronized (packageStats) {
+ for (PackageStats pkg : packageStats.values()) {
+ synchronized (pkg.compileTimePerCodePath) {
+ if (!pkg.compileTimePerCodePath.isEmpty()) {
+ fpw.println(pkg.getPackageName());
+
+ for (Map.Entry<String, Long> e : pkg.compileTimePerCodePath.entrySet()) {
+ fpw.println("-" + e.getKey() + ":" + e.getValue());
+ }
+ }
+ }
+ }
+ }
+
+ fpw.flush();
+ }
+
+ public boolean read(Reader r) {
+ synchronized (packageStats) {
+ // TODO: Could make this a final switch, then we wouldn't have to synchronize over
+ // the whole reading.
+ packageStats.clear();
+
+ try {
+ BufferedReader in = new BufferedReader(r);
+
+ // Read header, do version check.
+ String versionLine = in.readLine();
+ if (versionLine == null) {
+ throw new IllegalArgumentException("No version line found.");
+ } else {
+ if (!versionLine.startsWith(COMPILER_STATS_VERSION_HEADER)) {
+ throw new IllegalArgumentException("Invalid version line: " + versionLine);
+ }
+ int version = Integer.parseInt(
+ versionLine.substring(COMPILER_STATS_VERSION_HEADER.length()));
+ if (version != COMPILER_STATS_VERSION) {
+ // TODO: Upgrade older formats? For now, just reject and regenerate.
+ throw new IllegalArgumentException("Unexpected version: " + version);
+ }
+ }
+
+ // For simpler code, we ignore any data lines before the first package. We
+ // collect it in a fake package.
+ PackageStats currentPackage = new PackageStats("fake package");
+
+ String s = null;
+ while ((s = in.readLine()) != null) {
+ if (s.startsWith("-")) {
+ int colonIndex = s.indexOf(':');
+ if (colonIndex == -1 || colonIndex == 1) {
+ throw new IllegalArgumentException("Could not parse data " + s);
+ }
+ String codePath = s.substring(1, colonIndex);
+ long time = Long.parseLong(s.substring(colonIndex + 1));
+ currentPackage.setCompileTime(codePath, time);
+ } else {
+ currentPackage = getOrCreatePackageStats(s);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(PackageManagerService.TAG, "Error parsing compiler stats", e);
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ void writeNow() {
+ writeNow(null);
+ }
+
+ boolean maybeWriteAsync() {
+ return maybeWriteAsync(null);
+ }
+
+ @Override
+ protected void writeInternal(Void data) {
+ AtomicFile file = getFile();
+ FileOutputStream f = null;
+
+ try {
+ f = file.startWrite();
+ OutputStreamWriter osw = new OutputStreamWriter(f);
+ write(osw);
+ osw.flush();
+ file.finishWrite(f);
+ } catch (IOException e) {
+ if (f != null) {
+ file.failWrite(f);
+ }
+ Log.e(PackageManagerService.TAG, "Failed to write compiler stats", e);
+ }
+ }
+
+ void read() {
+ read((Void)null);
+ }
+
+ @Override
+ protected void readInternal(Void data) {
+ AtomicFile file = getFile();
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new InputStreamReader(file.openRead()));
+ read(in);
+ } catch (FileNotFoundException expected) {
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 098b39e..1cff926 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -31,6 +31,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.print.PrintManager;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
@@ -605,6 +606,15 @@
grantRuntimePermissionsLPw(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
grantRuntimePermissionsLPw(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
}
+
+ // Storage Manager
+ Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
+ PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackageLPr(
+ storageManagerIntent, userId);
+ if (storageManagerPckg != null
+ && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
+ grantRuntimePermissionsLPw(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
+ }
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
@@ -619,6 +629,7 @@
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(dialerPackage, CAMERA_PERMISSIONS, userId);
}
}
@@ -656,6 +667,7 @@
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, false, true, userId);
grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissionsLPw(dialerPackage, CAMERA_PERMISSIONS, false, true, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 01b3dc2..77c69c9 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -213,9 +213,20 @@
// Use the package manager install and install lock here for the OTA dex optimizer.
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
+ // Make sure that core apps are optimized according to their own "reason".
+ // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed
+ // (by default is speed-profile) they will be interepreted/JITed. This in itself is not a
+ // problem as we will end up doing profile guided compilation. However, some core apps may
+ // be loaded by system server which doesn't JIT and we need to make sure we don't
+ // interpret-only
+ int compilationReason = nextPackage.coreApp
+ ? PackageManagerService.REASON_CORE_APP
+ : PackageManagerService.REASON_AB_OTA;
+
optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
null /* ISAs */, false /* checkProfiles */,
- getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
+ getCompilerFilterForReason(compilationReason),
+ null /* CompilerStats.PackageStats */);
mCommandsForCurrentPackage = collectingConnection.commands;
if (mCommandsForCurrentPackage.isEmpty()) {
@@ -261,7 +272,8 @@
mPackageManagerService.mInstaller, mPackageManagerService.mInstallLock, mContext);
optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles, null /* ISAs */,
false /* checkProfiles */,
- getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
+ getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA),
+ mPackageManagerService.getOrCreateCompilerPackageStats(nextPackage));
}
private void moveAbArtifacts(Installer installer) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 26a840d..19b1201 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -90,7 +90,8 @@
* synchronized on {@link #mInstallLock}.
*/
int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
- String[] instructionSets, boolean checkProfiles, String targetCompilationFilter) {
+ String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
+ CompilerStats.PackageStats packageStats) {
synchronized (mInstallLock) {
final boolean useLock = mSystemReady;
if (useLock) {
@@ -99,7 +100,7 @@
}
try {
return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
- targetCompilationFilter);
+ targetCompilationFilter, packageStats);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -150,7 +151,8 @@
}
private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
- String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter) {
+ String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter,
+ CompilerStats.PackageStats packageStats) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -254,10 +256,17 @@
| DEXOPT_BOOTCOMPLETE);
try {
+ long startTime = System.currentTimeMillis();
+
mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid,
sharedLibrariesPath);
performedDexOpt = true;
+
+ if (packageStats != null) {
+ long endTime = System.currentTimeMillis();
+ packageStats.setCompileTime(path, (int)(endTime - startTime));
+ }
} catch (InstallerException e) {
Slog.w(TAG, "Failed to dexopt", e);
successfulDexOpt = false;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 83af017..6a56fa6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -182,6 +182,10 @@
*/
private final Random mRandom = new SecureRandom();
+ /** All sessions allocated */
+ @GuardedBy("mSessions")
+ private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
+
@GuardedBy("mSessions")
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
@@ -365,6 +369,7 @@
// keep details around for dumpsys.
mHistoricalSessions.put(session.sessionId, session);
}
+ mAllocatedSessions.put(session.sessionId, true);
}
}
}
@@ -666,23 +671,26 @@
"Too many historical sessions for UID " + callingUid);
}
- final long createdMillis = System.currentTimeMillis();
sessionId = allocateSessionIdLocked();
+ }
- // We're staging to exactly one location
- File stageDir = null;
- String stageCid = null;
- if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- final boolean isEphemeral =
- (params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
- stageDir = buildStageDir(params.volumeUuid, sessionId, isEphemeral);
- } else {
- stageCid = buildExternalStageCid(sessionId);
- }
+ final long createdMillis = System.currentTimeMillis();
+ // We're staging to exactly one location
+ File stageDir = null;
+ String stageCid = null;
+ if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+ final boolean isEphemeral =
+ (params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
+ stageDir = buildStageDir(params.volumeUuid, sessionId, isEphemeral);
+ } else {
+ stageCid = buildExternalStageCid(sessionId);
+ }
- session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
- mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
- params, createdMillis, stageDir, stageCid, false, false);
+ session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
+ mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
+ params, createdMillis, stageDir, stageCid, false, false);
+
+ synchronized (mSessions) {
mSessions.put(sessionId, session);
}
@@ -765,8 +773,8 @@
int sessionId;
do {
sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
- if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null
- && !mLegacySessions.get(sessionId, false)) {
+ if (!mAllocatedSessions.get(sessionId, false)) {
+ mAllocatedSessions.put(sessionId, true);
return sessionId;
}
} while (n++ < 32);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 455e1fa..b907be0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -76,8 +76,6 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
import static android.content.pm.PackageParser.isApkFile;
-import static android.os.Process.PACKAGE_INFO_GID;
-import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
@@ -95,6 +93,7 @@
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
@@ -159,7 +158,6 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.ShortcutServiceInternal;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
@@ -208,7 +206,6 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
@@ -267,7 +264,6 @@
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
@@ -280,7 +276,6 @@
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
-import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
@@ -307,7 +302,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
/**
* Keep track of all those APKs everywhere.
@@ -1131,204 +1125,7 @@
final @NonNull String mSharedSystemSharedLibraryPackageName;
private final PackageUsage mPackageUsage = new PackageUsage();
-
- private class PackageUsage {
- private static final int WRITE_INTERVAL
- = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms
-
- private final Object mFileLock = new Object();
- private final AtomicLong mLastWritten = new AtomicLong(0);
- private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
-
- private boolean mIsHistoricalPackageUsageAvailable = true;
-
- boolean isHistoricalPackageUsageAvailable() {
- return mIsHistoricalPackageUsageAvailable;
- }
-
- void write(boolean force) {
- if (force) {
- writeInternal();
- return;
- }
- if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
- && !DEBUG_DEXOPT) {
- return;
- }
- if (mBackgroundWriteRunning.compareAndSet(false, true)) {
- new Thread("PackageUsage_DiskWriter") {
- @Override
- public void run() {
- try {
- writeInternal();
- } finally {
- mBackgroundWriteRunning.set(false);
- }
- }
- }.start();
- }
- }
-
- private void writeInternal() {
- synchronized (mPackages) {
- synchronized (mFileLock) {
- AtomicFile file = getFile();
- FileOutputStream f = null;
- try {
- f = file.startWrite();
- BufferedOutputStream out = new BufferedOutputStream(f);
- FileUtils.setPermissions(file.getBaseFile().getPath(),
- 0640, SYSTEM_UID, PACKAGE_INFO_GID);
- StringBuilder sb = new StringBuilder();
-
- sb.append(USAGE_FILE_MAGIC_VERSION_1);
- sb.append('\n');
- out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
-
- for (PackageParser.Package pkg : mPackages.values()) {
- if (pkg.getLatestPackageUseTimeInMills() == 0L) {
- continue;
- }
- sb.setLength(0);
- sb.append(pkg.packageName);
- for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) {
- sb.append(' ');
- sb.append(usageTimeInMillis);
- }
- sb.append('\n');
- out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
- }
- out.flush();
- file.finishWrite(f);
- } catch (IOException e) {
- if (f != null) {
- file.failWrite(f);
- }
- Log.e(TAG, "Failed to write package usage times", e);
- }
- }
- }
- mLastWritten.set(SystemClock.elapsedRealtime());
- }
-
- void readLP() {
- synchronized (mFileLock) {
- AtomicFile file = getFile();
- BufferedInputStream in = null;
- try {
- in = new BufferedInputStream(file.openRead());
- StringBuffer sb = new StringBuffer();
-
- String firstLine = readLine(in, sb);
- if (firstLine == null) {
- // Empty file. Do nothing.
- } else if (USAGE_FILE_MAGIC_VERSION_1.equals(firstLine)) {
- readVersion1LP(in, sb);
- } else {
- readVersion0LP(in, sb, firstLine);
- }
- } catch (FileNotFoundException expected) {
- mIsHistoricalPackageUsageAvailable = false;
- } catch (IOException e) {
- Log.w(TAG, "Failed to read package usage times", e);
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
- mLastWritten.set(SystemClock.elapsedRealtime());
- }
-
- private void readVersion0LP(InputStream in, StringBuffer sb, String firstLine)
- throws IOException {
- // Initial version of the file had no version number and stored one
- // package-timestamp pair per line.
- // Note that the first line has already been read from the InputStream.
- for (String line = firstLine; line != null; line = readLine(in, sb)) {
- String[] tokens = line.split(" ");
- if (tokens.length != 2) {
- throw new IOException("Failed to parse " + line +
- " as package-timestamp pair.");
- }
-
- String packageName = tokens[0];
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- continue;
- }
-
- long timestamp = parseAsLong(tokens[1]);
- for (int reason = 0;
- reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
- reason++) {
- pkg.mLastPackageUsageTimeInMills[reason] = timestamp;
- }
- }
- }
-
- private void readVersion1LP(InputStream in, StringBuffer sb) throws IOException {
- // Version 1 of the file started with the corresponding version
- // number and then stored a package name and eight timestamps per line.
- String line;
- while ((line = readLine(in, sb)) != null) {
- String[] tokens = line.split(" ");
- if (tokens.length != PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT + 1) {
- throw new IOException("Failed to parse " + line + " as a timestamp array.");
- }
-
- String packageName = tokens[0];
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- continue;
- }
-
- for (int reason = 0;
- reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
- reason++) {
- pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]);
- }
- }
- }
-
- private long parseAsLong(String token) throws IOException {
- try {
- return Long.parseLong(token);
- } catch (NumberFormatException e) {
- throw new IOException("Failed to parse " + token + " as a long.", e);
- }
- }
-
- private String readLine(InputStream in, StringBuffer sb) throws IOException {
- return readToken(in, sb, '\n');
- }
-
- private String readToken(InputStream in, StringBuffer sb, char endOfToken)
- throws IOException {
- sb.setLength(0);
- while (true) {
- int ch = in.read();
- if (ch == -1) {
- if (sb.length() == 0) {
- return null;
- }
- throw new IOException("Unexpected EOF");
- }
- if (ch == endOfToken) {
- return sb.toString();
- }
- sb.append((char)ch);
- }
- }
-
- private AtomicFile getFile() {
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- File fname = new File(systemDir, "package-usage.list");
- return new AtomicFile(fname);
- }
-
- private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
- private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
- }
+ private final CompilerStats mCompilerStats = new CompilerStats();
class PackageHandler extends Handler {
private boolean mBound = false;
@@ -2709,7 +2506,8 @@
// Now that we know all the packages we are keeping,
// read and update their last usage times.
- mPackageUsage.readLP();
+ mPackageUsage.read(mPackages);
+ mCompilerStats.read();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
@@ -2801,7 +2599,7 @@
}
}
- int[] stats = performDexOpt(coreApps, false,
+ int[] stats = performDexOptUpgrade(coreApps, false,
getCompilerFilterForReason(REASON_CORE_APP));
final int elapsedTimeSeconds =
@@ -7325,7 +7123,7 @@
}
final long startTime = System.nanoTime();
- final int[] stats = performDexOpt(pkgs, mIsPreNUpgrade /* showDialog */,
+ final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT));
final int elapsedTimeSeconds =
@@ -7344,7 +7142,7 @@
* which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
* and {@code numberOfPackagesFailed}.
*/
- private int[] performDexOpt(List<PackageParser.Package> pkgs, boolean showDialog,
+ private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
String compilerFilter) {
int numberOfPackagesVisited = 0;
@@ -7378,6 +7176,19 @@
}
}
+ // If the OTA updates a system app which was previously preopted to a non-preopted state
+ // the app might end up being verified at runtime. That's because by default the apps
+ // are verify-profile but for preopted apps there's no profile.
+ // Do a hacky check to ensure that if we have no profiles (a reasonable indication
+ // that before the OTA the app was preopted) the app gets compiled with a non-profile
+ // filter (by default interpret-only).
+ // Note that at this stage unused apps are already filtered.
+ if (isSystemApp(pkg) &&
+ DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
+ !Environment.getReferenceProfile(pkg.packageName).exists()) {
+ compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
+ }
+
// checkProfiles is false to avoid merging profiles during boot which
// might interfere with background compilation (b/28612421).
// Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
@@ -7464,7 +7275,8 @@
// Package could not be found. Report failure.
return PackageDexOptimizer.DEX_OPT_FAILED;
}
- mPackageUsage.write(false);
+ mPackageUsage.maybeWriteAsync(mPackages);
+ mCompilerStats.maybeWriteAsync();
}
long callingId = Binder.clearCallingIdentity();
try {
@@ -7509,11 +7321,12 @@
// Currently this will do a full compilation of the library by default.
pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
false /* checkProfiles */,
- getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY));
+ getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY),
+ getOrCreateCompilerPackageStats(depPackage));
}
}
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
- targetCompilerFilter);
+ targetCompilerFilter, getOrCreateCompilerPackageStats(p));
}
Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
@@ -7567,7 +7380,8 @@
}
public void shutdown() {
- mPackageUsage.write(true);
+ mPackageUsage.writeNow(mPackages);
+ mCompilerStats.writeNow();
}
@Override
@@ -11439,9 +11253,6 @@
} else {
resolvedUserIds = userIds;
}
- final ShortcutServiceInternal shortcutService =
- LocalServices.getService(ShortcutServiceInternal.class);
-
for (int id : resolvedUserIds) {
final Intent intent = new Intent(action,
pkg != null ? Uri.fromParts("package", pkg, null) : null);
@@ -11466,10 +11277,6 @@
+ intent.toShortString(false, true, false, false)
+ " " + intent.getExtras(), here);
}
- // TODO b/29385425 Consider making lifecycle callbacks for this.
- if (shortcutService != null) {
- shortcutService.onPackageBroadcast(intent);
- }
am.broadcastIntent(null, intent, null, finishedReceiver,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
null, finishedReceiver != null, false, id);
@@ -11704,12 +11511,18 @@
if (pkgSetting == null) {
return false;
}
+ // Do not allow "android" is being disabled
+ if ("android".equals(packageName)) {
+ Slog.w(TAG, "Cannot hide package: android");
+ return false;
+ }
// Only allow protected packages to hide themselves.
if (hidden && !UserHandle.isSameApp(uid, pkgSetting.appId)
&& mProtectedPackages.isPackageStateProtected(userId, packageName)) {
Slog.w(TAG, "Not hiding protected package: " + packageName);
return false;
}
+
if (pkgSetting.getHidden(userId) != hidden) {
pkgSetting.setHidden(hidden, userId);
mSettings.writePackageRestrictionsLPr(userId);
@@ -15220,7 +15033,8 @@
// Also, don't fail application installs if the dexopt step fails.
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */, false /* checkProfiles */,
- getCompilerFilterForReason(REASON_INSTALL));
+ getCompilerFilterForReason(REASON_INSTALL),
+ getOrCreateCompilerPackageStats(pkg));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Notify BackgroundDexOptService that the package has been changed.
@@ -16880,9 +16694,28 @@
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
+ postPreferredActivityChangedBroadcast(userId);
}
}
+ private void postPreferredActivityChangedBroadcast(int userId) {
+ mHandler.post(() -> {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ if (am == null) {
+ return;
+ }
+
+ final Intent intent = new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ try {
+ am.broadcastIntent(null, intent, null, null,
+ 0, null, null, null, android.app.AppOpsManager.OP_NONE,
+ null, false, false, userId);
+ } catch (RemoteException e) {
+ }
+ });
+ }
+
@Override
public void replacePreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
@@ -17034,6 +16867,9 @@
changed = true;
}
}
+ if (changed) {
+ postPreferredActivityChangedBroadcast(userId);
+ }
return changed;
}
@@ -17147,6 +16983,7 @@
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
new PersistentPreferredActivity(filter, activity));
scheduleWritePackageRestrictionsLocked(userId);
+ postPreferredActivityChangedBroadcast(userId);
}
}
@@ -17189,6 +17026,7 @@
if (changed) {
scheduleWritePackageRestrictionsLocked(userId);
+ postPreferredActivityChangedBroadcast(userId);
}
}
}
@@ -18181,6 +18019,7 @@
public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
public static final int DUMP_FROZEN = 1 << 19;
public static final int DUMP_DEXOPT = 1 << 20;
+ public static final int DUMP_COMPILER_STATS = 1 << 21;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
@@ -18298,6 +18137,7 @@
pw.println(" installs: details about install sessions");
pw.println(" check-permission <permission> <package> [<user>]: does pkg hold perm?");
pw.println(" dexopt: dump dexopt state");
+ pw.println(" compiler-stats: dump compiler statistics");
pw.println(" <package.name>: info about given package");
return;
} else if ("--checkin".equals(opt)) {
@@ -18419,6 +18259,8 @@
dumpState.setDump(DumpState.DUMP_FROZEN);
} else if ("dexopt".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_DEXOPT);
+ } else if ("compiler-stats".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
} else if ("write".equals(cmd)) {
synchronized (mPackages) {
mSettings.writeLPr();
@@ -18781,6 +18623,11 @@
dumpDexoptStateLPr(pw, packageName);
}
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ dumpCompilerStatsLPr(pw, packageName);
+ }
+
if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -18845,6 +18692,38 @@
}
}
+ private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Compiler stats:");
+ ipw.increaseIndent();
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
+ } else {
+ packages = mPackages.values();
+ }
+
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
+
+ CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+ if (stats == null) {
+ ipw.println("(No recorded stats)");
+ } else {
+ stats.dump(ipw);
+ }
+ ipw.decreaseIndent();
+ }
+ }
+
private String dumpDomainString(String packageName) {
List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
.getList();
@@ -20443,12 +20322,7 @@
}
}
- void onBeforeUserStartUninitialized(final int userId) {
- synchronized (mPackages) {
- if (mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
- return;
- }
- }
+ void onNewUserCreated(final int userId) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
// If permission review for legacy apps is required, we represent
// dagerous permissions for such apps as always granted runtime
@@ -21011,4 +20885,20 @@
msg.setData(data);
mProcessLoggingHandler.sendMessage(msg);
}
+
+ public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
+ return mCompilerStats.getPackageStats(pkgName);
+ }
+
+ public CompilerStats.PackageStats getOrCreateCompilerPackageStats(PackageParser.Package pkg) {
+ return getOrCreateCompilerPackageStats(pkg.packageName);
+ }
+
+ public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) {
+ return mCompilerStats.getOrCreatePackageStats(pkgName);
+ }
+
+ public void deleteCompilerPackageStats(String pkgName) {
+ mCompilerStats.deletePackageStats(pkgName);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java
new file mode 100644
index 0000000..ac1f739
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageUsage.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
+
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.FileUtils;
+import android.util.AtomicFile;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> {
+
+ private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
+ private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
+
+ private boolean mIsHistoricalPackageUsageAvailable = true;
+
+ PackageUsage() {
+ super("package-usage.list", "PackageUsage_DiskWriter", /* lock */ true);
+ }
+
+ boolean isHistoricalPackageUsageAvailable() {
+ return mIsHistoricalPackageUsageAvailable;
+ }
+
+ @Override
+ protected void writeInternal(Map<String, PackageParser.Package> packages) {
+ AtomicFile file = getFile();
+ FileOutputStream f = null;
+ try {
+ f = file.startWrite();
+ BufferedOutputStream out = new BufferedOutputStream(f);
+ FileUtils.setPermissions(file.getBaseFile().getPath(),
+ 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(USAGE_FILE_MAGIC_VERSION_1);
+ sb.append('\n');
+ out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+
+ for (PackageParser.Package pkg : packages.values()) {
+ if (pkg.getLatestPackageUseTimeInMills() == 0L) {
+ continue;
+ }
+ sb.setLength(0);
+ sb.append(pkg.packageName);
+ for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) {
+ sb.append(' ');
+ sb.append(usageTimeInMillis);
+ }
+ sb.append('\n');
+ out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+ }
+ out.flush();
+ file.finishWrite(f);
+ } catch (IOException e) {
+ if (f != null) {
+ file.failWrite(f);
+ }
+ Log.e(PackageManagerService.TAG, "Failed to write package usage times", e);
+ }
+ }
+
+ @Override
+ protected void readInternal(Map<String, PackageParser.Package> packages) {
+ AtomicFile file = getFile();
+ BufferedInputStream in = null;
+ try {
+ in = new BufferedInputStream(file.openRead());
+ StringBuffer sb = new StringBuffer();
+
+ String firstLine = readLine(in, sb);
+ if (firstLine == null) {
+ // Empty file. Do nothing.
+ } else if (USAGE_FILE_MAGIC_VERSION_1.equals(firstLine)) {
+ readVersion1LP(packages, in, sb);
+ } else {
+ readVersion0LP(packages, in, sb, firstLine);
+ }
+ } catch (FileNotFoundException expected) {
+ mIsHistoricalPackageUsageAvailable = false;
+ } catch (IOException e) {
+ Log.w(PackageManagerService.TAG, "Failed to read package usage times", e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ private void readVersion0LP(Map<String, PackageParser.Package> packages, InputStream in,
+ StringBuffer sb, String firstLine)
+ throws IOException {
+ // Initial version of the file had no version number and stored one
+ // package-timestamp pair per line.
+ // Note that the first line has already been read from the InputStream.
+ for (String line = firstLine; line != null; line = readLine(in, sb)) {
+ String[] tokens = line.split(" ");
+ if (tokens.length != 2) {
+ throw new IOException("Failed to parse " + line +
+ " as package-timestamp pair.");
+ }
+
+ String packageName = tokens[0];
+ PackageParser.Package pkg = packages.get(packageName);
+ if (pkg == null) {
+ continue;
+ }
+
+ long timestamp = parseAsLong(tokens[1]);
+ for (int reason = 0;
+ reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
+ reason++) {
+ pkg.mLastPackageUsageTimeInMills[reason] = timestamp;
+ }
+ }
+ }
+
+ private void readVersion1LP(Map<String, PackageParser.Package> packages, InputStream in,
+ StringBuffer sb) throws IOException {
+ // Version 1 of the file started with the corresponding version
+ // number and then stored a package name and eight timestamps per line.
+ String line;
+ while ((line = readLine(in, sb)) != null) {
+ String[] tokens = line.split(" ");
+ if (tokens.length != PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT + 1) {
+ throw new IOException("Failed to parse " + line + " as a timestamp array.");
+ }
+
+ String packageName = tokens[0];
+ PackageParser.Package pkg = packages.get(packageName);
+ if (pkg == null) {
+ continue;
+ }
+
+ for (int reason = 0;
+ reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
+ reason++) {
+ pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]);
+ }
+ }
+ }
+
+ private long parseAsLong(String token) throws IOException {
+ try {
+ return Long.parseLong(token);
+ } catch (NumberFormatException e) {
+ throw new IOException("Failed to parse " + token + " as a long.", e);
+ }
+ }
+
+ private String readLine(InputStream in, StringBuffer sb) throws IOException {
+ return readToken(in, sb, '\n');
+ }
+
+ private String readToken(InputStream in, StringBuffer sb, char endOfToken)
+ throws IOException {
+ sb.setLength(0);
+ while (true) {
+ int ch = in.read();
+ if (ch == -1) {
+ if (sb.length() == 0) {
+ return null;
+ }
+ throw new IOException("Unexpected EOF");
+ }
+ if (ch == endOfToken) {
+ return sb.toString();
+ }
+ sb.append((char)ch);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 1a4e4e0..3c18198 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -34,6 +34,7 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.ShortcutService.ShortcutOperation;
+import com.android.server.pm.ShortcutService.Stats;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -437,8 +438,6 @@
* locale changes.
*/
public int getApiCallCount() {
- mShortcutUser.resetThrottlingIfNeeded();
-
final ShortcutService s = mShortcutUser.mService;
// Reset the counter if:
@@ -598,7 +597,37 @@
}
/**
- * Called when the package is updated or added.
+ * @return false if any of the target activities are no longer enabled.
+ */
+ private boolean areAllActivitiesStillEnabled() {
+ if (mShortcuts.size() == 0) {
+ return true;
+ }
+ final ShortcutService s = mShortcutUser.mService;
+
+ // Normally the number of target activities is 1 or so, so no need to use a complex
+ // structure like a set.
+ final ArrayList<ComponentName> checked = new ArrayList<>(4);
+
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = mShortcuts.valueAt(i);
+ final ComponentName activity = si.getActivity();
+
+ if (checked.contains(activity)) {
+ continue; // Already checked.
+ }
+ checked.add(activity);
+
+ if (!s.injectIsActivityEnabledAndExported(activity, getOwnerUserId())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Called when the package may be added or updated, or its activities may be disabled, and
+ * if so, rescan the package and do the necessary stuff.
*
* Add case:
* - Publish manifest shortcuts.
@@ -606,23 +635,35 @@
* Update case:
* - Re-publish manifest shortcuts.
* - If there are shortcuts with resources (icons or strings), update their timestamps.
+ * - Disable shortcuts whose target activities are disabled.
*
* @return TRUE if any shortcuts have been changed.
*/
- public boolean handlePackageAddedOrUpdated(boolean isNewApp, boolean forceRescan) {
- final PackageInfo pi = mShortcutUser.mService.getPackageInfo(
- getPackageName(), getPackageUserId());
- if (pi == null) {
- return false; // Shouldn't happen.
- }
+ public boolean rescanPackageIfNeeded(boolean isNewApp, boolean forceRescan) {
+ final ShortcutService s = mShortcutUser.mService;
+ final long start = s.injectElapsedRealtime();
- if (!isNewApp && !forceRescan) {
- // Make sure the version code or last update time has changed.
- // Otherwise, nothing to do.
- if (getPackageInfo().getVersionCode() >= pi.versionCode
- && getPackageInfo().getLastUpdateTime() >= pi.lastUpdateTime) {
- return false;
+ final PackageInfo pi;
+ try {
+ pi = mShortcutUser.mService.getPackageInfo(
+ getPackageName(), getPackageUserId());
+ if (pi == null) {
+ return false; // Shouldn't happen.
}
+
+ if (!isNewApp && !forceRescan) {
+ // Return if the package hasn't changed, ie:
+ // - version code hasn't change
+ // - lastUpdateTime hasn't change
+ // - all target activities are still enabled.
+ if ((getPackageInfo().getVersionCode() >= pi.versionCode)
+ && (getPackageInfo().getLastUpdateTime() >= pi.lastUpdateTime)
+ && areAllActivitiesStillEnabled()) {
+ return false;
+ }
+ }
+ } finally {
+ s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start);
}
// Now prepare to publish manifest shortcuts.
@@ -654,8 +695,6 @@
getPackageInfo().updateVersionInfo(pi);
- final ShortcutService s = mShortcutUser.mService;
-
boolean changed = false;
// For existing shortcuts, update timestamps if they have any resources.
@@ -1001,7 +1040,7 @@
}
}
if (changed) {
- s.scheduleSaveUser(getPackageUserId());
+ s.packageShortcutsChanged(getPackageName(), getPackageUserId());
}
}
@@ -1185,8 +1224,8 @@
private static void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup)
throws IOException, XmlPullParserException {
if (forBackup) {
- if (!si.isPinned()) {
- return; // Backup only pinned icons.
+ if (!(si.isPinned() && si.isEnabled())) {
+ return; // We only backup pinned shortcuts that are enabled.
}
}
out.startTag(null, TAG_SHORTCUT);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 757dd19..26b52e9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -48,6 +48,10 @@
mPackageInfo = Preconditions.checkNotNull(packageInfo);
}
+ public ShortcutUser getUser() {
+ return mShortcutUser;
+ }
+
/**
* ID of the user who actually has this package running on. For {@link ShortcutPackage},
* this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index 0762c0b..3f302d6 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -29,6 +29,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
+import android.util.TypedValue;
import android.util.Xml;
import com.android.internal.R;
@@ -260,7 +261,12 @@
final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs,
R.styleable.ShortcutCategories);
try {
- return sa.getString(R.styleable.ShortcutCategories_name);
+ if (sa.getType(R.styleable.ShortcutCategories_name) == TypedValue.TYPE_STRING) {
+ return sa.getNonResourceString(R.styleable.ShortcutCategories_name);
+ } else {
+ Log.w(TAG, "android:name for shortcut category must be string literal.");
+ return null;
+ }
} finally {
sa.recycle();
}
@@ -272,7 +278,11 @@
final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs,
R.styleable.Shortcut);
try {
- final String id = sa.getString(R.styleable.Shortcut_shortcutId);
+ if (sa.getType(R.styleable.Shortcut_shortcutId) != TypedValue.TYPE_STRING) {
+ Log.w(TAG, "android:shortcutId must be string literal. activity=" + activity);
+ return null;
+ }
+ final String id = sa.getNonResourceString(R.styleable.Shortcut_shortcutId);
final boolean enabled = sa.getBoolean(R.styleable.Shortcut_enabled, true);
final int iconResId = sa.getResourceId(R.styleable.Shortcut_icon, 0);
final int titleResId = sa.getResourceId(R.styleable.Shortcut_shortcutShortLabel, 0);
@@ -281,11 +291,11 @@
R.styleable.Shortcut_shortcutDisabledMessage, 0);
if (TextUtils.isEmpty(id)) {
- Slog.w(TAG, "Shortcut ID must be provided. activity=" + activity);
+ Log.w(TAG, "android:shortcutId must be provided. activity=" + activity);
return null;
}
if (titleResId == 0) {
- Slog.w(TAG, "Shortcut title must be provided. activity=" + activity);
+ Log.w(TAG, "android:shortcutShortLabel must be provided. activity=" + activity);
return null;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPendingTasks.java b/services/core/java/com/android/server/pm/ShortcutPendingTasks.java
deleted file mode 100644
index a5ace56..0000000
--- a/services/core/java/com/android/server/pm/ShortcutPendingTasks.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.pm;
-
-import android.annotation.NonNull;
-import android.util.Slog;
-
-import java.io.PrintWriter;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.logging.Handler;
-
-/**
- * Used by {@link ShortcutService} to register tasks to be executed on Handler and also wait for
- * all pending tasks.
- *
- * Tasks can be registered with {@link #addTask(Runnable)}. Call {@link #waitOnAllTasks()} to wait
- * on all tasks that have been registered.
- *
- * In order to avoid deadlocks, {@link #waitOnAllTasks} MUST NOT be called with any lock held, nor
- * on the handler thread. These conditions are checked by {@link #mWaitThreadChecker} and wtf'ed.
- *
- * During unit tests, we can't run tasks asynchronously, so we just run Runnables synchronously,
- * which also means the "is lock held" check doesn't work properly during unit tests (e.g. normally
- * when a Runnable is executed on a Handler, the thread doesn't hold any lock, but during the tests
- * we just run a Runnable on the thread that registers it, so the thread may or may not hold locks.)
- * So unfortunately we have to disable {@link #mWaitThreadChecker} during unit tests.
- *
- * Because of the complications like those, this class should be used only for specific purposes:
- * - {@link #addTask(Runnable)} should only be used to register tasks on callbacks from lower level
- * services like the package manager or the activity manager.
- *
- * - {@link #waitOnAllTasks} should only be called at the entry point of RPC calls (or the test only
- * accessors}.
- */
-public class ShortcutPendingTasks {
- private static final String TAG = "ShortcutPendingTasks";
-
- private static final boolean DEBUG = false || ShortcutService.DEBUG; // DO NOT SUBMIT WITH TRUE.
-
- private final Consumer<Runnable> mRunner;
-
- private final BooleanSupplier mWaitThreadChecker;
-
- private final Consumer<Throwable> mExceptionHandler;
-
- /** # of tasks in the queue, including the running one. */
- private final AtomicInteger mRunningTaskCount = new AtomicInteger();
-
- /** For dumpsys */
- private final AtomicLong mLastTaskStartTime = new AtomicLong();
-
- /**
- * Constructor. In order to allow injection during unit tests, it doesn't take a
- * {@link Handler} directly, and instead takes {@code runner} which will post an argument
- * to a handler.
- */
- public ShortcutPendingTasks(Consumer<Runnable> runner, BooleanSupplier waitThreadChecker,
- Consumer<Throwable> exceptionHandler) {
- mRunner = runner;
- mWaitThreadChecker = waitThreadChecker;
- mExceptionHandler = exceptionHandler;
- }
-
- private static void dlog(String message) {
- if (DEBUG) {
- Slog.d(TAG, message);
- }
- }
-
- /**
- * Block until all tasks that are already queued finish. DO NOT call it while holding any lock
- * or on the handler thread.
- */
- public boolean waitOnAllTasks() {
- dlog("waitOnAllTasks: enter");
- try {
- // Make sure it's not holding the lock.
- if (!mWaitThreadChecker.getAsBoolean()) {
- return false;
- }
-
- // Optimize for the no-task case.
- if (mRunningTaskCount.get() == 0) {
- return true;
- }
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- addTask(latch::countDown);
-
- for (; ; ) {
- try {
- if (latch.await(1, TimeUnit.SECONDS)) {
- return true;
- }
- dlog("waitOnAllTasks: Task(s) still running...");
- } catch (InterruptedException ignore) {
- }
- }
- } finally {
- dlog("waitOnAllTasks: exit");
- }
- }
-
- /**
- * Add a new task. This operation is lock-free.
- */
- public void addTask(Runnable task) {
- mRunningTaskCount.incrementAndGet();
- mLastTaskStartTime.set(System.currentTimeMillis());
-
- dlog("Task registered");
-
- mRunner.accept(() -> {
- try {
- dlog("Task started");
-
- task.run();
- } catch (Throwable th) {
- mExceptionHandler.accept(th);
- } finally {
- dlog("Task finished");
- mRunningTaskCount.decrementAndGet();
- }
- });
- }
-
- public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
- pw.print(prefix);
- pw.print("Pending tasks: # running tasks: ");
- pw.println(mRunningTaskCount.get());
-
- pw.print(prefix);
- pw.print(" Last task started time: ");
- final long lastStarted = mLastTaskStartTime.get();
- pw.print(" [");
- pw.print(lastStarted);
- pw.print("] ");
- pw.println(ShortcutService.formatTime(lastStarted));
- }
-}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a9018b3..10f1b4b 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -24,9 +24,11 @@
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -54,6 +56,7 @@
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.LocaleList;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -82,6 +85,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -116,7 +120,6 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -176,7 +179,6 @@
private static final String TAG_ROOT = "root";
private static final String TAG_LAST_RESET_TIME = "last_reset_time";
- private static final String TAG_LOCALE_CHANGE_SEQUENCE_NUMBER = "locale_seq_no";
private static final String ATTR_VALUE = "value";
@@ -289,20 +291,8 @@
@GuardedBy("mLock")
private List<Integer> mDirtyUserIds = new ArrayList<>();
- /**
- * A counter that increments every time the system locale changes. We keep track of it to
- * reset
- * throttling counters on the first call from each package after the last locale change.
- *
- * We need this mechanism because we can't do much in the locale change callback, which is
- * {@link ShortcutServiceInternal#onSystemLocaleChangedNoLock()}.
- */
- private final AtomicLong mLocaleChangeSequenceNumber = new AtomicLong();
-
private final AtomicBoolean mBootCompleted = new AtomicBoolean();
- private final ShortcutPendingTasks mPendingTasks;
-
private static final int PACKAGE_MATCH_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -325,8 +315,9 @@
int GET_LAUNCHER_ACTIVITY = 11;
int CHECK_LAUNCHER_ACTIVITY = 12;
int IS_ACTIVITY_ENABLED = 13;
+ int PACKAGE_UPDATE_CHECK = 14;
- int COUNT = IS_ACTIVITY_ENABLED + 1;
+ int COUNT = PACKAGE_UPDATE_CHECK + 1;
}
final Object mStatLock = new Object();
@@ -376,41 +367,40 @@
mUsageStatsManagerInternal = Preconditions.checkNotNull(
LocalServices.getService(UsageStatsManagerInternal.class));
- mPendingTasks = new ShortcutPendingTasks(
- this::injectPostToHandler,
- this::injectCheckPendingTaskWaitThread,
- throwable -> wtf(throwable.getMessage(), throwable));
-
if (onlyForPackageManagerApis) {
return; // Don't do anything further. For unit tests only.
}
+ // Register receivers.
+
+ // We need to set a priority, so let's just not use PackageMonitor for now.
+ // TODO Refactor PackageMonitor to support priorities.
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ packageFilter.addDataScheme("package");
+ packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
+ packageFilter, null, mHandler);
+
+ final IntentFilter preferedActivityFilter = new IntentFilter();
+ preferedActivityFilter.addAction(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
+ preferedActivityFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
+ preferedActivityFilter, null, mHandler);
+
+ final IntentFilter localeFilter = new IntentFilter();
+ localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ localeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL,
+ localeFilter, null, mHandler);
+
injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
| ActivityManager.UID_OBSERVER_GONE);
}
- /**
- * Check whether {@link ShortcutPendingTasks#waitOnAllTasks()} can be called on the current
- * thread.
- *
- * During unit tests, all tasks are executed synchronously which makes the lock held check would
- * misfire, so we override this method to always return true.
- */
- @VisibleForTesting
- boolean injectCheckPendingTaskWaitThread() {
- // We shouldn't wait while holding mLock. We should never do this so wtf().
- if (Thread.holdsLock(mLock)) {
- wtf("waitOnAllTasks() called while holding the lock");
- return false;
- }
- // This shouldn't be called on the handler thread either.
- if (Thread.currentThread() == mHandler.getLooper().getThread()) {
- wtf("waitOnAllTasks() called on handler thread");
- return false;
- }
- return true;
- }
-
void logDurationStat(int statId, long start) {
synchronized (mStatLock) {
mCountStats[statId]++;
@@ -418,8 +408,9 @@
}
}
- public long getLocaleChangeSequenceNumber() {
- return mLocaleChangeSequenceNumber.get();
+ public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
+ // TODO This should get the per-user locale. b/30123329 b/30119489
+ return LocaleList.getDefault().toLanguageTags();
}
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@@ -528,8 +519,11 @@
Slog.d(TAG, "handleUnlockUser: user=" + userId);
}
synchronized (mLock) {
- // Preload
- getUserShortcutsLocked(userId);
+ // Preload the user's shortcuts.
+ // Also see if the locale has changed.
+ // Note as of nyc, the locale is per-user, so the locale shouldn't change
+ // when the user is locked. However due to b/30119489 it still happens.
+ getUserShortcutsLocked(userId).detectLocaleChange();
checkPackageChanges(userId);
}
@@ -775,8 +769,6 @@
// Body.
writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
- writeTagValue(out, TAG_LOCALE_CHANGE_SEQUENCE_NUMBER,
- mLocaleChangeSequenceNumber.get());
// Epilogue.
out.endTag(null, TAG_ROOT);
@@ -821,9 +813,6 @@
case TAG_LAST_RESET_TIME:
mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
break;
- case TAG_LOCALE_CHANGE_SEQUENCE_NUMBER:
- mLocaleChangeSequenceNumber.set(parseLongAttribute(parser, ATTR_VALUE));
- break;
default:
Slog.e(TAG, "Invalid tag: " + tag);
break;
@@ -1468,6 +1457,10 @@
shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
"Cannot publish shortcut: activity " + shortcut.getActivity() + " does not"
+ " belong to package " + shortcut.getPackage());
+ Preconditions.checkState(
+ injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
+ "Cannot publish shortcut: activity " + shortcut.getActivity() + " is not"
+ + " main activity");
}
if (!forUpdate) {
@@ -1516,13 +1509,12 @@
@UserIdInt int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
final int size = newShortcuts.size();
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
@@ -1567,13 +1559,12 @@
@UserIdInt int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
final int size = newShortcuts.size();
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
@@ -1647,13 +1638,12 @@
@UserIdInt int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
final int size = newShortcuts.size();
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
@@ -1699,10 +1689,9 @@
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
@@ -1728,10 +1717,9 @@
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
@@ -1750,10 +1738,9 @@
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
@@ -1774,10 +1761,10 @@
public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts();
+ final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+ ps.deleteAllDynamicShortcuts();
}
packageShortcutsChanged(packageName, userId);
@@ -1788,9 +1775,6 @@
public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
-
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1802,9 +1786,6 @@
public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
-
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1816,9 +1797,6 @@
public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
-
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1831,7 +1809,9 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
- getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags);
+ final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+ ps.findAll(ret, query, cloneFlags);
return new ParceledListSlice<>(ret);
}
@@ -1848,11 +1828,10 @@
public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
- return mMaxUpdatesPerInterval
- - getPackageShortcutsLocked(packageName, userId).getApiCallCount();
+ final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+ return mMaxUpdatesPerInterval - ps.getApiCallCount();
}
}
@@ -1860,8 +1839,6 @@
public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
return getNextResetTimeLocked();
}
@@ -1880,8 +1857,6 @@
public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
verifyCaller(packageName, userId);
- mPendingTasks.waitOnAllTasks();
-
Preconditions.checkNotNull(shortcutId);
if (DEBUG) {
@@ -1891,6 +1866,8 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+
if (ps.findShortcutById(shortcutId) == null) {
Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
packageName, shortcutId));
@@ -1914,8 +1891,6 @@
public void resetThrottling() {
enforceSystemOrShell();
- mPendingTasks.waitOnAllTasks();
-
resetThrottlingInner(getCallingUserId());
}
@@ -1948,16 +1923,18 @@
if (DEBUG) {
Slog.d(TAG, "onApplicationActive: package=" + packageName + " userid=" + userId);
}
-
- mPendingTasks.waitOnAllTasks();
-
enforceResetThrottlingPermission();
resetPackageThrottling(packageName, userId);
}
// We override this method in unit tests to do a simpler check.
boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
- return hasShortcutHostPermissionInner(callingPackage, userId);
+ final long start = injectElapsedRealtime();
+ try {
+ return hasShortcutHostPermissionInner(callingPackage, userId);
+ } finally {
+ logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
+ }
}
// This method is extracted so we can directly call this method from unit tests,
@@ -1965,15 +1942,22 @@
@VisibleForTesting
boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
synchronized (mLock) {
- final long start = injectElapsedRealtime();
-
final ShortcutUser user = getUserShortcutsLocked(userId);
+ // Always trust the in-memory cache.
+ final ComponentName cached = user.getCachedLauncher();
+ if (cached != null) {
+ if (cached.getPackageName().equals(callingPackage)) {
+ return true;
+ }
+ }
+ // If the cached one doesn't match, then go ahead
+
final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
// Default launcher from package manager.
final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
- final ComponentName defaultLauncher = injectPackageManagerInternal()
+ final ComponentName defaultLauncher = mPackageManagerInternal
.getHomeActivitiesAsUser(allHomeCandidates, userId);
logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
@@ -1984,7 +1968,7 @@
Slog.v(TAG, "Default launcher from PM: " + detected);
}
} else {
- detected = user.getDefaultLauncherComponent();
+ detected = user.getLastKnownLauncher();
if (detected != null) {
if (injectIsActivityEnabledAndExported(detected, userId)) {
@@ -1994,7 +1978,7 @@
} else {
Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
detected = null;
- user.setDefaultLauncherComponent(null);
+ user.clearLauncher();
}
}
}
@@ -2025,13 +2009,13 @@
lastPriority = ri.priority;
}
}
- logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
+ // Update the cache.
+ user.setLauncher(detected);
if (detected != null) {
if (DEBUG) {
Slog.v(TAG, "Detected launcher: " + detected);
}
- user.setDefaultLauncherComponent(detected);
return detected.getPackageName().equals(callingPackage);
} else {
// Default launcher not found.
@@ -2093,7 +2077,7 @@
if (appStillExists && (packageUserId == owningUserId)) {
// This will do the notification and save when needed, so do it after the above
// notifyListeners.
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ true);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
}
if (!wasUserLoaded) {
@@ -2113,14 +2097,6 @@
@Nullable String packageName, @Nullable List<String> shortcutIds,
@Nullable ComponentName componentName,
int queryFlags, int userId) {
-
- // When this method is called from onShortcutChangedInner() in LauncherApps,
- // we're on the handler thread. Do not try to wait on tasks. Not waiting for pending
- // tasks on this specific case should be fine.
- if (Thread.currentThread() != mHandler.getLooper().getThread()) {
- mPendingTasks.waitOnAllTasks();
- }
-
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
final boolean cloneKeyFieldOnly =
((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
@@ -2199,8 +2175,6 @@
Preconditions.checkStringNotEmpty(packageName, "packageName");
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2238,8 +2212,6 @@
Preconditions.checkStringNotEmpty(packageName, "packageName");
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
final ShortcutLauncher launcher =
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
@@ -2260,8 +2232,6 @@
Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2292,8 +2262,6 @@
Preconditions.checkNotNull(packageName, "packageName");
Preconditions.checkNotNull(shortcutId, "shortcutId");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2318,8 +2286,6 @@
Preconditions.checkNotNull(packageName, "packageName");
Preconditions.checkNotNull(shortcutId, "shortcutId");
- mPendingTasks.waitOnAllTasks();
-
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2354,46 +2320,20 @@
@NonNull String callingPackage) {
return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
}
-
- /**
- * Called by AM when the system locale changes *within the AM lock. ABSOLUTELY do not take
- * any locks in this method.
- */
- @Override
- public void onSystemLocaleChangedNoLock() {
- // DO NOT HOLD ANY LOCKS HERE.
-
- // We want to reset throttling for all packages for all users. But we can't just do so
- // here because:
- // - We can't load/save users that are locked.
- // - Even for loaded users, resetting the counters would require us to hold mLock.
- //
- // So we use a "pull" model instead. In here, we just increment the "locale change
- // sequence number". Each ShortcutUser has the "last known locale change sequence".
- //
- // This allows ShortcutUser's to detect the system locale change, so they can reset
- // counters.
-
- // Ignore all callback during system boot.
- if (mBootCompleted.get()) {
- mLocaleChangeSequenceNumber.incrementAndGet();
- if (DEBUG) {
- Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get());
- }
- mPendingTasks.addTask(() -> handleLocaleChanged());
- }
- }
-
- @Override
- public void onPackageBroadcast(Intent intent) {
- if (DEBUG) {
- Slog.d(TAG, "onPackageBroadcast");
- }
- mPendingTasks.addTask(() -> ShortcutService.this.onPackageBroadcast(
- new Intent(intent)));
- }
}
+ final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!mBootCompleted.get()) {
+ return; // Boot not completed, ignore the broadcast.
+ }
+ if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ handleLocaleChanged();
+ }
+ }
+ };
+
void handleLocaleChanged() {
if (DEBUG) {
Slog.d(TAG, "handleLocaleChanged");
@@ -2402,55 +2342,87 @@
final long token = injectClearCallingIdentity();
try {
- forEachLoadedUserLocked(u -> u.forAllPackages(p -> p.resolveResourceStrings()));
+ forEachLoadedUserLocked(user -> user.detectLocaleChange());
} finally {
injectRestoreCallingIdentity(token);
}
}
- private void onPackageBroadcast(Intent intent) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId == UserHandle.USER_NULL) {
- Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
- return;
- }
-
- final String action = intent.getAction();
-
- if (!mUserManager.isUserUnlocked(userId)) {
- if (DEBUG) {
- Slog.d(TAG, "Ignoring package broadcast " + action + " for locked/stopped user "
- + userId);
+ /**
+ * Package event callbacks.
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mPackageMonitor = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
+ return;
}
- return;
- }
- final Uri intentUri = intent.getData();
- final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart() : null;
- if (packageName == null) {
- Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
- return;
- }
+ final String action = intent.getAction();
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ // This is normally called on Handler, so clearCallingIdentity() isn't needed,
+ // but we still check it in unit tests.
+ final long token = injectClearCallingIdentity();
+ try {
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- if (replacing) {
- handlePackageUpdateFinished(packageName, userId);
- } else {
- handlePackageAdded(packageName, userId);
+ if (!mUserManager.isUserUnlocked(userId)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring package broadcast " + action
+ + " for locked/stopped user " + userId);
+ }
+ return;
+ }
+
+ // Whenever we get one of those package broadcasts, or get
+ // ACTION_PREFERRED_ACTIVITY_CHANGED, we purge the default launcher cache.
+ synchronized (mLock) {
+ final ShortcutUser user = getUserShortcutsLocked(userId);
+ user.clearLauncher();
+ }
+ if (Intent.ACTION_PREFERRED_ACTIVITY_CHANGED.equals(action)) {
+ // Nothing farther to do.
+ return;
+ }
+
+ final Uri intentUri = intent.getData();
+ final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
+ : null;
+ if (packageName == null) {
+ Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
+ return;
+ }
+
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+ switch (action) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ if (replacing) {
+ handlePackageUpdateFinished(packageName, userId);
+ } else {
+ handlePackageAdded(packageName, userId);
+ }
+ break;
+ case Intent.ACTION_PACKAGE_REMOVED:
+ if (!replacing) {
+ handlePackageRemoved(packageName, userId);
+ }
+ break;
+ case Intent.ACTION_PACKAGE_CHANGED:
+ handlePackageChanged(packageName, userId);
+
+ break;
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ handlePackageDataCleared(packageName, userId);
+ break;
+ }
+ } finally {
+ injectRestoreCallingIdentity(token);
}
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- if (!replacing) {
- handlePackageRemoved(packageName, userId);
- }
- } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- handlePackageChanged(packageName, userId);
-
- } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
- handlePackageDataCleared(packageName, userId);
}
- }
+ };
/**
* Called when a user is unlocked.
@@ -2499,7 +2471,7 @@
// Then for each installed app, publish manifest shortcuts when needed.
forUpdatedPackages(ownerUserId, user.getLastAppScanTime(), ai -> {
- user.handlePackageAddedOrUpdated(ai.packageName, /* forceRescan=*/ false);
+ user.rescanPackageIfNeeded(ai.packageName, /* forceRescan=*/ false);
});
// Write the time just before the scan, because there may be apps that have just
@@ -2520,7 +2492,7 @@
synchronized (mLock) {
final ShortcutUser user = getUserShortcutsLocked(userId);
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ false);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ false);
}
verifyStates();
}
@@ -2535,7 +2507,7 @@
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
if (isPackageInstalled(packageName, userId)) {
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ false);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ false);
}
}
verifyStates();
@@ -2571,7 +2543,7 @@
synchronized (mLock) {
final ShortcutUser user = getUserShortcutsLocked(packageUserId);
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ true);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
}
verifyStates();
@@ -3047,10 +3019,6 @@
pw.print("] ");
pw.print(formatTime(next));
- pw.print(" Locale change seq#: ");
- pw.print(mLocaleChangeSequenceNumber.get());
- pw.println();
-
pw.print(" Config:");
pw.print(" Max icon dim: ");
pw.println(mMaxIconDimension);
@@ -3086,6 +3054,7 @@
dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
+ dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
}
pw.println();
@@ -3097,9 +3066,6 @@
pw.println(Log.getStackTraceString(mLastWtfStacktrace));
}
- pw.println();
- mPendingTasks.dump(pw, " ");
-
for (int i = 0; i < mUsers.size(); i++) {
pw.println();
mUsers.valueAt(i).dump(pw, " ");
@@ -3148,8 +3114,6 @@
enforceShell();
- mPendingTasks.waitOnAllTasks();
-
final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
resultReceiver.send(status, null);
@@ -3176,6 +3140,10 @@
case "--user":
if (takeUser) {
mUserId = UserHandle.parseUserArg(getNextArgRequired());
+ if (!mUserManager.isUserUnlocked(mUserId)) {
+ throw new CommandException(
+ "User " + mUserId + " is not running or locked");
+ }
break;
}
// fallthrough
@@ -3321,7 +3289,7 @@
private void clearLauncher() {
synchronized (mLock) {
- getUserShortcutsLocked(mUserId).setDefaultLauncherComponent(null);
+ getUserShortcutsLocked(mUserId).forceClearLauncher();
}
}
@@ -3331,7 +3299,7 @@
hasShortcutHostPermissionInner("-", mUserId);
getOutPrintWriter().println("Launcher: "
- + getUserShortcutsLocked(mUserId).getDefaultLauncherComponent());
+ + getUserShortcutsLocked(mUserId).getLastKnownLauncher());
}
}
@@ -3455,11 +3423,6 @@
}
}
- @VisibleForTesting
- PackageManagerInternal injectPackageManagerInternal() {
- return mPackageManagerInternal;
- }
-
File getUserBitmapFilePath(@UserIdInt int userId) {
return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
}
@@ -3501,7 +3464,6 @@
@VisibleForTesting
ShortcutPackage getPackageShortcutForTest(String packageName, int userId) {
- mPendingTasks.waitOnAllTasks();
synchronized (mLock) {
final ShortcutUser user = mUsers.get(userId);
if (user == null) return null;
@@ -3512,12 +3474,8 @@
@VisibleForTesting
ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
- mPendingTasks.waitOnAllTasks();
synchronized (mLock) {
- final ShortcutUser user = mUsers.get(userId);
- if (user == null) return null;
-
- final ShortcutPackage pkg = user.getAllPackagesForTest().get(packageName);
+ final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId);
if (pkg == null) return null;
return pkg.findShortcutById(shortcutId);
@@ -3548,16 +3506,8 @@
}
private void verifyStatesInner() {
- synchronized (this) {
+ synchronized (mLock) {
forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
}
}
-
- ShortcutPendingTasks getPendingTasksForTest() {
- return mPendingTasks;
- }
-
- Object getLockForTest() {
- return mLock;
- }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 7ea89c9..3a43ece 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -19,6 +19,8 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
+import android.content.pm.ShortcutManager;
+import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.Slog;
@@ -51,7 +53,7 @@
private static final String TAG_LAUNCHER = "launcher";
private static final String ATTR_VALUE = "value";
- private static final String ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER = "locale-seq-no";
+ private static final String ATTR_KNOWN_LOCALES = "locales";
private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time";
static final class PackageWithUser {
@@ -101,10 +103,17 @@
private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
- /** Default launcher that can access the launcher apps APIs. */
- private ComponentName mDefaultLauncherComponent;
+ /**
+ * Last known launcher. It's used when the default launcher isn't set in PM -- i.e.
+ * when getHomeActivitiesAsUser() return null. We need it so that in this situation the
+ * previously default launcher can still access shortcuts.
+ */
+ private ComponentName mLastKnownLauncher;
- private long mKnownLocaleChangeSequenceNumber;
+ /** In-memory-cached default launcher. */
+ private ComponentName mCachedLauncher;
+
+ private String mKnownLocales;
private long mLastAppScanTime;
@@ -225,29 +234,62 @@
}
/**
- * Reset all throttling counters for all packages, if there has been a system locale change.
+ * Must be called at any entry points on {@link ShortcutManager} APIs to make sure the
+ * information on the package is up-to-date.
+ *
+ * We use broadcasts to handle locale changes and package changes, but because broadcasts
+ * are asynchronous, there's a chance a publisher calls getXxxShortcuts() after a certain event
+ * (e.g. system locale change) but shortcut manager hasn't finished processing the broadcast.
+ *
+ * So we call this method at all entry points from publishers to make sure we update all
+ * relevant information.
+ *
+ * Similar inconsistencies can happen when the launcher fetches shortcut information, but
+ * that's a less of an issue because for the launcher we report shortcut changes with
+ * callbacks.
*/
- public void resetThrottlingIfNeeded() {
- final long currentNo = mService.getLocaleChangeSequenceNumber();
- if (mKnownLocaleChangeSequenceNumber < currentNo) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "LocaleChange detected for user " + mUserId);
- }
-
- mKnownLocaleChangeSequenceNumber = currentNo;
-
- forAllPackages(p -> p.resetRateLimiting());
-
- mService.scheduleSaveUser(mUserId);
- }
+ public void onCalledByPublisher(@NonNull String packageName) {
+ detectLocaleChange();
+ rescanPackageIfNeeded(packageName, /*forceRescan=*/ false);
}
- public void handlePackageAddedOrUpdated(@NonNull String packageName, boolean forceRescan) {
+ private String getKnownLocales() {
+ if (TextUtils.isEmpty(mKnownLocales)) {
+ mKnownLocales = mService.injectGetLocaleTagsForUser(mUserId);
+ mService.scheduleSaveUser(mUserId);
+ }
+ return mKnownLocales;
+ }
+
+ /**
+ * Check to see if the system locale has changed, and if so, reset throttling
+ * and update resource strings.
+ */
+ public void detectLocaleChange() {
+ final String currentLocales = mService.injectGetLocaleTagsForUser(mUserId);
+ if (getKnownLocales().equals(currentLocales)) {
+ return;
+ }
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, "Locale changed from " + currentLocales + " to " + mKnownLocales
+ + " for user " + mUserId);
+ }
+ mKnownLocales = currentLocales;
+
+ forAllPackages(pkg -> {
+ pkg.resetRateLimiting();
+ pkg.resolveResourceStrings();
+ });
+
+ mService.scheduleSaveUser(mUserId);
+ }
+
+ public void rescanPackageIfNeeded(@NonNull String packageName, boolean forceRescan) {
final boolean isNewApp = !mPackages.containsKey(packageName);
final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
- if (!shortcutPackage.handlePackageAddedOrUpdated(isNewApp, forceRescan)) {
+ if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
if (isNewApp) {
mPackages.remove(packageName);
}
@@ -265,13 +307,11 @@
throws IOException, XmlPullParserException {
out.startTag(null, TAG_ROOT);
- ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER,
- mKnownLocaleChangeSequenceNumber);
+ ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
mLastAppScanTime);
- ShortcutService.writeTagValue(out, TAG_LAUNCHER,
- mDefaultLauncherComponent);
+ ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
// Can't use forEachPackageItem due to the checked exceptions.
{
@@ -307,8 +347,8 @@
boolean fromBackup) throws IOException, XmlPullParserException {
final ShortcutUser ret = new ShortcutUser(s, userId);
- ret.mKnownLocaleChangeSequenceNumber = ShortcutService.parseLongAttribute(parser,
- ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER);
+ ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
+ ATTR_KNOWN_LOCALES);
// If lastAppScanTime is in the future, that means the clock went backwards.
// Just scan all apps again.
@@ -330,7 +370,7 @@
if (depth == outerDepth + 1) {
switch (tag) {
case TAG_LAUNCHER: {
- ret.mDefaultLauncherComponent = ShortcutService.parseComponentNameAttribute(
+ ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
parser, ATTR_VALUE);
continue;
}
@@ -355,18 +395,44 @@
return ret;
}
- public ComponentName getDefaultLauncherComponent() {
- return mDefaultLauncherComponent;
+ public ComponentName getLastKnownLauncher() {
+ return mLastKnownLauncher;
}
- public void setDefaultLauncherComponent(ComponentName launcherComponent) {
- if (Objects.equal(mDefaultLauncherComponent, launcherComponent)) {
+ public void setLauncher(ComponentName launcherComponent) {
+ setLauncher(launcherComponent, /* allowPurgeLastKnown */ false);
+ }
+
+ /** Clears the launcher information without clearing the last known one */
+ public void clearLauncher() {
+ setLauncher(null);
+ }
+
+ /**
+ * Clears the launcher information *with(* clearing the last known one; we do this witl
+ * "cmd shortcut clear-default-launcher".
+ */
+ public void forceClearLauncher() {
+ setLauncher(null, /* allowPurgeLastKnown */ true);
+ }
+
+ private void setLauncher(ComponentName launcherComponent, boolean allowPurgeLastKnown) {
+ mCachedLauncher = launcherComponent; // Always update the in-memory cache.
+
+ if (Objects.equal(mLastKnownLauncher, launcherComponent)) {
return;
}
- mDefaultLauncherComponent = launcherComponent;
+ if (!allowPurgeLastKnown && launcherComponent == null) {
+ return;
+ }
+ mLastKnownLauncher = launcherComponent;
mService.scheduleSaveUser(mUserId);
}
+ public ComponentName getCachedLauncher() {
+ return mCachedLauncher;
+ }
+
public void resetThrottling() {
for (int i = mPackages.size() - 1; i >= 0; i--) {
mPackages.valueAt(i).resetThrottling();
@@ -377,8 +443,8 @@
pw.print(prefix);
pw.print("User: ");
pw.print(mUserId);
- pw.print(" Known locale seq#: ");
- pw.print(mKnownLocaleChangeSequenceNumber);
+ pw.print(" Known locales: ");
+ pw.print(mKnownLocales);
pw.print(" Last app scan: [");
pw.print(mLastAppScanTime);
pw.print("] ");
@@ -388,8 +454,13 @@
prefix += prefix + " ";
pw.print(prefix);
- pw.print("Default launcher: ");
- pw.print(mDefaultLauncherComponent);
+ pw.print("Cached launcher: ");
+ pw.print(mCachedLauncher);
+ pw.println();
+
+ pw.print(prefix);
+ pw.print("Last known launcher: ");
+ pw.print(mLastKnownLauncher);
pw.println();
for (int i = 0; i < mLaunchers.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d750cbf..68ccbdf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1799,6 +1799,18 @@
mUserVersion = USER_VERSION;
Bundle restrictions = new Bundle();
+ try {
+ final String[] defaultFirstUserRestrictions = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_defaultFirstUserRestrictions);
+ for (String userRestriction : defaultFirstUserRestrictions) {
+ if (UserRestrictionsUtils.isValidRestriction(userRestriction)) {
+ restrictions.putBoolean(userRestriction, true);
+ }
+ }
+ } catch (Resources.NotFoundException e) {
+ Log.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e);
+ }
+
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
}
@@ -2304,6 +2316,7 @@
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.append(userId, restrictions);
}
+ mPm.onNewUserCreated(userId);
Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
@@ -2874,10 +2887,6 @@
synchronized (mRestrictionsLock) {
applyUserRestrictionsLR(userId);
}
- UserInfo userInfo = getUserInfoNoChecks(userId);
- if (userInfo != null && !userInfo.isInitialized()) {
- mPm.onBeforeUserStartUninitialized(userId);
- }
}
maybeInitializeDemoMode(userId);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index c082143..0499757 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -104,7 +104,8 @@
UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_DATA_ROAMING,
UserManager.DISALLOW_SET_USER_ICON,
- UserManager.DISALLOW_SET_WALLPAPER
+ UserManager.DISALLOW_SET_WALLPAPER,
+ UserManager.DISALLOW_OEM_UNLOCK
});
/**
@@ -138,7 +139,8 @@
*/
private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet(
UserManager.DISALLOW_RECORD_AUDIO,
- UserManager.DISALLOW_WALLPAPER
+ UserManager.DISALLOW_WALLPAPER,
+ UserManager.DISALLOW_OEM_UNLOCK
);
/**
@@ -426,6 +428,7 @@
newValue ? 1 : 0);
break;
case UserManager.DISALLOW_FACTORY_RESET:
+ case UserManager.DISALLOW_OEM_UNLOCK:
if (newValue) {
PersistentDataBlockManager manager = (PersistentDataBlockManager) context
.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 2e32fe3..c764833 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -134,7 +134,7 @@
}
public void immersiveModeChangedLw(String pkg, boolean isImmersiveMode,
- boolean userSetupComplete) {
+ boolean userSetupComplete, boolean navBarEmpty) {
mHandler.removeMessages(H.SHOW);
if (isImmersiveMode) {
final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
@@ -144,6 +144,7 @@
&& (DEBUG_SHOW_EVERY_TIME || !mConfirmed)
&& userSetupComplete
&& !mVrModeEnabled
+ && !navBarEmpty
&& !UserManager.isDeviceInDemoMode(mContext)) {
mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
}
@@ -152,12 +153,13 @@
}
}
- public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) {
+ public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
+ boolean navBarEmpty) {
if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
// turning the screen back on within the panic threshold
return mClingWindow == null;
}
- if (isScreenOn && inImmersiveMode) {
+ if (isScreenOn && inImmersiveMode && !navBarEmpty) {
// turning the screen off, remember if we were in immersive mode
mPanicTime = time;
} else {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index cefd148..f0b128e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1024,7 +1024,8 @@
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
- SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags));
+ SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
+ isNavBarEmpty(mLastSystemUiFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
}
@@ -7591,7 +7592,7 @@
if (win != null && oldImmersiveMode != newImmersiveMode) {
final String pkg = win.getOwningPackage();
mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
- isUserSetupComplete());
+ isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()));
}
vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
@@ -7650,6 +7651,14 @@
&& canHideNavigationBar();
}
+ private static boolean isNavBarEmpty(int systemUiFlags) {
+ final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
+ | View.STATUS_BAR_DISABLE_BACK
+ | View.STATUS_BAR_DISABLE_RECENT);
+
+ return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
+ }
+
/**
* @return whether the navigation or status bar can be made translucent
*
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index ca92b90..552803f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.KeyEvent;
@@ -942,6 +943,20 @@
+ " token=" + tok.token);
}
pw.println(" mCurrentUserId=" + mCurrentUserId);
+ pw.println(" mIcons=");
+ for (String slot : mIcons.keySet()) {
+ pw.println(" ");
+ pw.print(slot);
+ pw.print(" -> ");
+ final StatusBarIcon icon = mIcons.get(slot);
+ pw.print(icon);
+ if (!TextUtils.isEmpty(icon.contentDescription)) {
+ pw.print(" \"");
+ pw.print(icon.contentDescription);
+ pw.print("\"");
+ }
+ pw.println();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 77e8b1f..40ee5d8 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -246,7 +246,9 @@
Intent queryIntent = new Intent(serviceName);
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
queryIntent,
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA |
+ PackageManager.MATCH_DIRECT_BOOT_AWARE |
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
if (installedServices != null) {
for (int i = 0, count = installedServices.size(); i < count; i++) {
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 5fefd4c..7d20931 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -403,107 +403,6 @@
publishLocalService(VrManagerInternal.class, new LocalService());
publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder());
-
- // If there are no VR packages installed on the device, then disable VR
- // components, otherwise, enable them.
- setEnabledStatusOfVrComponents();
- }
-
- private void setEnabledStatusOfVrComponents() {
- ArraySet<ComponentName> vrComponents = SystemConfig.getInstance().getDefaultVrComponents();
- if (vrComponents == null) {
- return;
- }
-
- // We only want to enable VR components if there is a VR package installed on the device.
- // The VR components themselves do not quality as a VR package, so exclude them.
- ArraySet<String> vrComponentPackageNames = new ArraySet<>();
- for (ComponentName componentName : vrComponents) {
- vrComponentPackageNames.add(componentName.getPackageName());
- }
-
- // Check to see if there are any packages on the device, other than the VR component
- // packages.
- PackageManager pm = mContext.getPackageManager();
- List<PackageInfo> packageInfos = pm.getInstalledPackages(
- PackageManager.GET_CONFIGURATIONS);
- boolean vrModeIsUsed = false;
- for (PackageInfo packageInfo : packageInfos) {
- if (packageInfo != null && packageInfo.packageName != null &&
- pm.getApplicationEnabledSetting(packageInfo.packageName) ==
- PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
- vrModeIsUsed = enableVrComponentsIfVrModeUsed(pm, packageInfo,
- vrComponentPackageNames, vrComponents);
- if (vrModeIsUsed) {
- break;
- }
- }
- }
-
- if (!vrModeIsUsed) {
- Slog.i(TAG, "No VR packages found, disabling VR components");
- setVrComponentsEnabledOrDisabled(vrComponents, false);
-
- // Register to receive an intent when a new package is installed, in case that package
- // requires VR components.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- intentFilter.addDataScheme("package");
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- PackageManager pm = context.getPackageManager();
- final String packageName = intent.getData().getSchemeSpecificPart();
- if (packageName != null) {
- try {
- PackageInfo packageInfo = pm.getPackageInfo(packageName,
- PackageManager.GET_CONFIGURATIONS);
- enableVrComponentsIfVrModeUsed(pm, packageInfo,
- vrComponentPackageNames, vrComponents);
- } catch (NameNotFoundException e) {
- }
- }
- };
- }, intentFilter);
- }
- }
-
- private void setVrComponentsEnabledOrDisabled(ArraySet<ComponentName> vrComponents,
- boolean enabled) {
- int state = enabled ?
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- PackageManager pm = mContext.getPackageManager();
- for (ComponentName componentName : vrComponents) {
- try {
- // Note that we must first check for the existance of the package before trying
- // to set its enabled state. This is to prevent PackageManager from throwing
- // an excepton if the package is not found (not just a NameNotFoundException
- // exception).
- PackageInfo packageInfo = pm.getPackageInfo(componentName.getPackageName(),
- PackageManager.GET_CONFIGURATIONS);
- pm.setApplicationEnabledSetting(componentName.getPackageName(), state , 0);
- } catch (NameNotFoundException e) {
- }
- }
- }
-
- private boolean enableVrComponentsIfVrModeUsed(PackageManager pm, PackageInfo packageInfo,
- ArraySet<String> vrComponentPackageNames, ArraySet<ComponentName> vrComponents) {
- boolean isVrComponent = vrComponents != null &&
- vrComponentPackageNames.contains(packageInfo.packageName);
- if (packageInfo != null && packageInfo.reqFeatures != null && !isVrComponent) {
- for (FeatureInfo featureInfo : packageInfo.reqFeatures) {
- if (featureInfo.name != null &&
- (featureInfo.name.equals(PackageManager.FEATURE_VR_MODE) ||
- featureInfo.name.equals(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE))) {
- Slog.i(TAG, "VR package found, enabling VR components");
- setVrComponentsEnabledOrDisabled(vrComponents, true);
- return true;
- }
- }
- }
- return false;
}
@Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d79aa8c..59070ba 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1470,19 +1470,27 @@
}
@Override
- public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
+ public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
+ int userId) {
+
if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
- setWallpaperComponent(name);
+ setWallpaperComponent(name, userId);
}
}
// ToDo: Remove this version of the function
@Override
public void setWallpaperComponent(ComponentName name) {
+ setWallpaperComponent(name, UserHandle.getCallingUserId());
+ }
+
+ private void setWallpaperComponent(ComponentName name, int userId) {
+ userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
+ false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
+
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
- int userId = UserHandle.getCallingUserId();
WallpaperData wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 8be5dfb..a5ddf5a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -389,7 +389,7 @@
if (spec != null && !spec.isNop()) {
WindowManagerPolicy policy = mWindowManagerService.mPolicy;
final int windowType = windowState.mAttrs.type;
- if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
+ if (!policy.isTopLevelWindow(windowType) && windowState.isChildWindow()
&& !policy.canMagnifyWindow(windowType)) {
return null;
}
@@ -1205,9 +1205,8 @@
window.title = windowState.mAttrs.accessibilityTitle;
window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
- WindowState attachedWindow = windowState.mAttachedWindow;
- if (attachedWindow != null) {
- window.parentToken = attachedWindow.mClient.asBinder();
+ if (windowState.isChildWindow()) {
+ window.parentToken = windowState.mParentWindow.mClient.asBinder();
}
window.focused = windowState.isFocused();
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2b58156..3aefc08 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -604,7 +604,7 @@
float scaleH = mTmpRect.height() / (float) appHeight;
Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
computePivot(mTmpRect.left, scaleW),
- computePivot(mTmpRect.right, scaleH));
+ computePivot(mTmpRect.top, scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(0, 1);
@@ -1615,8 +1615,7 @@
if (isTransitionSet()) {
clear();
mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
- putDefaultNextAppTransitionCoordinates(startX, startY, startX + startWidth,
- startY + startHeight, null);
+ putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
postAnimationCallback();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fba439f..9919553 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -94,9 +94,6 @@
/** Detect user tapping outside of current focused stack bounds .*/
Region mTouchExcludeRegion = new Region();
- /** Detect user tapping in a non-resizeable task in docked or fullscreen stack .*/
- Region mNonResizeableRegion = new Region();
-
/** Save allocating when calculating rects */
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
@@ -358,7 +355,6 @@
mTouchExcludeRegion.set(mBaseDisplayRect);
final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
boolean addBackFocusedTask = false;
- mNonResizeableRegion.setEmpty();
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
TaskStack stack = mStacks.get(stackNdx);
final ArrayList<Task> tasks = stack.getTasks();
@@ -400,11 +396,6 @@
}
mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
}
- if (task.isTwoFingerScrollMode()) {
- stack.getBounds(mTmpRect);
- mNonResizeableRegion.op(mTmpRect, Region.Op.UNION);
- break;
- }
}
}
// If we removed the focused task above, add it back and only leave its
@@ -432,7 +423,7 @@
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
}
if (mTapDetector != null) {
- mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion, mNonResizeableRegion);
+ mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4434730..00781c5 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -201,14 +201,6 @@
inputWindowHandle.frameRight = frame.right;
inputWindowHandle.frameBottom = frame.bottom;
- if (child.isDockedInEffect()) {
- // Adjust to account for non-resizeable tasks that's scrolled
- inputWindowHandle.frameLeft += child.mXOffset;
- inputWindowHandle.frameTop += child.mYOffset;
- inputWindowHandle.frameRight += child.mXOffset;
- inputWindowHandle.frameBottom += child.mYOffset;
- }
-
if (child.mGlobalScale != 1) {
// If we are scaling the window, input coordinates need
// to be inversely scaled to map from what is on screen
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b4387b9..423b134 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -65,9 +65,6 @@
final Rect mPreparedFrozenBounds = new Rect();
final Configuration mPreparedFrozenMergedConfig = new Configuration();
- private Rect mPreScrollBounds = new Rect();
- private boolean mScrollValid;
-
// Bounds used to calculate the insets.
private final Rect mTempInsetBounds = new Rect();
@@ -234,22 +231,19 @@
// Can't set to fullscreen if we don't have a display to get bounds from...
return BOUNDS_CHANGE_NONE;
}
- if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
+ if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
return BOUNDS_CHANGE_NONE;
}
int boundsChange = BOUNDS_CHANGE_NONE;
- if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) {
+ if (mBounds.left != bounds.left || mBounds.top != bounds.top) {
boundsChange |= BOUNDS_CHANGE_POSITION;
}
- if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) {
+ if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
boundsChange |= BOUNDS_CHANGE_SIZE;
}
-
- mPreScrollBounds.set(bounds);
-
- resetScrollLocked();
+ mBounds.set(bounds);
mRotation = rotation;
if (displayContent != null) {
@@ -352,67 +346,6 @@
resizeLocked(mTmpRect2, mOverrideConfig, false /* forced */);
}
- void resetScrollLocked() {
- if (mScrollValid) {
- mScrollValid = false;
- applyScrollToAllWindows(0, 0);
- }
- mBounds.set(mPreScrollBounds);
- }
-
- void applyScrollToAllWindows(final int xOffset, final int yOffset) {
- for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
- final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
- for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState win = windows.get(winNdx);
- win.mXOffset = xOffset;
- win.mYOffset = yOffset;
- }
- }
- }
-
- void applyScrollToWindowIfNeeded(final WindowState win) {
- if (mScrollValid) {
- win.mXOffset = mBounds.left;
- win.mYOffset = mBounds.top;
- }
- }
-
- boolean scrollLocked(Rect bounds) {
- // shift the task bound if it doesn't fully cover the stack area
- mStack.getDimBounds(mTmpRect);
- if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) {
- if (bounds.left > mTmpRect.left) {
- bounds.left = mTmpRect.left;
- bounds.right = mTmpRect.left + mBounds.width();
- } else if (bounds.right < mTmpRect.right) {
- bounds.left = mTmpRect.right - mBounds.width();
- bounds.right = mTmpRect.right;
- }
- } else {
- if (bounds.top > mTmpRect.top) {
- bounds.top = mTmpRect.top;
- bounds.bottom = mTmpRect.top + mBounds.height();
- } else if (bounds.bottom < mTmpRect.bottom) {
- bounds.top = mTmpRect.bottom - mBounds.height();
- bounds.bottom = mTmpRect.bottom;
- }
- }
-
- // We can stop here if we're already scrolling and the scrolled bounds not changed.
- if (mScrollValid && bounds.equals(mBounds)) {
- return false;
- }
-
- // Normal setBounds() does not allow non-null bounds for fullscreen apps.
- // We only change bounds for the scrolling case without change it size,
- // on resizing path we should still want the validation.
- mBounds.set(bounds);
- mScrollValid = true;
- applyScrollToAllWindows(bounds.left, bounds.top);
- return true;
- }
-
/** Return true if the current bound can get outputted to the rest of the system as-is. */
private boolean useCurrentBounds() {
final DisplayContent displayContent = mStack.getDisplayContent();
@@ -583,11 +516,11 @@
}
// Device rotation changed.
- // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer
- // valid.
+ // - We don't want the task to move around on the screen when this happens, so update the
+ // task bounds so it stays in the same place.
// - Rotate the bounds and notify activity manager if the task can be resized independently
- // from its stack. The stack will take care of task rotation for the other case.
- mTmpRect2.set(mPreScrollBounds);
+ // from its stack. The stack will take care of task rotation for the other case.
+ mTmpRect2.set(mBounds);
if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
setBounds(mTmpRect2, mOverrideConfig);
@@ -600,7 +533,7 @@
// call. We do this to prevent a deadlock between window manager lock and activity
// manager lock been held.
mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
- RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget();
+ RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds).sendToTarget();
}
}
@@ -708,36 +641,14 @@
return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
}
- boolean inDockedWorkspace() {
- return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
- }
-
boolean inPinnedWorkspace() {
return mStack != null && mStack.mStackId == PINNED_STACK_ID;
}
- boolean isResizeableByDockedStack() {
- final DisplayContent displayContent = getDisplayContent();
- return displayContent != null && displayContent.getDockedStackLocked() != null
- && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
- }
-
boolean isFloating() {
return StackId.tasksAreFloating(mStack.mStackId);
}
- /**
- * Whether the task should be treated as if it's docked. Returns true if the task
- * is currently in docked workspace, or it's side-by-side to a docked task.
- */
- boolean isDockedInEffect() {
- return inDockedWorkspace() || isResizeableByDockedStack();
- }
-
- boolean isTwoFingerScrollMode() {
- return inCropWindowsResizeMode() && isDockedInEffect();
- }
-
WindowState getTopVisibleAppMainWindow() {
final AppWindowToken token = getTopVisibleAppToken();
return token != null ? token.findMainWindow() : null;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 80f73dc..5c321a1 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -345,20 +345,12 @@
mStartDragX = startX;
mStartDragY = startY;
- if (mTask.isDockedInEffect()) {
- // If this is a docked task or if task size is affected by docked stack changing size,
- // we can only be here if the task is not resizeable and we're handling a two-finger
- // scrolling. Use the original task bounds to position the task, the dim bounds
- // is cropped and doesn't move.
- mTask.getBounds(mTmpRect);
- } else {
- // Use the dim bounds, not the original task bounds. The cursor
- // movement should be calculated relative to the visible bounds.
- // Also, use the dim bounds of the task which accounts for
- // multiple app windows. Don't use any bounds from win itself as it
- // may not be the same size as the task.
- mTask.getDimBounds(mTmpRect);
- }
+ // Use the dim bounds, not the original task bounds. The cursor
+ // movement should be calculated relative to the visible bounds.
+ // Also, use the dim bounds of the task which accounts for
+ // multiple app windows. Don't use any bounds from win itself as it
+ // may not be the same size as the task.
+ mTask.getDimBounds(mTmpRect);
if (resize) {
if (startX < mTmpRect.left) {
@@ -422,52 +414,37 @@
// This is a moving or scrolling operation.
mTask.mStack.getDimBounds(mTmpRect);
- boolean dragEnded = false;
int nX = (int) x;
int nY = (int) y;
if (!mTmpRect.contains(nX, nY)) {
- if (mTask.isDockedInEffect()) {
- // We end the scrolling operation if position is outside the stack bounds.
- dragEnded = true;
- } else {
- // For a moving operation we allow the pointer to go out of the stack bounds, but
- // use the clamped pointer position for the drag bounds computation.
- nX = Math.min(Math.max(nX, mTmpRect.left), mTmpRect.right);
- nY = Math.min(Math.max(nY, mTmpRect.top), mTmpRect.bottom);
- }
+ // For a moving operation we allow the pointer to go out of the stack bounds, but
+ // use the clamped pointer position for the drag bounds computation.
+ nX = Math.min(Math.max(nX, mTmpRect.left), mTmpRect.right);
+ nY = Math.min(Math.max(nY, mTmpRect.top), mTmpRect.bottom);
}
updateWindowDragBounds(nX, nY, mTmpRect);
updateDimLayerVisibility(nX);
- return dragEnded;
+ return false;
}
private void updateWindowDragBounds(int x, int y, Rect stackBounds) {
final int offsetX = Math.round(x - mStartDragX);
final int offsetY = Math.round(y - mStartDragY);
mWindowDragBounds.set(mWindowOriginalBounds);
- if (mTask.isDockedInEffect()) {
- // Offset the bounds without clamp, the bounds will be shifted later
- // by window manager before applying the scrolling.
- if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) {
- mWindowDragBounds.offset(offsetX, 0);
- } else {
- mWindowDragBounds.offset(0, offsetY);
- }
- } else {
- // Horizontally, at least mMinVisibleWidth pixels of the window should remain visible.
- final int maxLeft = stackBounds.right - mMinVisibleWidth;
- final int minLeft = stackBounds.left + mMinVisibleWidth - mWindowOriginalBounds.width();
+ // Horizontally, at least mMinVisibleWidth pixels of the window should remain visible.
+ final int maxLeft = stackBounds.right - mMinVisibleWidth;
+ final int minLeft = stackBounds.left + mMinVisibleWidth - mWindowOriginalBounds.width();
- // Vertically, the top mMinVisibleHeight of the window should remain visible.
- // (This assumes that the window caption bar is at the top of the window).
- final int minTop = stackBounds.top;
- final int maxTop = stackBounds.bottom - mMinVisibleHeight;
+ // Vertically, the top mMinVisibleHeight of the window should remain visible.
+ // (This assumes that the window caption bar is at the top of the window).
+ final int minTop = stackBounds.top;
+ final int maxTop = stackBounds.bottom - mMinVisibleHeight;
- mWindowDragBounds.offsetTo(
- Math.min(Math.max(mWindowOriginalBounds.left + offsetX, minLeft), maxLeft),
- Math.min(Math.max(mWindowOriginalBounds.top + offsetY, minTop), maxTop));
- }
+ mWindowDragBounds.offsetTo(
+ Math.min(Math.max(mWindowOriginalBounds.left + offsetX, minLeft), maxLeft),
+ Math.min(Math.max(mWindowOriginalBounds.top + offsetY, minTop), maxTop));
+
if (DEBUG_TASK_POSITIONING) Slog.d(TAG,
"updateWindowDragBounds: " + mWindowDragBounds);
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 8be5b19..b137840 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -182,21 +182,9 @@
Configuration config = configs.get(task.mTaskId);
if (config != null) {
Rect bounds = taskBounds.get(task.mTaskId);
- if (task.isTwoFingerScrollMode()) {
- // This is a non-resizeable task that's docked (or side-by-side to the docked
- // stack). It might have been scrolled previously, and after the stack resizing,
- // it might no longer fully cover the stack area.
- // Save the old bounds and re-apply the scroll. This adjusts the bounds to
- // fit the new stack bounds.
- task.resizeLocked(bounds, config, false /* forced */);
- task.getBounds(mTmpRect);
- task.scrollLocked(mTmpRect);
- } else {
- task.resizeLocked(bounds, config, false /* forced */);
- task.setTempInsetBounds(
- taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
- : null);
- }
+ task.resizeLocked(bounds, config, false /* forced */);
+ task.setTempInsetBounds(taskTempInsetBounds != null ?
+ taskTempInsetBounds.get(task.mTaskId) : null);
} else {
Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
}
@@ -250,19 +238,13 @@
if (mFullscreen) {
return;
}
+
+ final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
+
// Update bounds of containing tasks.
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = mTasks.get(taskNdx);
- if (task.isTwoFingerScrollMode()) {
- // If we're scrolling we don't care about your bounds or configs,
- // they should be null as if we were in fullscreen.
- task.resizeLocked(null, null, false /* forced */);
- task.getBounds(mTmpRect2);
- task.scrollLocked(mTmpRect2);
- } else {
- final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
- task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
- }
+ task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
}
}
@@ -542,11 +524,6 @@
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
"positionTask: task=" + task + " position=" + position);
mTasks.add(position, task);
-
- // If we are moving the task across stacks, the scroll is no longer valid.
- if (task.mStack != this) {
- task.resetScrollLocked();
- }
task.mStack = this;
task.updateDisplayInfo(mDisplayContent);
boolean toTop = position == mTasks.size() - 1;
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 73ce0f2..0310b97 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -19,7 +19,6 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
-import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy.PointerEventListener;
@@ -37,10 +36,6 @@
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
private final Rect mTmpRect = new Rect();
- private final Region mNonResizeableRegion = new Region();
- private boolean mTwoFingerScrolling;
- private boolean mInGestureDetection;
- private GestureDetector mGestureDetector;
private int mPointerIconType = TYPE_NOT_SPECIFIED;
public TaskTapPointerEventListener(WindowManagerService service,
@@ -49,18 +44,8 @@
mDisplayContent = displayContent;
}
- // initialize the object, note this must be done outside WindowManagerService
- // ctor, otherwise it may cause recursion as some code in GestureDetector ctor
- // depends on WMS being already created.
- void init() {
- mGestureDetector = new GestureDetector(
- mService.mContext, new TwoFingerScrollListener(), mService.mH);
- }
-
@Override
public void onPointerEvent(MotionEvent motionEvent) {
- doGestureDetection(motionEvent);
-
final int action = motionEvent.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
@@ -73,15 +58,8 @@
x, y, mDisplayContent).sendToTarget();
}
}
- break;
}
-
- case MotionEvent.ACTION_MOVE: {
- if (motionEvent.getPointerCount() != 2) {
- stopTwoFingerScroll();
- }
- break;
- }
+ break;
case MotionEvent.ACTION_HOVER_MOVE: {
final int x = (int) motionEvent.getX();
@@ -116,76 +94,14 @@
InputManager.getInstance().setPointerIconType(mPointerIconType);
}
}
- } break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP: {
- stopTwoFingerScroll();
- break;
}
+ break;
}
}
- private void doGestureDetection(MotionEvent motionEvent) {
- if (mGestureDetector == null || mNonResizeableRegion.isEmpty()) {
- return;
- }
- final int action = motionEvent.getAction() & MotionEvent.ACTION_MASK;
- final int x = (int) motionEvent.getX();
- final int y = (int) motionEvent.getY();
- final boolean isTouchInside = mNonResizeableRegion.contains(x, y);
- if (mInGestureDetection || action == MotionEvent.ACTION_DOWN && isTouchInside) {
- // If we receive the following actions, or the pointer goes out of the area
- // we're interested in, stop detecting and cancel the current detection.
- mInGestureDetection = isTouchInside
- && action != MotionEvent.ACTION_UP
- && action != MotionEvent.ACTION_POINTER_UP
- && action != MotionEvent.ACTION_CANCEL;
- if (mInGestureDetection) {
- mGestureDetector.onTouchEvent(motionEvent);
- } else {
- MotionEvent cancelEvent = motionEvent.copy();
- cancelEvent.cancel();
- mGestureDetector.onTouchEvent(cancelEvent);
- stopTwoFingerScroll();
- }
- }
- }
-
- private void onTwoFingerScroll(MotionEvent e) {
- final int x = (int)e.getX(0);
- final int y = (int)e.getY(0);
- if (!mTwoFingerScrolling) {
- mTwoFingerScrolling = true;
- mService.mH.obtainMessage(
- H.TWO_FINGER_SCROLL_START, x, y, mDisplayContent).sendToTarget();
- }
- }
-
- private void stopTwoFingerScroll() {
- if (mTwoFingerScrolling) {
- mTwoFingerScrolling = false;
- mService.mH.obtainMessage(H.FINISH_TASK_POSITIONING).sendToTarget();
- }
- }
-
- private final class TwoFingerScrollListener extends GestureDetector.SimpleOnGestureListener {
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- if (e2.getPointerCount() == 2) {
- onTwoFingerScroll(e2);
- return true;
- }
- stopTwoFingerScroll();
- return false;
- }
- }
-
- void setTouchExcludeRegion(Region newRegion, Region nonResizeableRegion) {
+ void setTouchExcludeRegion(Region newRegion) {
synchronized (this) {
mTouchExcludeRegion.set(newRegion);
- mNonResizeableRegion.set(nonResizeableRegion);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 18f97a7..749ea12 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -661,9 +661,9 @@
while (wallpaperTargetIndex > 0) {
WindowState wb = windows.get(wallpaperTargetIndex - 1);
if (wb.mBaseLayer < maxLayer &&
- wb.mAttachedWindow != wallpaperTarget &&
- (wallpaperTarget.mAttachedWindow == null ||
- wb.mAttachedWindow != wallpaperTarget.mAttachedWindow) &&
+ wb.mParentWindow != wallpaperTarget &&
+ (wallpaperTarget.mParentWindow == null ||
+ wb.mParentWindow != wallpaperTarget.mParentWindow) &&
(wb.mAttrs.type != TYPE_APPLICATION_STARTING
|| wallpaperTarget.mToken == null
|| wb.mToken != wallpaperTarget.mToken)) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 55ade2e..67c8b0f 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -370,7 +370,7 @@
&& !mPostKeyguardExitAnimation.hasEnded()
&& !winAnimator.mKeyguardGoingAwayAnimation
&& win.hasDrawnLw()
- && win.mAttachedWindow == null
+ && !win.isChildWindow()
&& !win.mIsImWindow
&& displayId == Display.DEFAULT_DISPLAY;
@@ -388,7 +388,7 @@
if (DEBUG_KEYGUARD || DEBUG_VISIBILITY) Slog.v(TAG,
"Now policy shown: " + win);
if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
- && win.mAttachedWindow == null) {
+ && !win.isChildWindow()) {
if (unForceHiding == null) {
unForceHiding = new ArrayList<>();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2735ae7..318e890 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -200,6 +200,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
@@ -545,7 +546,7 @@
SparseArray<DisplayContent> mDisplayContents = new SparseArray<>(2);
int mRotation = 0;
- int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ int mLastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean mAltOrientation = false;
private boolean mKeyguardWaitingForActivityDrawn;
@@ -1365,7 +1366,7 @@
if (displayContent == null) {
return;
}
- final WindowState attached = win.mAttachedWindow;
+ final WindowState attached = win.mParentWindow;
WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
@@ -1426,7 +1427,7 @@
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
" Callers=" + Debug.getCallers(4));
- if (win.mAttachedWindow == null) {
+ if (!win.isChildWindow()) {
final WindowToken token = win.mToken;
int tokenWindowsPos = 0;
if (token.appWindowToken != null) {
@@ -1714,7 +1715,7 @@
if (mInputMethodWindow != null) {
while (pos < windows.size()) {
WindowState wp = windows.get(pos);
- if (wp == mInputMethodWindow || wp.mAttachedWindow == mInputMethodWindow) {
+ if (wp == mInputMethodWindow || wp.mParentWindow == mInputMethodWindow) {
pos++;
continue;
}
@@ -1956,6 +1957,11 @@
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ if (type == TYPE_TOAST) {
+ Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
} else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -2005,6 +2011,12 @@
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ } else if (type == TYPE_TOAST) {
+ if (token.windowType != TYPE_TOAST) {
+ Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
} else if (type == TYPE_QS_DIALOG) {
if (token.windowType != TYPE_QS_DIALOG) {
Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
@@ -2108,10 +2120,6 @@
}
}
- // If the window is being added to a task that's docked but non-resizeable,
- // we need to update this new window's scroll position when it's added.
- win.applyScrollIfNeeded();
-
// If the window is being added to a stack that's currently adjusted for IME,
// make sure to apply the same adjust to this new window.
win.applyAdjustForImeIfNeeded();
@@ -2711,7 +2719,7 @@
if (win == null) {
return;
}
- if (win.mAttachedWindow == null) {
+ if (!win.isChildWindow()) {
throw new IllegalArgumentException(
"repositionChild called but window is not"
+ "attached to a parent win=" + win);
@@ -2913,9 +2921,23 @@
}
result |= RELAYOUT_RES_SURFACE_CHANGED;
}
+ final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
+ if (viewVisibility == View.VISIBLE && surfaceController != null) {
+ // We already told the client to go invisible, but the message may not be
+ // handled yet, or it might want to draw a last frame. If we already have a
+ // surface, let the client use that, but don't create new surface at this point.
+ surfaceController.getSurface(outSurface);
+ } else {
+ if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
- outSurface.release();
- if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
+ + win.mAttrs.getTitle());
+ outSurface.release();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
}
if (focusMayChange) {
@@ -3050,6 +3072,7 @@
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
+ Slog.w(TAG_WM, "Failed to create surface control for " + win);
outSurface.release();
}
return result;
@@ -3096,7 +3119,7 @@
// resizing (as we only have one full-screen surface). So there is no need
// to preserve and destroy windows which are attached to another, they
// will keep their surface and its size may change over time.
- if (win.mHasSurface && win.mAttachedWindow == null) {
+ if (win.mHasSurface && !win.isChildWindow()) {
winAnimator.preserveSurfaceLocked();
result |= WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
}
@@ -3527,13 +3550,16 @@
// can re-appear and inflict its own orientation on us. Keep the
// orientation stable until this all settles down.
return mLastWindowForcedOrientation;
- } else if (mPolicy.isKeyguardLocked()
- && mLastKeyguardForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
- // Use the last orientation the keyguard forced while the display is frozen with the
- // keyguard locked.
+ } else if (mPolicy.isKeyguardLocked()) {
+ // Use the last orientation the while the display is frozen with the
+ // keyguard locked. This could be the keyguard forced orientation or
+ // from a SHOW_WHEN_LOCKED window. We don't want to check the show when
+ // locked window directly though as things aren't stable while
+ // the display is frozen, for example the window could be momentarily unavailable
+ // due to activity relaunch.
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display is frozen while keyguard locked, "
- + "return " + mLastKeyguardForcedOrientation);
- return mLastKeyguardForcedOrientation;
+ + "return " + mLastOrientation);
+ return mLastOrientation;
}
} else {
// TODO(multidisplay): Change to the correct display.
@@ -3663,12 +3689,12 @@
}
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "No app is requesting an orientation, return " + mForcedAppOrientation);
+ "No app is requesting an orientation, return " + mLastOrientation);
// The next app has not been requested to be visible, so we keep the current orientation
// to prevent freezing/unfreezing the display too early unless we are in multi-window, in
// which we don't let the app customize the orientation unless it was the home task that
// is handled above.
- return inMultiWindow ? SCREEN_ORIENTATION_UNSPECIFIED : mForcedAppOrientation;
+ return inMultiWindow ? SCREEN_ORIENTATION_UNSPECIFIED : mLastOrientation;
}
@Override
@@ -3751,8 +3777,8 @@
long ident = Binder.clearCallingIdentity();
try {
int req = getOrientationLocked();
- if (req != mForcedAppOrientation) {
- mForcedAppOrientation = req;
+ if (req != mLastOrientation) {
+ mLastOrientation = req;
//send a message to Policy indicating orientation change to take
//action like disabling/enabling sensors etc.,
mPolicy.setCurrentOrientationLw(req);
@@ -5263,21 +5289,6 @@
}
}
- public void scrollTask(int taskId, Rect bounds) {
- synchronized (mWindowMap) {
- Task task = mTaskIdToTask.get(taskId);
- if (task == null) {
- throw new IllegalArgumentException("scrollTask: taskId " + taskId
- + " not found.");
- }
-
- if (task.scrollLocked(bounds)) {
- task.getDisplayContent().layoutNeeded = true;
- mInputMonitor.setUpdateInputWindowsNeededLw();
- mWindowPlacerLocked.performSurfacePlacement();
- }
- }
- }
/**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
@@ -6165,6 +6176,21 @@
}
}
+ @Override
+ public Bitmap screenshotWallpaper() {
+ if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+ "screenshotWallpaper()")) {
+ throw new SecurityException("Requires READ_FRAME_BUFFER permission");
+ }
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
+ return screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1, true, 1f,
+ Bitmap.Config.ARGB_8888, true);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+
/**
* Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
* In portrait mode, it grabs the upper region of the screen based on the vertical dimension
@@ -6181,7 +6207,7 @@
@Override
public void run() {
Bitmap bm = screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1,
- true, 1f, Bitmap.Config.ARGB_8888);
+ true, 1f, Bitmap.Config.ARGB_8888, false);
try {
receiver.send(bm);
} catch (RemoteException e) {
@@ -6211,14 +6237,27 @@
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
return screenshotApplicationsInner(appToken, displayId, width, height, false,
- frameScale, Bitmap.Config.RGB_565);
+ frameScale, Bitmap.Config.RGB_565, false);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
+ /**
+ * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
+ * In portrait mode, it grabs the full screenshot.
+ *
+ * @param displayId the Display to take a screenshot of.
+ * @param width the width of the target bitmap
+ * @param height the height of the target bitmap
+ * @param includeFullDisplay true if the screen should not be cropped before capture
+ * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
+ * @param config of the output bitmap
+ * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
+ */
Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height,
- boolean includeFullDisplay, float frameScale, Bitmap.Config config) {
+ boolean includeFullDisplay, float frameScale, Bitmap.Config config,
+ boolean wallpaperOnly) {
final DisplayContent displayContent;
synchronized(mWindowMap) {
displayContent = getDisplayContentLocked(displayId);
@@ -6245,7 +6284,7 @@
boolean screenshotReady;
int minLayer;
- if (appToken == null) {
+ if (appToken == null && !wallpaperOnly) {
screenshotReady = true;
minLayer = 0;
} else {
@@ -6285,11 +6324,20 @@
if (ws.mLayer >= aboveAppLayer) {
continue;
}
+ if (wallpaperOnly && !ws.mIsWallpaper) {
+ continue;
+ }
if (ws.mIsImWindow) {
if (!includeImeInScreenshot) {
continue;
}
} else if (ws.mIsWallpaper) {
+ // If this is the wallpaper layer and we're only looking for the wallpaper layer
+ // then the target window state is this one.
+ if (wallpaperOnly) {
+ appWin = ws;
+ }
+
if (appWin == null) {
// We have not ran across the target window yet, so it is probably
// behind the wallpaper. This can happen when the keyguard is up and
@@ -6337,8 +6385,10 @@
}
}
- if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
- ws.isDisplayedLw() && winAnim.getShown()) {
+ final boolean foundTargetWs =
+ (ws.mAppToken != null && ws.mAppToken.token == appToken)
+ || (appWin != null && wallpaperOnly);
+ if (foundTargetWs && ws.isDisplayedLw() && winAnim.getShown()) {
screenshotReady = true;
}
@@ -6628,13 +6678,13 @@
// an orientation that has different metrics than it expected.
// eg. Portrait instead of Landscape.
- int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
+ int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
- mForcedAppOrientation, rotation);
+ mLastOrientation, rotation);
if (DEBUG_ORIENTATION) {
- Slog.v(TAG_WM, "Application requested orientation "
- + mForcedAppOrientation + ", got rotation " + rotation
+ Slog.v(TAG_WM, "Selected orientation "
+ + mLastOrientation + ", got rotation " + rotation
+ " which has " + (altOrientation ? "incompatible" : "compatible")
+ " metrics");
}
@@ -6648,7 +6698,7 @@
Slog.v(TAG_WM,
"Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
+ " from " + mRotation + (mAltOrientation ? " (alt)" : "")
- + ", forceApp=" + mForcedAppOrientation);
+ + ", lastOrientation=" + mLastOrientation);
}
int oldRotation = mRotation;
@@ -7568,26 +7618,6 @@
return true;
}
- private void startScrollingTask(DisplayContent displayContent, int startX, int startY) {
- if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM,
- "startScrollingTask: " + "{" + startX + ", " + startY + "}");
-
- Task task = null;
- synchronized (mWindowMap) {
- int taskId = displayContent.taskIdFromPoint(startX, startY);
- if (taskId >= 0) {
- task = mTaskIdToTask.get(taskId);
- }
- if (task == null || !task.isDockedInEffect() || !startPositioningLocked(
- task.getTopVisibleAppMainWindow(), false /*resize*/, startX, startY)) {
- return;
- }
- }
- try {
- mActivityManager.setFocusedTask(task.mTaskId);
- } catch(RemoteException e) {}
- }
-
private void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
int taskId = -1;
synchronized (mWindowMap) {
@@ -7976,9 +8006,6 @@
if (displayContent != null) {
mAnimator.addDisplayLocked(displayId);
displayContent.initializeDisplayBaseInfo();
- if (displayContent.mTapDetector != null) {
- displayContent.mTapDetector.init();
- }
}
}
}
@@ -8043,8 +8070,6 @@
public static final int RESIZE_STACK = 42;
public static final int RESIZE_TASK = 43;
- public static final int TWO_FINGER_SCROLL_START = 44;
-
public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
@@ -8542,11 +8567,6 @@
}
break;
- case TWO_FINGER_SCROLL_START: {
- startScrollingTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
- }
- break;
-
case TAP_OUTSIDE_TASK: {
handleTapOutsideTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
}
@@ -10501,7 +10521,7 @@
pw.print(" mRotation="); pw.print(mRotation);
pw.print(" mAltOrientation="); pw.println(mAltOrientation);
pw.print(" mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
- pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
+ pw.print(" mLastOrientation="); pw.println(mLastOrientation);
pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
pw.print(" Animation settings: disabled="); pw.print(mAnimationsDisabled);
pw.print(" window="); pw.print(mWindowAnimationScaleSetting);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1ac3d44..769ed10 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -150,7 +150,7 @@
// modified they will need to be locked.
final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
final DeathRecipient mDeathRecipient;
- final WindowState mAttachedWindow;
+ final WindowState mParentWindow;
final WindowList mChildWindows = new WindowList();
final int mBaseLayer;
final int mSubLayer;
@@ -504,7 +504,7 @@
boolean mSeamlesslyRotated = false;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
- WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
+ WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
mService = service;
mSession = s;
@@ -541,7 +541,7 @@
c.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
mDeathRecipient = null;
- mAttachedWindow = null;
+ mParentWindow = null;
mLayoutAttached = false;
mIsImWindow = false;
mIsWallpaper = false;
@@ -559,13 +559,13 @@
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(
- attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
+ parentWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
- mAttachedWindow = attachedWindow;
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow);
+ mParentWindow = parentWindow;
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mParentWindow);
- final WindowList childWindows = mAttachedWindow.mChildWindows;
+ final WindowList childWindows = mParentWindow.mChildWindows;
final int numChildWindows = childWindows.size();
if (numChildWindows == 0) {
childWindows.add(this);
@@ -590,9 +590,9 @@
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
- mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
- || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
- mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
+ mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
+ || parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+ mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
} else {
// The multiplier here is to reserve space for multiple
@@ -601,7 +601,7 @@
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
mSubLayer = 0;
- mAttachedWindow = null;
+ mParentWindow = null;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
@@ -611,7 +611,7 @@
WindowState appWin = this;
while (appWin.isChildWindow()) {
- appWin = appWin.mAttachedWindow;
+ appWin = appWin.mParentWindow;
}
WindowToken appToken = appWin.mToken;
while (appToken.appWindowToken == null) {
@@ -1040,7 +1040,7 @@
public int getBaseType() {
WindowState win = this;
while (win.isChildWindow()) {
- win = win.mAttachedWindow;
+ win = win.mParentWindow;
}
return win.mAttrs.type;
}
@@ -1406,7 +1406,7 @@
return mHasSurface && (mContentChanged || mMovedByResize)
&& !mAnimatingExit && mService.okToDisplay()
&& (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
- && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
+ && (!isChildWindow() || !mParentWindow.hasMoved());
}
boolean isObscuringFullscreen(final DisplayInfo displayInfo) {
@@ -1451,8 +1451,8 @@
disposeInputChannel();
if (isChildWindow()) {
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + this + " from " + mAttachedWindow);
- mAttachedWindow.mChildWindows.remove(this);
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + this + " from " + mParentWindow);
+ mParentWindow.mChildWindows.remove(this);
}
mWinAnimator.destroyDeferredSurfaceLocked();
mWinAnimator.destroySurfaceLocked();
@@ -1636,29 +1636,12 @@
}
}
- boolean inDockedWorkspace() {
- final Task task = getTask();
- return task != null && task.inDockedWorkspace();
- }
-
// TODO: Strange usage of word workspace here and above.
boolean inPinnedWorkspace() {
final Task task = getTask();
return task != null && task.inPinnedWorkspace();
}
- boolean isDockedInEffect() {
- final Task task = getTask();
- return task != null && task.isDockedInEffect();
- }
-
- void applyScrollIfNeeded() {
- final Task task = getTask();
- if (task != null) {
- task.applyScrollToWindowIfNeeded(this);
- }
- }
-
void applyAdjustForImeIfNeeded() {
final Task task = getTask();
if (task != null && task.mStack != null && task.mStack.isAdjustedForIme()) {
@@ -2170,7 +2153,7 @@
// Attached windows are evaluated based on the window that they are attached to.
WindowState win = this;
while (win.isChildWindow()) {
- win = win.mAttachedWindow;
+ win = win.mParentWindow;
}
if (win.mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
&& win.mAppToken != null && win.mAppToken.showForAllUsers) {
@@ -2549,7 +2532,7 @@
pw.print(" h="); pw.println(mLastRequestedHeight);
}
if (isChildWindow() || mLayoutAttached) {
- pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
+ pw.print(prefix); pw.print("mParentWindow="); pw.print(mParentWindow);
pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
}
if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
@@ -2838,7 +2821,7 @@
}
boolean isChildWindow() {
- return mAttachedWindow != null;
+ return mParentWindow != null;
}
boolean layoutInParentFrame() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e374ee9..e760e47 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -261,8 +260,8 @@
}
mWin = win;
- mAttachedWinAnimator = win.mAttachedWindow == null
- ? null : win.mAttachedWindow.mWinAnimator;
+ mAttachedWinAnimator = !win.isChildWindow()
+ ? null : win.mParentWindow.mWinAnimator;
mAppAnimator = win.mAppToken == null ? null : win.mAppToken.mAppAnimator;
mSession = win.mSession;
mAttrType = win.mAttrs.type;
@@ -1161,7 +1160,7 @@
// Initialize the decor rect to the entire frame.
if (w.isDockedResizing() ||
- (w.isChildWindow() && w.mAttachedWindow.isDockedResizing())) {
+ (w.isChildWindow() && w.mParentWindow.isDockedResizing())) {
// If we are resizing with the divider, the task bounds might be smaller than the
// stack bounds. The system decor is used to clip to the task bounds, which we don't
@@ -2048,7 +2047,7 @@
mDeferTransactionUntilFrame = frameNumber;
mDeferTransactionTime = System.currentTimeMillis();
mSurfaceController.deferTransactionUntil(
- mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
+ mWin.mParentWindow.mWinAnimator.mSurfaceController.getHandle(),
frameNumber);
}
@@ -2068,7 +2067,7 @@
mDeferTransactionUntilFrame = -1;
} else {
mSurfaceController.deferTransactionUntil(
- mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
+ mWin.mParentWindow.mWinAnimator.mSurfaceController.getHandle(),
mDeferTransactionUntilFrame);
}
}
@@ -2154,8 +2153,8 @@
frameRect.set(x, y, x+width, y+height);
transform.mapRect(frameRect);
- w.mAttrs.x = (int) frameRect.left - w.mAttachedWindow.mFrame.left;
- w.mAttrs.y = (int) frameRect.top - w.mAttachedWindow.mFrame.top;
+ w.mAttrs.x = (int) frameRect.left - w.mParentWindow.mFrame.left;
+ w.mAttrs.y = (int) frameRect.top - w.mParentWindow.mFrame.top;
w.mAttrs.width = (int) Math.ceil(frameRect.width());
w.mAttrs.height = (int) Math.ceil(frameRect.height());
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index e5f9728..5b4f316 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -665,7 +665,7 @@
WindowState w = windows.get(i);
if (w.mHasSurface) {
mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs,
- w.mAttachedWindow);
+ w.mParentWindow);
}
}
displayContent.pendingLayoutChanges |=
@@ -1041,7 +1041,7 @@
}
win.mLayoutNeeded = false;
win.prelayout();
- mService.mPolicy.layoutWindowLw(win, win.mAttachedWindow);
+ mService.mPolicy.layoutWindowLw(win, win.mParentWindow);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG,
" LAYOUT: mFrame=" + win.mFrame + " mContainingFrame="
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 18f0d80..887a166 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -218,6 +218,8 @@
private static final String ATTR_SETUP_COMPLETE = "setup-complete";
private static final String ATTR_PROVISIONING_STATE = "provisioning-state";
private static final String ATTR_PERMISSION_POLICY = "permission-policy";
+ private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED =
+ "device-provisioning-config-applied";
private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER
@@ -417,6 +419,8 @@
int mUserProvisioningState;
int mPermissionPolicy;
+ boolean mDeviceProvisioningConfigApplied = false;
+
final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>();
final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
@@ -2173,6 +2177,10 @@
out.attribute(null, ATTR_SETUP_COMPLETE,
Boolean.toString(true));
}
+ if (policy.mDeviceProvisioningConfigApplied) {
+ out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED,
+ Boolean.toString(true));
+ }
if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) {
out.attribute(null, ATTR_PROVISIONING_STATE,
Integer.toString(policy.mUserProvisioningState));
@@ -2333,6 +2341,12 @@
if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) {
policy.mUserSetupComplete = true;
}
+ String deviceProvisioningConfigApplied = parser.getAttributeValue(null,
+ ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED);
+ if (deviceProvisioningConfigApplied != null
+ && Boolean.toString(true).equals(deviceProvisioningConfigApplied)) {
+ policy.mDeviceProvisioningConfigApplied = true;
+ }
String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE);
if (!TextUtils.isEmpty(provisioningState)) {
policy.mUserProvisioningState = Integer.parseInt(provisioningState);
@@ -9103,4 +9117,23 @@
// restrictions.
pushUserRestrictions(userHandle);
}
+
+ @Override
+ public void setDeviceProvisioningConfigApplied() {
+ enforceManageUsers();
+ synchronized (this) {
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
+ policy.mDeviceProvisioningConfigApplied = true;
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
+ }
+ }
+
+ @Override
+ public boolean isDeviceProvisioningConfigApplied() {
+ enforceManageUsers();
+ synchronized (this) {
+ final DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
+ return policy.mDeviceProvisioningConfigApplied;
+ }
+ }
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 57f784a..0f812ac 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -180,6 +180,7 @@
private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+ private static final int IPV4_ANY_HOST_ADDRESS = 0;
private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
@@ -201,12 +202,14 @@
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
- private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
+ private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
+ private static final short ARP_OPCODE_REQUEST = 1;
+ private static final short ARP_OPCODE_REPLY = 2;
+ private static final byte[] ARP_IPV4_HEADER = new byte[]{
0, 1, // Hardware type: Ethernet (1)
8, 0, // Protocol type: IP (0x0800)
6, // Hardware size: 6
4, // Protocol size: 4
- 0, 1 // Opcode: request (1)
};
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
@@ -667,23 +670,48 @@
private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
// Here's a basic summary of what the ARP filter program does:
//
- // if interface has IPv4 address:
- // if it's not an ARP IPv4 request:
- // pass
- // if it's not a request for our IPv4 address:
- // drop
+ // if not ARP IPv4
+ // pass
+ // if not ARP IPv4 reply or request
+ // pass
+ // if unicast ARP reply
+ // pass
+ // if interface has no IPv4 address
+ // if target ip is 0.0.0.0
+ // drop
+ // else
+ // if target ip is not the interface ip
+ // drop
// pass
- if (mIPv4Address != null) {
- // if it's not an ARP IPv4 request, pass
- gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_REQUEST_HEADER, gen.PASS_LABEL);
- // if it's not a request for our IPv4 address, drop
+ final String checkTargetIPv4 = "checkTargetIPv4";
+
+ // Pass if not ARP IPv4.
+ gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL);
+
+ // Pass if unknown ARP opcode.
+ gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
+ gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
+ gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL);
+
+ // Pass if unicast reply.
+ gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
+
+ // Either a unicast request, a unicast reply, or a broadcast reply.
+ gen.defineLabel(checkTargetIPv4);
+ if (mIPv4Address == null) {
+ // When there is no IPv4 address, drop GARP replies (b/29404209).
+ gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+ gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL);
+ } else {
+ // When there is an IPv4 address, drop unicast/broadcast requests
+ // and broadcast replies with a different target IPv4 address.
gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
}
- // Otherwise, pass
gen.addJump(gen.PASS_LABEL);
}
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 855a2b6..c351e73 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -321,13 +321,15 @@
private void setupDemoUser(UserInfo userInfo) {
UserManager um = getUserManager();
UserHandle user = UserHandle.of(userInfo.id);
- LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
- lockPatternUtils.setLockScreenDisabled(true, userInfo.id);
um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
um.setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user);
um.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
+ um.setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user);
+ // Disallow rebooting in safe mode - controlled by user 0
+ getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true,
+ UserHandle.SYSTEM);
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
Settings.Secure.putIntForUser(getContext().getContentResolver(),
@@ -496,6 +498,9 @@
mAmi.updatePersistentConfigurationForUser(getSystemUsersConfiguration(), userId);
turnOffAllFlashLights();
muteVolumeStreams();
+ // Disable lock screen for demo users.
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
+ lockPatternUtils.setLockScreenDisabled(true, userId);
mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId));
synchronized (mActivityLock) {
diff --git a/services/tests/servicestests/res/xml/shortcut_error_3.xml b/services/tests/servicestests/res/xml/shortcut_error_3.xml
index a7b9b84..24ee024 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_3.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_3.xml
@@ -19,6 +19,10 @@
android:shortcutShortLabel="@string/shortcut_title1"
/>
<shortcut
+ android:shortcutId="@string/shortcut_title1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ />
+ <shortcut
android:shortcutId="x3"
android:shortcutShortLabel="@string/shortcut_title1"
>
@@ -26,5 +30,7 @@
android:action="android.intent.action.VIEW"
>
</intent>
+ <categories android:name="@string/shortcut_title1" />
+ <categories android:name="cat2" />
</shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index 815133a..bd76118 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -580,7 +580,7 @@
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
IpConnectivityLog log) throws Exception {
- super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
+ super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
ipManagerCallback, multicastFilter, log);
}
@@ -618,6 +618,7 @@
}
private static final int ETH_HEADER_LEN = 14;
+ private static final int ETH_DEST_ADDR_OFFSET = 0;
private static final int ETH_ETHERTYPE_OFFSET = 12;
private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
@@ -676,9 +677,18 @@
4, // Protocol size: 4
0, 1 // Opcode: request (1)
};
+ private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
+ 0, 1, // Hardware type: Ethernet (1)
+ 8, 0, // Protocol type: IP (0x0800)
+ 6, // Hardware size: 6
+ 4, // Protocol size: 4
+ 0, 2 // Opcode: reply (2)
+ };
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
+ private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
+ private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
@LargeTest
public void testApfFilterIPv4() throws Exception {
@@ -801,51 +811,81 @@
apfFilter.shutdown();
}
- private void verifyArpFilter(MockIpManagerCallback ipManagerCallback, ApfFilter apfFilter,
- LinkProperties linkProperties, int filterResult) {
- ipManagerCallback.resetApfProgramWait();
- apfFilter.setLinkProperties(linkProperties);
- byte[] program = ipManagerCallback.getApfProgram();
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- assertPass(program, packet.array(), 0);
- packet.position(ARP_HEADER_OFFSET);
- packet.put(ARP_IPV4_REQUEST_HEADER);
- assertVerdict(filterResult, program, packet.array(), 0);
- packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
- packet.put(MOCK_IPV4_ADDR);
- assertPass(program, packet.array(), 0);
+ private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
+ cb.resetApfProgramWait();
+ filter.setLinkProperties(lp);
+ return cb.getApfProgram();
+ }
+
+ private void verifyArpFilter(byte[] program, int filterResult) {
+ // Verify ARP request packet
+ assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
+ assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
+ assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
+
+ // Verify unicast ARP reply packet is always accepted.
+ assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
+ assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
+ assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
+
+ // Verify GARP reply packets are always filtered
+ assertDrop(program, garpReply(), 0);
}
@LargeTest
public void testApfFilterArp() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
- byte[] program = ipManagerCallback.getApfProgram();
- // Verify initially ARP filter is off
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- assertPass(program, packet.array(), 0);
- packet.position(ARP_HEADER_OFFSET);
- packet.put(ARP_IPV4_REQUEST_HEADER);
- assertPass(program, packet.array(), 0);
- packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
- packet.put(MOCK_IPV4_ADDR);
- assertPass(program, packet.array(), 0);
+ // Verify initially ARP request filter is off, and GARP filter is on.
+ verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
// Inform ApfFilter of our address and verify ARP filtering is on
+ LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
LinkProperties lp = new LinkProperties();
- assertTrue(lp.addLinkAddress(
- new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24)));
- verifyArpFilter(ipManagerCallback, apfFilter, lp, DROP);
+ assertTrue(lp.addLinkAddress(linkAddress));
+ verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP);
// Inform ApfFilter of loss of IP and verify ARP filtering is off
- verifyArpFilter(ipManagerCallback, apfFilter, new LinkProperties(), PASS);
+ verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS);
apfFilter.shutdown();
}
+ private static byte[] arpRequestBroadcast(byte[] tip) {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+ packet.position(ETH_DEST_ADDR_OFFSET);
+ packet.put(ETH_BROADCAST_MAC_ADDRESS);
+ packet.position(ARP_HEADER_OFFSET);
+ packet.put(ARP_IPV4_REQUEST_HEADER);
+ packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
+ packet.put(tip);
+ return packet.array();
+ }
+
+ private static byte[] arpReplyUnicast(byte[] tip) {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+ packet.position(ARP_HEADER_OFFSET);
+ packet.put(ARP_IPV4_REPLY_HEADER);
+ packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
+ packet.put(tip);
+ return packet.array();
+ }
+
+ private static byte[] garpReply() {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+ packet.position(ETH_DEST_ADDR_OFFSET);
+ packet.put(ETH_BROADCAST_MAC_ADDRESS);
+ packet.position(ARP_HEADER_OFFSET);
+ packet.put(ARP_IPV4_REPLY_HEADER);
+ packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
+ packet.put(IPV4_ANY_HOST_ADDR);
+ return packet.array();
+ }
+
// Verify that the last program pushed to the IpManager.Callback properly filters the
// given packet for the given lifetime.
private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 3d68b59..037b24e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -110,13 +110,14 @@
public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected static final String TAG = "ShortcutManagerTest";
+ protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
/**
* Whether to enable dump or not. Should be only true when debugging to avoid bugs where
* dump affecting the behavior.
*/
- protected static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
-
- protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+ protected static final boolean ENABLE_DUMP = false // DO NOT SUBMIT WITH true
+ || DUMP_IN_TEARDOWN || ShortcutService.DEBUG;
protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
@@ -154,6 +155,11 @@
// ignore.
return null;
}
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ // ignore.
+ }
}
/** Context used in the client side */
@@ -212,6 +218,11 @@
}
@Override
+ public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
+ return mInjectedLocale.toLanguageTag();
+ }
+
+ @Override
boolean injectShouldPerformVerification() {
return true; // Always verify during unit tests.
}
@@ -292,11 +303,6 @@
}
@Override
- PackageManagerInternal injectPackageManagerInternal() {
- return mMockPackageManagerInternal;
- }
-
- @Override
boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
return mDefaultLauncherChecker.test(callingPackage, userId);
}
@@ -404,11 +410,6 @@
// During tests, WTF is fatal.
fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th));
}
-
- @Override
- boolean injectCheckPendingTaskWaitThread() {
- return true;
- }
}
/** ShortcutManager with injection override methods. */
@@ -720,11 +721,6 @@
// Start the service.
initService();
setCaller(CALLING_PACKAGE_1);
-
- // In order to complicate the situation, we set mLocaleChangeSequenceNumber to 1 by
- // calling this. Running test with mLocaleChangeSequenceNumber == 0 might make us miss
- // some edge cases.
- mInternal.onSystemLocaleChangedNoLock();
}
/**
@@ -842,19 +838,11 @@
// Send boot sequence events.
mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
- // Make sure a call to onSystemLocaleChangedNoLock() before PHASE_BOOT_COMPLETED will be
- // ignored.
- final long origSequenceNumber = mService.getLocaleChangeSequenceNumber();
- mInternal.onSystemLocaleChangedNoLock();
- assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber());
-
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
protected void shutdownServices() {
if (mService != null) {
- mService.getPendingTasksForTest().waitOnAllTasks();
-
// Flush all the unsaved data from the previous instance.
mService.saveDirtyInfo();
@@ -1480,12 +1468,30 @@
return new File(si.getBitmapPath()).getName();
}
+ /**
+ * @return all shortcuts stored internally for the caller. This reflects the *internal* view
+ * of shortcuts, which may be different from what {@link #getCallerVisibleShortcuts} would
+ * return, because getCallerVisibleShortcuts() will get shortcuts from the proper "front door"
+ * which performs some extra checks, like {@link ShortcutPackage#onRestored}.
+ */
protected List<ShortcutInfo> getCallerShortcuts() {
final ShortcutPackage p = mService.getPackageShortcutForTest(
getCallingPackage(), getCallingUserId());
return p == null ? null : p.getAllShortcutsForTest();
}
+ /**
+ * @return all shortcuts owned by caller that are actually visible via ShortcutManager.
+ * See also {@link #getCallerShortcuts}.
+ */
+ protected List<ShortcutInfo> getCallerVisibleShortcuts() {
+ final ArrayList<ShortcutInfo> ret = new ArrayList<>();
+ ret.addAll(mManager.getDynamicShortcuts());
+ ret.addAll(mManager.getPinnedShortcuts());
+ ret.addAll(mManager.getManifestShortcuts());
+ return ret;
+ }
+
protected ShortcutInfo getCallerShortcut(String shortcutId) {
return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
}
@@ -1696,6 +1702,8 @@
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
});
+
+ // Note LAUNCHER_3 has allowBackup=false.
runWithCaller(LAUNCHER_3, USER_0, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index aa1072e..55fa625f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -62,7 +62,6 @@
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.Manifest.permission;
import android.app.ActivityManager;
@@ -1298,7 +1297,8 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_3);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
@@ -1316,7 +1316,8 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
@@ -2814,7 +2815,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
}).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
.areAllManifest()
@@ -2851,7 +2852,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_0);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertForLauncherCallback(mLauncherApps, () -> {
@@ -3130,7 +3131,7 @@
assertEquals(2, mManager.getRemainingCallCount());
});
- mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setDefaultLauncherComponent(
+ mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setLauncher(
new ComponentName("pkg1", "class"));
// Restore.
@@ -3164,7 +3165,7 @@
});
assertEquals("pkg1", mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM)
- .getDefaultLauncherComponent().getPackageName());
+ .getLastKnownLauncher().getPackageName());
// Start another user
mService.handleUnlockUser(USER_10);
@@ -3180,7 +3181,7 @@
assertEquals("title10-1-1", getCallerShortcut("s1").getTitle());
assertEquals("title10-1-2", getCallerShortcut("s2").getTitle());
});
- assertNull(mService.getShortcutsForTest().get(USER_10).getDefaultLauncherComponent());
+ assertNull(mService.getShortcutsForTest().get(USER_10).getLastKnownLauncher());
// Try stopping the user
mService.handleCleanupUser(USER_10);
@@ -3471,7 +3472,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3488,7 +3489,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3850,7 +3851,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertWith(getCallerShortcuts())
@@ -3890,7 +3891,7 @@
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
uninstallPackage(USER_0, CALLING_PACKAGE_1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -3910,7 +3911,7 @@
mRunningUsers.put(USER_10, true);
uninstallPackage(USER_10, CALLING_PACKAGE_2);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4001,7 +4002,7 @@
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDataClear(CALLING_PACKAGE_1, USER_0));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4020,7 +4021,7 @@
mRunningUsers.put(USER_10, true);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDataClear(CALLING_PACKAGE_2, USER_10));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4047,7 +4048,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4068,7 +4069,7 @@
});
// Clear data
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDataClear(CALLING_PACKAGE_1, USER_10));
// Only manifest shortcuts will remain, and are no longer pinned.
@@ -4133,9 +4134,9 @@
reset(c0);
reset(c10);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10));
waitOnMainThread();
@@ -4156,7 +4157,7 @@
updatePackageVersion(CALLING_PACKAGE_1, 1);
// Then send the broadcast, to only user-0.
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
waitOnMainThread();
@@ -4221,7 +4222,7 @@
updatePackageVersion(CALLING_PACKAGE_2, 10);
// Then send the broadcast, to only user-0.
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
mService.handleUnlockUser(USER_10);
@@ -4245,7 +4246,7 @@
updatePackageVersion(CALLING_PACKAGE_3, 100);
// Then send the broadcast, to only user-0.
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
mService.handleUnlockUser(USER_10);
@@ -4327,7 +4328,7 @@
// Update the package.
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -4356,7 +4357,7 @@
mRunningUsers.put(USER_10, true);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4388,7 +4389,7 @@
});
// First, no changes.
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4411,7 +4412,7 @@
// Disable activity 1
mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4431,7 +4432,7 @@
// Re-enable activity 1.
// Manifest shortcuts will be re-published, but dynamic ones are not.
mEnabledActivityChecker = (activity, userId) -> true;
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4455,7 +4456,7 @@
// Disable activity 2
// Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled.
mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4518,7 +4519,7 @@
setCaller(LAUNCHER_1, USER_0);
assertForLauncherCallback(mLauncherApps, () -> {
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
}).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
// Make sure the launcher gets callbacks.
@@ -4635,8 +4636,10 @@
final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
- assertExistsAndShadow(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_1)));
- assertExistsAndShadow(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_2)));
+ assertExistsAndShadow(user0.getAllLaunchersForTest().get(
+ PackageWithUser.of(USER_0, LAUNCHER_1)));
+ assertExistsAndShadow(user0.getAllLaunchersForTest().get(
+ PackageWithUser.of(USER_0, LAUNCHER_2)));
assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
@@ -4644,90 +4647,98 @@
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertEquals(0, mManager.getDynamicShortcuts().size());
- assertShortcutIds(assertAllPinned(
- mManager.getPinnedShortcuts()),
- "s1", "s2");
+ assertWith(getCallerVisibleShortcuts())
+ .selectDynamic()
+ .isEmpty()
+
+ .revertToOriginalList()
+ .selectPinned()
+ .haveIds("s1", "s2");
});
installPackage(USER_0, LAUNCHER_1);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
- "s1");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
- /* empty, not restored */ );
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
- /* empty, not restored */ );
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s1");
- assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
+ .isEmpty();
});
installPackage(USER_0, CALLING_PACKAGE_2);
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- assertEquals(0, mManager.getDynamicShortcuts().size());
- assertShortcutIds(assertAllPinned(
- mManager.getPinnedShortcuts()),
- "s1", "s2", "s3");
+ assertWith(getCallerVisibleShortcuts())
+ .selectDynamic()
+ .isEmpty()
+
+ .revertToOriginalList()
+ .selectPinned()
+ .haveIds("s1", "s2", "s3");
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
- "s1");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
- "s1", "s2");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
- /* empty, not restored */ );
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s1");
- assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s1", "s2");
+
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
+ .isEmpty();
});
// 3 shouldn't be backed up, so no pinned shortcuts.
installPackage(USER_0, CALLING_PACKAGE_3);
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
- assertEquals(0, mManager.getDynamicShortcuts().size());
- assertEquals(0, mManager.getPinnedShortcuts().size());
+ assertWith(getCallerVisibleShortcuts())
+ .isEmpty();
});
// Launcher on a different profile shouldn't be restored.
runWithCaller(LAUNCHER_1, USER_P0, () -> {
- assertEquals(0,
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
- .size());
- assertEquals(0,
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
- .size());
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
- /* wasn't restored, so still empty */ );
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ .isEmpty();
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ .isEmpty();
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ .isEmpty();
});
// Package on a different profile, no restore.
installPackage(USER_P0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
- assertEquals(0, mManager.getDynamicShortcuts().size());
- assertEquals(0, mManager.getPinnedShortcuts().size());
+ assertWith(getCallerVisibleShortcuts())
+ .isEmpty();
});
// Restore launcher 2 on user 0.
installPackage(USER_0, LAUNCHER_2);
runWithCaller(LAUNCHER_2, USER_0, () -> {
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
- "s2");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
- "s2", "s3");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
- /* wasn't restored, so still empty */ );
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s2");
- assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s2", "s3");
+
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
+ .isEmpty();
});
@@ -4735,33 +4746,33 @@
// make sure they still have the same result.
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertEquals(0, mManager.getDynamicShortcuts().size());
- assertShortcutIds(assertAllPinned(
- mManager.getPinnedShortcuts()),
- "s1", "s2");
+ assertWith(getCallerVisibleShortcuts())
+ .areAllPinned()
+ .haveIds("s1", "s2");
});
installPackage(USER_0, LAUNCHER_1);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
- "s1");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
- "s1", "s2");
- assertShortcutIds(assertAllPinned(
- mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
- /* wasn't restored, so still empty */ );
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s1");
- assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ .areAllPinned()
+ .haveIds("s1", "s2");
+
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
+ .isEmpty();
});
installPackage(USER_0, CALLING_PACKAGE_2);
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- assertEquals(0, mManager.getDynamicShortcuts().size());
- assertShortcutIds(assertAllPinned(
- mManager.getPinnedShortcuts()),
- "s1", "s2", "s3");
+ assertWith(getCallerVisibleShortcuts())
+ .areAllPinned()
+ .haveIds("s1", "s2", "s3");
});
}
@@ -5082,6 +5093,112 @@
});
}
+ public void testBackupAndRestore_disabled() {
+ prepareCrossProfileDataSet();
+
+ // Before doing backup & restore, disable s1.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.disableShortcuts(list("s1"));
+ });
+
+ backupAndRestore();
+
+ // Below is copied from checkBackupAndRestore_success.
+
+ // Make sure non-system user is not restored.
+ final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
+ assertEquals(0, userP0.getAllPackagesForTest().size());
+ assertEquals(0, userP0.getAllLaunchersForTest().size());
+
+ // Make sure only "allowBackup" apps are restored, and are shadow.
+ final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
+ assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
+ assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
+ assertExistsAndShadow(user0.getAllLaunchersForTest().get(
+ PackageWithUser.of(USER_0, LAUNCHER_1)));
+ assertExistsAndShadow(user0.getAllLaunchersForTest().get(
+ PackageWithUser.of(USER_0, LAUNCHER_2)));
+
+ assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
+ assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
+ assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerVisibleShortcuts())
+ .areAllEnabled() // disabled shortcuts shouldn't be restored.
+
+ .selectDynamic()
+ .isEmpty()
+
+ .revertToOriginalList()
+ .selectPinned()
+ // s1 is not restored.
+ .haveIds("s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ // Note, s1 was pinned by launcher 1, but was disabled, so isn't restored.
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ .isEmpty();
+
+ assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
+ .isEmpty();
+ });
+ }
+
+
+ public void testBackupAndRestore_manifestNotRestored() {
+ // Publish two manifest shortcuts.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(mServiceContext,
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ // Pin from launcher 1.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1", "ms2"), HANDLE_USER_0);
+ });
+
+ // Update and now ms2 is gone -> disabled.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_1);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(mServiceContext,
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ // Make sure the manifest shortcuts have been published.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .areAllPinned()
+ .haveIds("ms1", "ms2")
+
+ .selectByIds("ms1")
+ .areAllManifest()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("ms2")
+ .areAllNotManifest()
+ .areAllDisabled();
+ });
+
+ // Now do the regular backup & restore test.
+ // The existence of the manifest shortcuts shouldn't affect the result.
+ prepareCrossProfileDataSet();
+ backupAndRestore();
+ }
+
public void testSaveAndLoad_crossProfile() {
prepareCrossProfileDataSet();
@@ -5518,7 +5635,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5539,7 +5656,7 @@
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_2, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5576,7 +5693,7 @@
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5613,28 +5730,31 @@
mRunningUsers.put(USER_10, false);
mUnlockedUsers.put(USER_10, false);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertEmpty(mManager.getManifestShortcuts());
- assertEmpty(mManager.getPinnedShortcuts());
+ // Don't use the mManager APIs to get shortcuts, because they'll trigger the package
+ // update check.
+ // So look the internal data directly using getCallerShortcuts().
+ assertEmpty(getCallerShortcuts());
});
// Try again, but the user is locked, so still ignored.
mRunningUsers.put(USER_10, true);
-
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertEmpty(mManager.getManifestShortcuts());
- assertEmpty(mManager.getPinnedShortcuts());
+ // Don't use the mManager APIs to get shortcuts, because they'll trigger the package
+ // update check.
+ // So look the internal data directly using getCallerShortcuts().
+ assertEmpty(getCallerShortcuts());
});
// Unlock the user, now it should work.
mUnlockedUsers.put(USER_10, true);
// Send PACKAGE_ADD broadcast to have Package 2 on user-10 publish manifest shortcuts.
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
@@ -5675,7 +5795,7 @@
R.xml.shortcut_5_reverse);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
@@ -5703,7 +5823,7 @@
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()),
R.xml.shortcut_0);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
// No manifest shortcuts, and pinned ones are disabled.
@@ -5734,14 +5854,16 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
- mManager.getManifestShortcuts()))),
- "x1");
+ assertWith(getCallerShortcuts())
+ .areAllManifest()
+ .areAllImmutable()
+ .areAllEnabled()
+ .haveIds("x1");
});
// Package 1 updated, which has one valid manifest shortcut and one invalid.
@@ -5749,14 +5871,16 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
- mManager.getManifestShortcuts()))),
- "x2");
+ assertWith(getCallerShortcuts())
+ .areAllManifest()
+ .areAllImmutable()
+ .areAllEnabled()
+ .haveIds("x2");
});
// Package 1 updated, which has one valid manifest shortcut and one invalid.
@@ -5764,14 +5888,19 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_3);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
- mManager.getManifestShortcuts()))),
- "x3");
+ assertWith(getCallerShortcuts())
+ .areAllManifest()
+ .areAllImmutable()
+ .areAllEnabled()
+ .haveIds("x3")
+ .forShortcutWithId("x3", si -> {
+ assertEquals(set("cat2"), si.getCategories());
+ });
});
}
@@ -5780,7 +5909,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_4);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5808,7 +5937,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5846,7 +5975,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_4);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Make sure 3, 4 and 5 still exist but disabled.
@@ -5894,7 +6023,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -5991,7 +6120,7 @@
});
}
- public void testManifestShortcuts_localeChange() {
+ public void testManifestShortcuts_localeChange() throws InterruptedException {
mService.handleUnlockUser(USER_0);
// Package 1 updated, which has one valid manifest shortcut and one invalid.
@@ -5999,7 +6128,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6047,8 +6176,15 @@
mInjectedCurrentTimeMillis++;
+ // Change the locale and send the broadcast, make sure the launcher gets a callback too.
mInjectedLocale = Locale.JAPANESE;
- mInternal.onSystemLocaleChangedNoLock();
+
+ setCaller(LAUNCHER_1, USER_0);
+
+ assertForLauncherCallback(mLauncherApps, () -> {
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .haveIds("ms1", "ms2", "s1");
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
// check first shortcut.
@@ -6096,7 +6232,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -6115,7 +6251,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1_disable);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Because shortcut 1 wasn't pinned, it'll just go away.
@@ -6136,7 +6272,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -6159,7 +6295,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1_disable);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Because shortcut 1 was pinned, it'll still exist as pinned, but disabled.
@@ -6192,7 +6328,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2_duplicate);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6222,7 +6358,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6294,7 +6430,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6344,7 +6480,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(LAUNCHER_1, USER_0, () -> {
@@ -6355,7 +6491,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6437,7 +6573,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6507,7 +6643,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(2, mManager.getManifestShortcuts().size());
@@ -6633,7 +6769,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(2, mManager.getManifestShortcuts().size());
@@ -6782,7 +6918,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(1, mManager.getManifestShortcuts().size());
@@ -6802,7 +6938,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_1_alt);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(3, mManager.getManifestShortcuts().size());
@@ -6822,7 +6958,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_5_alt); // manifest has 5, but max is 3, so a2 will have 3.
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(5, mManager.getManifestShortcuts().size());
@@ -6841,7 +6977,7 @@
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_0);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(0, mManager.getManifestShortcuts().size());
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index f570ff2..bd413be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -47,6 +47,8 @@
import com.android.frameworks.servicestests.R;
import com.android.server.pm.ShortcutService.ConfigConstants;
+import java.util.Locale;
+
/**
* Tests for ShortcutService and ShortcutManager.
*
@@ -130,7 +132,6 @@
assertExpectException(NullPointerException.class, "action must be set",
() -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
- // same for add.
assertExpectException(
IllegalArgumentException.class, "Short label must be provided", () -> {
ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
@@ -139,6 +140,7 @@
assertTrue(getManager().setDynamicShortcuts(list(si)));
});
+ // same for add.
assertExpectException(
IllegalArgumentException.class, "Short label must be provided", () -> {
ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
@@ -147,7 +149,6 @@
assertTrue(getManager().addDynamicShortcuts(list(si)));
});
- // same for add.
assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
@@ -181,6 +182,33 @@
.build();
assertTrue(getManager().addDynamicShortcuts(list(si)));
});
+
+ // Now all activities are not main.
+ mMainActivityChecker = (component, userId) -> false;
+
+ assertExpectException(
+ IllegalStateException.class, "is not main", () -> {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
+ .setActivity(new ComponentName(getTestContext(), "s"))
+ .build();
+ assertTrue(getManager().setDynamicShortcuts(list(si)));
+ });
+ // For add
+ assertExpectException(
+ IllegalStateException.class, "is not main", () -> {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
+ .setActivity(new ComponentName(getTestContext(), "s"))
+ .build();
+ assertTrue(getManager().addDynamicShortcuts(list(si)));
+ });
+ // For update
+ assertExpectException(
+ IllegalStateException.class, "is not main", () -> {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
+ .setActivity(new ComponentName(getTestContext(), "s"))
+ .build();
+ assertTrue(getManager().updateShortcuts(list(si)));
+ });
}
public void testShortcutInfoParcel() {
@@ -1331,13 +1359,12 @@
mService.saveDirtyInfo();
initService();
- final long origSequenceNumber = mService.getLocaleChangeSequenceNumber();
-
- mInternal.onSystemLocaleChangedNoLock();
- assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber());
+ mInjectedLocale = Locale.CHINA;
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
// Note at this point only user-0 is loaded, and the counters are reset for this user,
- // but it will work for other users too, because we persist when
+ // but it will work for other users too because we check the locale change at any
+ // API entry point.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(3, mManager.getRemainingCallCount());
@@ -1358,11 +1385,28 @@
assertEquals(3, mManager.getRemainingCallCount());
});
+ // Make sure even if we receive ACTION_LOCALE_CHANGED, if the locale hasn't actually
+ // changed, we don't reset throttling.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.updateShortcuts(list());
+ assertEquals(2, mManager.getRemainingCallCount());
+ });
+
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
+ });
+
mService.saveDirtyInfo();
initService();
- // Make sure the counter is persisted.
- assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber());
+ // The locale should be persisted, so it still shouldn't reset throttling.
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
+ });
}
public void testThrottling_foreground() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
index fcf7ea2..eb4db7a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
@@ -66,7 +66,7 @@
private void publishManifestShortcuts(ComponentName activity, int resId) {
addManifestShortcutResource(activity, resId);
updatePackageVersion(CALLING_PACKAGE, 1);
- mInternal.onPackageBroadcast(
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE, USER_0));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
new file mode 100644
index 0000000..ffb2953
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.List;
+
+/**
+ * Tests for {@link ShortcutService#hasShortcutHostPermissionInner}.
+ */
+@SmallTest
+public class ShortcutManagerTest6 extends BaseShortcutManagerTest {
+
+ private static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher";
+ private static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name";
+ private static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0;
+
+ private static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings";
+ private static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
+ private static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
+
+ private void prepareGetHomeActivitiesAsUser(ComponentName preferred,
+ List<ResolveInfo> candidates, int userId) {
+ doAnswer(inv -> {
+ ((List) inv.getArguments()[0]).addAll(candidates);
+ return preferred;
+ }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId));
+ }
+
+ private static ComponentName cn(String packageName, String name) {
+ return new ComponentName(packageName, name);
+ }
+
+ private static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) {
+ final ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = new ActivityInfo();
+ ri.activityInfo.applicationInfo = new ApplicationInfo();
+
+ ri.activityInfo.packageName = packageName;
+ ri.activityInfo.name = name;
+ if (isSystem) {
+ ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ ri.priority = priority;
+ return ri;
+ }
+
+ private static ResolveInfo getSystemLauncher() {
+ return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true,
+ PACKAGE_SYSTEM_LAUNCHER_PRIORITY);
+ }
+
+ private static ResolveInfo getFallbackLauncher() {
+ return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
+ PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
+ }
+
+ public void testHasShortcutHostPermissionInner_systemLauncherOnly() {
+ // Preferred isn't set, use the system launcher.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ null,
+ list(getSystemLauncher(), getFallbackLauncher()),
+ USER_0);
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
+
+ // Should be cached.
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ // Also make sure the last known is saved, but the cached is not.
+
+ initService();
+
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(null,
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+ }
+
+ public void testHasShortcutHostPermissionInner_with3pLauncher() {
+ // Preferred isn't set, still use the system launcher.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ null,
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_0);
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
+
+ // Should be cached.
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+ }
+
+ public void testHasShortcutHostPermissionInner_with3pLauncher_complicated() {
+ // Preferred is set. That's the default launcher.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ cn(CALLING_PACKAGE_2, "name"),
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_0);
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+ assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
+
+ // Should be cached.
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+
+ // Once set, even after the preferred launcher is cleared, SM still allows it to access
+ // shortcuts.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ null,
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_0);
+
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+ assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
+
+ // Should be cached.
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ // However, if the component has been disabled, then we'll recalculate it.
+ mEnabledActivityChecker = (comp, user) -> false;
+
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
+
+ mEnabledActivityChecker = (comp, user) -> true;
+
+ // Now the preferred changed.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ cn(CALLING_PACKAGE_1, "xyz"),
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_0);
+
+ assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+
+ // Should be cached.
+ assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+
+ // As long as there's the cached launcher set, even if getHomeActivitiesAsUser()
+ // returns different values, the cached one is still the default.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ getSystemLauncher().activityInfo.getComponentName(),
+ list(getSystemLauncher(), getFallbackLauncher()),
+ USER_0);
+
+ assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+
+ // Cached ones haven't changed.
+ assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ // However, now the "real" default launcher is the system one. So if the system
+ // launcher asks for shortcuts, we'll allow it.
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+
+ // Since the cache is updated, CALLING_PACKAGE_1 no longer has the permission.
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+
+ // Cached ones haven't changed.
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+ }
+
+ public void testHasShortcutHostPermissionInner_multiUser() {
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ null,
+ list(getSystemLauncher(), getFallbackLauncher()),
+ USER_0);
+
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ cn(CALLING_PACKAGE_2, "name"),
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_10);
+
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
+
+ // Check the cache.
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10));
+ assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_10));
+ assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10));
+ assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10));
+
+ // Check the cache.
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher());
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
+ }
+
+ public void testHasShortcutHostPermissionInner_clearCache() {
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ null,
+ list(getSystemLauncher(), getFallbackLauncher()),
+ USER_0);
+
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ cn(CALLING_PACKAGE_2, "name"),
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_10);
+
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+ assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10));
+
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
+
+ // Send ACTION_PREFERRED_ACTIVITY_CHANGED on user 10.
+ // But the user is not running, so will be ignored.
+ mService.mPackageMonitor.onReceive(mServiceContext,
+ new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED).putExtra(
+ Intent.EXTRA_USER_HANDLE, USER_10));
+
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ assertEquals(cn(CALLING_PACKAGE_2, "name"),
+ mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
+
+ // Send it again after starting the user.
+ mRunningUsers.put(USER_10, true);
+ mService.mPackageMonitor.onReceive(mServiceContext,
+ new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED).putExtra(
+ Intent.EXTRA_USER_HANDLE, USER_10));
+
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ // Only user-10's cache is cleared.
+ assertEquals(null,
+ mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
+
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java
deleted file mode 100644
index bf1ed98..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.pm;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Run with:
- adb install \
- -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
- adb shell am instrument -e class com.android.server.pm.ShortcutPendingTasksTest \
- -w com.android.frameworks.servicestests
- */
-@LargeTest
-public class ShortcutPendingTasksTest extends BaseShortcutManagerTest {
- public void testAll() {
- final AtomicReference<Throwable> thrown = new AtomicReference<>();
-
- final AtomicBoolean threadCheckerResult = new AtomicBoolean(true);
-
- final Handler handler = new Handler(Looper.getMainLooper());
-
- final ShortcutPendingTasks tasks = new ShortcutPendingTasks(
- handler::post,
- threadCheckerResult::get,
- thrown::set);
-
- // No pending tasks, shouldn't block.
- assertTrue(tasks.waitOnAllTasks());
-
- final AtomicInteger counter = new AtomicInteger();
-
- // Run one task.
- tasks.addTask(() -> {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ignore) {
- }
- counter.incrementAndGet();
- });
-
- assertTrue(tasks.waitOnAllTasks());
- assertNull(thrown.get());
-
- assertEquals(1, counter.get());
-
- // Run 3 tasks.
-
- // We use this ID to make sure only one task can run at the same time.
- final AtomicInteger currentTaskId = new AtomicInteger();
-
- tasks.addTask(() -> {
- currentTaskId.set(1);
- try {
- Thread.sleep(500);
- } catch (InterruptedException ignore) {
- }
- counter.incrementAndGet();
- assertEquals(1, currentTaskId.get());
- });
- tasks.addTask(() -> {
- currentTaskId.set(2);
- try {
- Thread.sleep(500);
- } catch (InterruptedException ignore) {
- }
- counter.incrementAndGet();
- assertEquals(2, currentTaskId.get());
- });
- tasks.addTask(() -> {
- currentTaskId.set(3);
- try {
- Thread.sleep(500);
- } catch (InterruptedException ignore) {
- }
- counter.incrementAndGet();
- assertEquals(3, currentTaskId.get());
- });
-
- assertTrue(tasks.waitOnAllTasks());
- assertNull(thrown.get());
- assertEquals(4, counter.get());
-
- // No tasks running, shouldn't block.
- assertTrue(tasks.waitOnAllTasks());
- assertNull(thrown.get());
- assertEquals(4, counter.get());
-
- // Now the thread checker returns false, so waitOnAllTasks() returns false.
- threadCheckerResult.set(false);
- assertFalse(tasks.waitOnAllTasks());
-
- threadCheckerResult.set(true);
-
- // Make sure the exception handler is called.
- tasks.addTask(() -> {
- throw new RuntimeException("XXX");
- });
- assertTrue(tasks.waitOnAllTasks());
- assertNotNull(thrown.get());
- MoreAsserts.assertContainsRegex("XXX", thrown.get().getMessage());
- }
-}
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index f89c4e4..2f64ad7 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -973,6 +973,8 @@
waitOnMainThread();
+ launcherApps.unregisterCallback(asserter.getMockCallback());
+
return asserter;
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index eb3c665..69cf1a2 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -838,6 +838,10 @@
&& mAppWidgetManager.isBoundWidgetPackage(packageName, userId)) {
return false;
}
+
+ if (isDeviceProvisioningPackage(packageName)) {
+ return false;
+ }
}
if (!isAppIdleUnfiltered(packageName, userId, elapsedRealtime)) {
@@ -930,6 +934,16 @@
return dpm.packageHasActiveAdmins(packageName, userId);
}
+ /**
+ * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
+ * returns {@code false}.
+ */
+ private boolean isDeviceProvisioningPackage(String packageName) {
+ String deviceProvisioningPackage = getContext().getResources().getString(
+ com.android.internal.R.string.config_deviceProvisioningPackage);
+ return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
+ }
+
private boolean isCarrierApp(String packageName) {
synchronized (mLock) {
if (!mHaveCarrierPrivilegedApps) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 52f75f6..ee055f4 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -370,8 +370,14 @@
*/
public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 1<<5;
+ /**
+ * Indicates that the connection represents a downgraded IMS conference.
+ * @hide
+ */
+ public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
+
//**********************************************************************************************
- // Next PROPERTY value: 1<<6
+ // Next PROPERTY value: 1<<7
//**********************************************************************************************
/**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index df9ea8d..ccf52de 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -795,6 +795,13 @@
public static final int CDMA_ROAMING_MODE_ANY = 2;
/**
+ * Report IMEI as device id even if it's a CDMA/LTE phone.
+ *
+ * @hide
+ */
+ public static final String KEY_FORCE_IMEI_BOOL = "force_imei_bool";
+
+ /**
* The families of Radio Access Technologies that will get clustered and ratcheted,
* ie, we will report transitions up within the family, but not down until we change
* cells. This prevents flapping between base technologies and higher techs that are
@@ -1001,6 +1008,7 @@
sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
+ sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
sDefaults.putInt(KEY_CDMA_ROAMING_MODE_INT, CDMA_ROAMING_MODE_RADIO_DEFAULT);
// Carrier Signalling Receivers
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index dc053bf..ff082b6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5538,5 +5538,22 @@
}
return 0;
}
+
+ /**
+ * Policy control of data connection. Usually used when data limit is passed.
+ * @param enabled True if enabling the data, otherwise disabling.
+ * @param subId sub id
+ * @hide
+ */
+ public void setPolicyDataEnabled(boolean enabled, int subId) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ service.setPolicyDataEnabled(enabled, subId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setPolicyDataEnabled", e);
+ }
+ }
}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 65254d8..36abfc9 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -205,6 +205,14 @@
*/
public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+ /**
+ * Similar to {@link #EXTRA_CALL_RAT_TYPE}, except with a lowercase 'c'. Used to ensure
+ * compatibility with modems that are non-compliant with the {@link #EXTRA_CALL_RAT_TYPE}
+ * extra key. Should be removed when the non-compliant modems are fixed.
+ * @hide
+ */
+ public static final String EXTRA_CALL_RAT_TYPE_ALT = "callRadioTech";
+
public int mServiceType;
public int mCallType;
public int mRestrictCause = CALL_RESTRICT_CAUSE_NONE;
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 8166e00..f01e4c0 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -105,6 +105,7 @@
public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 43;
public static final int EVENT_REDIRECTION_DETECTED = BASE + 44;
public static final int EVENT_PCO_DATA_RECEIVED = BASE + 45;
+ public static final int EVENT_SET_CARRIER_DATA_ENABLED = BASE + 46;
/***** Constants *****/
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2168b0e..167e1a7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1158,4 +1158,12 @@
* @hide
*/
long getVtDataUsage();
+
+ /**
+ * Policy control of data connection. Usually used when data limit is passed.
+ * @param enabled True if enabling the data, otherwise disabling.
+ * @param subId Subscription index
+ * @hide
+ */
+ void setPolicyDataEnabled(boolean enabled, int subId);
}
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 0ff95c4..a2385d6 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -645,11 +645,11 @@
}
public void onAvailabilityChanged(int status) {
- postMessage(mModelInfo.name + "Availability changed to: " + status);
+ postMessage(mModelInfo.name + " availability changed to: " + status);
}
public void onDetected(SoundTriggerDetector.EventPayload event) {
- postMessage(mModelInfo.name + "onDetected(): " + eventPayloadToString(event));
+ postMessage(mModelInfo.name + " onDetected(): " + eventPayloadToString(event));
synchronized (SoundTriggerTestService.this) {
if (mUserActivity != null) {
mUserActivity.handleDetection(mModelInfo.modelUuid);
@@ -661,7 +661,7 @@
}
public void onError() {
- postMessage(mModelInfo.name + "onError()");
+ postMessage(mModelInfo.name + " onError()");
setModelState(mModelInfo, "Error");
}
@@ -671,7 +671,7 @@
}
public void onRecognitionResumed() {
- postMessage(mModelInfo.name + "onRecognitionResumed()");
+ postMessage(mModelInfo.name + " onRecognitionResumed()");
setModelState(mModelInfo, "Resumed");
}
}
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 447ace6..288b2a3 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -750,7 +750,7 @@
}
// Source for AndroidManifest.xml
- const String8 manifestFile = String8::format("%s@AndroidManifest.xml", filename);
+ const String8 manifestFile("AndroidManifest.xml");
// The dynamicRefTable can be null if there are no resources for this asset cookie.
// This fine.
@@ -850,14 +850,16 @@
depth++;
const char16_t* ctag16 = tree.getElementName(&len);
if (ctag16 == NULL) {
- fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: failed to get XML element name (bad string pool)");
goto bail;
}
String8 tag(ctag16);
//printf("Depth %d tag %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
- fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: manifest does not start with <manifest> tag");
goto bail;
}
String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
@@ -867,12 +869,14 @@
String8 error;
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name': %s", error.string());
goto bail;
}
if (name == "") {
- fprintf(stderr, "ERROR: missing 'android:name' for permission\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: missing 'android:name' for permission");
goto bail;
}
printf("permission: %s\n",
@@ -881,12 +885,14 @@
String8 error;
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
goto bail;
}
if (name == "") {
- fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: missing 'android:name' for uses-permission");
goto bail;
}
printUsesPermission(name,
@@ -896,13 +902,14 @@
String8 error;
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
goto bail;
}
if (name == "") {
- fprintf(stderr, "ERROR: missing 'android:name' for "
- "uses-permission-sdk-23\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: missing 'android:name' for uses-permission-sdk-23");
goto bail;
}
printUsesPermissionSdk23(
@@ -1163,14 +1170,16 @@
const char16_t* ctag16 = tree.getElementName(&len);
if (ctag16 == NULL) {
- fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: failed to get XML element name (bad string pool)");
goto bail;
}
String8 tag(ctag16);
//printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
- fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: manifest does not start with <manifest> tag");
goto bail;
}
pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
@@ -1179,7 +1188,8 @@
int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
&error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:versionCode' attribute: %s",
error.string());
goto bail;
}
@@ -1191,7 +1201,8 @@
String8 versionName = AaptXml::getResolvedAttribute(res, tree,
VERSION_NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:versionName' attribute: %s",
error.string());
goto bail;
}
@@ -1212,7 +1223,8 @@
int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
INSTALL_LOCATION_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:installLocation' attribute: %s",
error.string());
goto bail;
}
@@ -1278,14 +1290,15 @@
String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:icon' attribute: %s", error.string());
goto bail;
}
int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
&error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:testOnly' attribute: %s",
error.string());
goto bail;
}
@@ -1293,8 +1306,8 @@
String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
&error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:banner' attribute: %s", error.string());
goto bail;
}
printf("application: label='%s' ",
@@ -1312,8 +1325,8 @@
int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
ISGAME_ATTR, 0, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:isGame' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:isGame' attribute: %s", error.string());
goto bail;
}
if (isGame != 0) {
@@ -1323,7 +1336,8 @@
int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
DEBUGGABLE_ATTR, 0, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:debuggable' attribute: %s",
error.string());
goto bail;
}
@@ -1352,8 +1366,8 @@
String8 name = AaptXml::getResolvedAttribute(res, tree,
MIN_SDK_VERSION_ATTR, &error);
if (error != "") {
- fprintf(stderr,
- "ERROR getting 'android:minSdkVersion' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:minSdkVersion' attribute: %s",
error.string());
goto bail;
}
@@ -1374,8 +1388,8 @@
String8 name = AaptXml::getResolvedAttribute(res, tree,
TARGET_SDK_VERSION_ATTR, &error);
if (error != "") {
- fprintf(stderr,
- "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:targetSdkVersion' attribute: %s",
error.string());
goto bail;
}
@@ -1440,8 +1454,8 @@
FeatureGroup group;
group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:label' attribute:"
- " %s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:label' attribute: %s", error.string());
goto bail;
}
featureGroups.add(group);
@@ -1486,13 +1500,14 @@
} else if (tag == "uses-permission") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
goto bail;
}
if (name == "") {
- fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: missing 'android:name' for uses-permission");
goto bail;
}
@@ -1521,14 +1536,14 @@
} else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
goto bail;
}
if (name == "") {
- fprintf(stderr, "ERROR: missing 'android:name' for "
- "uses-permission-sdk-23\n");
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR: missing 'android:name' for uses-permission-sdk-23");
goto bail;
}
@@ -1543,9 +1558,9 @@
printf("uses-package:'%s'\n",
ResTable::normalizeForOutput(name.string()).string());
} else {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
- goto bail;
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
+ goto bail;
}
} else if (tag == "original-package") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
@@ -1553,9 +1568,9 @@
printf("original-package:'%s'\n",
ResTable::normalizeForOutput(name.string()).string());
} else {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
- goto bail;
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
+ goto bail;
}
} else if (tag == "supports-gl-texture") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
@@ -1563,15 +1578,15 @@
printf("supports-gl-texture:'%s'\n",
ResTable::normalizeForOutput(name.string()).string());
} else {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
- goto bail;
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
+ goto bail;
}
} else if (tag == "compatible-screens") {
printCompatibleScreens(tree, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting compatible screens: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting compatible screens: %s", error.string());
goto bail;
}
depth--;
@@ -1608,7 +1623,8 @@
withinActivity = true;
activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s",
error.string());
goto bail;
}
@@ -1616,7 +1632,8 @@
activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
&error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:label' attribute: %s",
error.string());
goto bail;
}
@@ -1624,7 +1641,8 @@
activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
&error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:icon' attribute: %s",
error.string());
goto bail;
}
@@ -1632,7 +1650,8 @@
activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
&error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:banner' attribute: %s",
error.string());
goto bail;
}
@@ -1659,9 +1678,9 @@
} else if (tag == "uses-library") {
String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr,
+ SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for uses-library"
- " %s\n", error.string());
+ " %s", error.string());
goto bail;
}
int req = AaptXml::getIntegerAttribute(tree,
@@ -1674,9 +1693,9 @@
receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr,
+ SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for receiver:"
- " %s\n", error.string());
+ " %s", error.string());
goto bail;
}
@@ -1687,9 +1706,9 @@
hasBindDeviceAdminPermission = true;
}
} else {
- fprintf(stderr,
+ SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:permission' attribute for"
- " receiver '%s': %s\n",
+ " receiver '%s': %s",
receiverName.string(), error.string());
}
} else if (tag == "service") {
@@ -1697,8 +1716,9 @@
serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for "
- "service:%s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute for "
+ "service:%s", error.string());
goto bail;
}
@@ -1723,8 +1743,9 @@
hasBindDreamServicePermission = true;
}
} else {
- fprintf(stderr, "ERROR getting 'android:permission' attribute for "
- "service '%s': %s\n", serviceName.string(), error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:permission' attribute for "
+ "service '%s': %s", serviceName.string(), error.string());
}
} else if (tag == "provider") {
withinProvider = true;
@@ -1732,26 +1753,27 @@
bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
EXPORTED_ATTR, &error);
if (error != "") {
- fprintf(stderr,
+ SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:exported' attribute for provider:"
- " %s\n", error.string());
+ " %s", error.string());
goto bail;
}
bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
if (error != "") {
- fprintf(stderr,
+ SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:grantUriPermissions' attribute for "
- "provider: %s\n", error.string());
+ "provider: %s", error.string());
goto bail;
}
String8 permission = AaptXml::getResolvedAttribute(res, tree,
PERMISSION_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:permission' attribute for "
- "provider: %s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:permission' attribute for "
+ "provider: %s", error.string());
goto bail;
}
@@ -1762,8 +1784,9 @@
String8 metaDataName = AaptXml::getResolvedAttribute(res, tree,
NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for "
- "meta-data:%s\n", error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute for "
+ "meta-data: %s", error.string());
goto bail;
}
printf("meta-data: name='%s' ",
@@ -1776,9 +1799,10 @@
printResolvedResourceAttribute(res, tree, RESOURCE_ATTR,
String8("resource"), &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:value' or "
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:value' or "
"'android:resource' attribute for "
- "meta-data:%s\n", error.string());
+ "meta-data: %s", error.string());
goto bail;
}
}
@@ -1788,7 +1812,8 @@
if (name != "" && error == "") {
supportedInput.add(name);
} else {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s",
error.string());
goto bail;
}
@@ -1847,8 +1872,9 @@
} else if (withinService && tag == "meta-data") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for "
- "meta-data tag in service '%s': %s\n", serviceName.string(),
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute for "
+ "meta-data tag in service '%s': %s", serviceName.string(),
error.string());
goto bail;
}
@@ -1863,8 +1889,9 @@
String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
RESOURCE_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:resource' attribute for "
- "meta-data tag in service '%s': %s\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:resource' attribute for "
+ "meta-data tag in service '%s': %s",
serviceName.string(), error.string());
goto bail;
}
@@ -1872,7 +1899,8 @@
Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
offHost, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting AID category for service '%s'\n",
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting AID category for service '%s'",
serviceName.string());
goto bail;
}
@@ -1893,8 +1921,8 @@
if (tag == "action") {
action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:name' attribute: %s", error.string());
goto bail;
}
@@ -1949,8 +1977,8 @@
if (tag == "category") {
String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
- error.string());
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'name' attribute: %s", error.string());
goto bail;
}
if (withinActivity) {
@@ -2261,6 +2289,10 @@
result = NO_ERROR;
bail:
+ if (SourcePos::hasErrors()) {
+ SourcePos::printErrors(stderr);
+ }
+
if (asset) {
delete asset;
}
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index f2c13ba..bbb9a51 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -103,6 +103,7 @@
java/JavaClassGenerator_test.cpp \
java/ManifestClassGenerator_test.cpp \
Locale_test.cpp \
+ NameMangler_test.cpp \
Resource_test.cpp \
ResourceParser_test.cpp \
ResourceTable_test.cpp \
diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h
index 51d8ca6..1d39b72 100644
--- a/tools/aapt2/AppInfo.h
+++ b/tools/aapt2/AppInfo.h
@@ -31,12 +31,12 @@
/**
* App's package name.
*/
- std::u16string package;
+ std::string package;
/**
* The App's minimum SDK version.
*/
- Maybe<std::u16string> minSdkVersion;
+ Maybe<std::string> minSdkVersion;
};
} // namespace aapt
diff --git a/tools/aapt2/ConfigDescription_test.cpp b/tools/aapt2/ConfigDescription_test.cpp
index e68d6be..455a57f 100644
--- a/tools/aapt2/ConfigDescription_test.cpp
+++ b/tools/aapt2/ConfigDescription_test.cpp
@@ -16,10 +16,9 @@
#include "ConfigDescription.h"
#include "SdkConstants.h"
-
+#include "test/Test.h"
#include "util/StringPiece.h"
-#include <gtest/gtest.h>
#include <string>
namespace aapt {
diff --git a/tools/aapt2/Flags.cpp b/tools/aapt2/Flags.cpp
index 666e8a8e..2033a4c 100644
--- a/tools/aapt2/Flags.cpp
+++ b/tools/aapt2/Flags.cpp
@@ -101,7 +101,7 @@
// Split the description by newlines and write out the argument (which is empty after
// the first line) followed by the description line. This will make sure that multiline
// descriptions are still right justified and aligned.
- for (StringPiece line : util::tokenize<char>(flag.description, '\n')) {
+ for (StringPiece line : util::tokenize(flag.description, '\n')) {
*out << " " << std::setw(kWidth) << std::left << argLine << line << "\n";
argLine = " ";
}
diff --git a/tools/aapt2/Locale_test.cpp b/tools/aapt2/Locale_test.cpp
index 758e1e3..e4b8ce7 100644
--- a/tools/aapt2/Locale_test.cpp
+++ b/tools/aapt2/Locale_test.cpp
@@ -23,7 +23,7 @@
namespace aapt {
static ::testing::AssertionResult TestLanguage(const char* input, const char* lang) {
- std::vector<std::string> parts = util::splitAndLowercase(std::string(input), '-');
+ std::vector<std::string> parts = util::splitAndLowercase(input, '-');
LocaleValue lv;
ssize_t count = lv.initFromParts(std::begin(parts), std::end(parts));
if (count < 0) {
@@ -45,7 +45,7 @@
static ::testing::AssertionResult TestLanguageRegion(const char* input, const char* lang,
const char* region) {
- std::vector<std::string> parts = util::splitAndLowercase(std::string(input), '-');
+ std::vector<std::string> parts = util::splitAndLowercase(input, '-');
LocaleValue lv;
ssize_t count = lv.initFromParts(std::begin(parts), std::end(parts));
if (count < 0) {
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h
index 054b9ee..505a982e 100644
--- a/tools/aapt2/NameMangler.h
+++ b/tools/aapt2/NameMangler.h
@@ -18,7 +18,6 @@
#define AAPT_NAME_MANGLER_H
#include "Resource.h"
-
#include "util/Maybe.h"
#include <set>
@@ -31,12 +30,12 @@
* Represents the package we are trying to build. References pointing
* to this package are not mangled, and mangled references inherit this package name.
*/
- std::u16string targetPackageName;
+ std::string targetPackageName;
/**
* We must know which references to mangle, and which to keep (android vs. com.android.support).
*/
- std::set<std::u16string> packagesToMangle;
+ std::set<std::string> packagesToMangle;
};
class NameMangler {
@@ -53,14 +52,11 @@
return {};
}
- return ResourceName{
- mPolicy.targetPackageName,
- name.type,
- mangleEntry(name.package, name.entry)
- };
+ std::string mangledEntryName = mangleEntry(name.package, name.entry);
+ return ResourceName(mPolicy.targetPackageName, name.type, mangledEntryName);
}
- bool shouldMangle(const std::u16string& package) const {
+ bool shouldMangle(const std::string& package) const {
if (package.empty() || mPolicy.targetPackageName == package) {
return false;
}
@@ -72,8 +68,8 @@
* The mangled name should contain symbols that are illegal to define in XML,
* so that there will never be name mangling collisions.
*/
- static std::u16string mangleEntry(const std::u16string& package, const std::u16string& name) {
- return package + u"$" + name;
+ static std::string mangleEntry(const std::string& package, const std::string& name) {
+ return package + "$" + name;
}
/**
@@ -81,8 +77,8 @@
* and the package in `outPackage`. Returns true if the name was unmangled or
* false if the name was never mangled to begin with.
*/
- static bool unmangle(std::u16string* outName, std::u16string* outPackage) {
- size_t pivot = outName->find(u'$');
+ static bool unmangle(std::string* outName, std::string* outPackage) {
+ size_t pivot = outName->find('$');
if (pivot == std::string::npos) {
return false;
}
diff --git a/tools/aapt2/NameMangler_test.cpp b/tools/aapt2/NameMangler_test.cpp
index 6103655..f624df2 100644
--- a/tools/aapt2/NameMangler_test.cpp
+++ b/tools/aapt2/NameMangler_test.cpp
@@ -15,31 +15,32 @@
*/
#include "NameMangler.h"
+#include "test/Test.h"
-#include <gtest/gtest.h>
#include <string>
namespace aapt {
TEST(NameManglerTest, MangleName) {
- std::u16string package = u"android.appcompat";
- std::u16string name = u"Platform.AppCompat";
+ std::string package = "android.appcompat";
+ std::string name = "Platform.AppCompat";
- NameMangler::mangle(package, &name);
- EXPECT_EQ(name, u"android.appcompat$Platform.AppCompat");
+ std::string mangledName = NameMangler::mangleEntry(package, name);
+ EXPECT_EQ(mangledName, "android.appcompat$Platform.AppCompat");
- std::u16string newPackage;
- ASSERT_TRUE(NameMangler::unmangle(&name, &newPackage));
- EXPECT_EQ(name, u"Platform.AppCompat");
- EXPECT_EQ(newPackage, u"android.appcompat");
+ std::string unmangledPackage;
+ std::string unmangledName = mangledName;
+ ASSERT_TRUE(NameMangler::unmangle(&unmangledName, &unmangledPackage));
+ EXPECT_EQ(unmangledName, "Platform.AppCompat");
+ EXPECT_EQ(unmangledPackage, "android.appcompat");
}
TEST(NameManglerTest, IgnoreUnmangledName) {
- std::u16string package;
- std::u16string name = u"foo_bar";
+ std::string package;
+ std::string name = "foo_bar";
EXPECT_FALSE(NameMangler::unmangle(&name, &package));
- EXPECT_EQ(name, u"foo_bar");
+ EXPECT_EQ(name, "foo_bar");
}
} // namespace aapt
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 9328b69..b7a091e 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -22,62 +22,62 @@
namespace aapt {
-StringPiece16 toString(ResourceType type) {
+StringPiece toString(ResourceType type) {
switch (type) {
- case ResourceType::kAnim: return u"anim";
- case ResourceType::kAnimator: return u"animator";
- case ResourceType::kArray: return u"array";
- case ResourceType::kAttr: return u"attr";
- case ResourceType::kAttrPrivate: return u"^attr-private";
- case ResourceType::kBool: return u"bool";
- case ResourceType::kColor: return u"color";
- case ResourceType::kDimen: return u"dimen";
- case ResourceType::kDrawable: return u"drawable";
- case ResourceType::kFraction: return u"fraction";
- case ResourceType::kId: return u"id";
- case ResourceType::kInteger: return u"integer";
- case ResourceType::kInterpolator: return u"interpolator";
- case ResourceType::kLayout: return u"layout";
- case ResourceType::kMenu: return u"menu";
- case ResourceType::kMipmap: return u"mipmap";
- case ResourceType::kPlurals: return u"plurals";
- case ResourceType::kRaw: return u"raw";
- case ResourceType::kString: return u"string";
- case ResourceType::kStyle: return u"style";
- case ResourceType::kStyleable: return u"styleable";
- case ResourceType::kTransition: return u"transition";
- case ResourceType::kXml: return u"xml";
+ case ResourceType::kAnim: return "anim";
+ case ResourceType::kAnimator: return "animator";
+ case ResourceType::kArray: return "array";
+ case ResourceType::kAttr: return "attr";
+ case ResourceType::kAttrPrivate: return "^attr-private";
+ case ResourceType::kBool: return "bool";
+ case ResourceType::kColor: return "color";
+ case ResourceType::kDimen: return "dimen";
+ case ResourceType::kDrawable: return "drawable";
+ case ResourceType::kFraction: return "fraction";
+ case ResourceType::kId: return "id";
+ case ResourceType::kInteger: return "integer";
+ case ResourceType::kInterpolator: return "interpolator";
+ case ResourceType::kLayout: return "layout";
+ case ResourceType::kMenu: return "menu";
+ case ResourceType::kMipmap: return "mipmap";
+ case ResourceType::kPlurals: return "plurals";
+ case ResourceType::kRaw: return "raw";
+ case ResourceType::kString: return "string";
+ case ResourceType::kStyle: return "style";
+ case ResourceType::kStyleable: return "styleable";
+ case ResourceType::kTransition: return "transition";
+ case ResourceType::kXml: return "xml";
}
return {};
}
-static const std::map<StringPiece16, ResourceType> sResourceTypeMap {
- { u"anim", ResourceType::kAnim },
- { u"animator", ResourceType::kAnimator },
- { u"array", ResourceType::kArray },
- { u"attr", ResourceType::kAttr },
- { u"^attr-private", ResourceType::kAttrPrivate },
- { u"bool", ResourceType::kBool },
- { u"color", ResourceType::kColor },
- { u"dimen", ResourceType::kDimen },
- { u"drawable", ResourceType::kDrawable },
- { u"fraction", ResourceType::kFraction },
- { u"id", ResourceType::kId },
- { u"integer", ResourceType::kInteger },
- { u"interpolator", ResourceType::kInterpolator },
- { u"layout", ResourceType::kLayout },
- { u"menu", ResourceType::kMenu },
- { u"mipmap", ResourceType::kMipmap },
- { u"plurals", ResourceType::kPlurals },
- { u"raw", ResourceType::kRaw },
- { u"string", ResourceType::kString },
- { u"style", ResourceType::kStyle },
- { u"styleable", ResourceType::kStyleable },
- { u"transition", ResourceType::kTransition },
- { u"xml", ResourceType::kXml },
+static const std::map<StringPiece, ResourceType> sResourceTypeMap {
+ { "anim", ResourceType::kAnim },
+ { "animator", ResourceType::kAnimator },
+ { "array", ResourceType::kArray },
+ { "attr", ResourceType::kAttr },
+ { "^attr-private", ResourceType::kAttrPrivate },
+ { "bool", ResourceType::kBool },
+ { "color", ResourceType::kColor },
+ { "dimen", ResourceType::kDimen },
+ { "drawable", ResourceType::kDrawable },
+ { "fraction", ResourceType::kFraction },
+ { "id", ResourceType::kId },
+ { "integer", ResourceType::kInteger },
+ { "interpolator", ResourceType::kInterpolator },
+ { "layout", ResourceType::kLayout },
+ { "menu", ResourceType::kMenu },
+ { "mipmap", ResourceType::kMipmap },
+ { "plurals", ResourceType::kPlurals },
+ { "raw", ResourceType::kRaw },
+ { "string", ResourceType::kString },
+ { "style", ResourceType::kStyle },
+ { "styleable", ResourceType::kStyleable },
+ { "transition", ResourceType::kTransition },
+ { "xml", ResourceType::kXml },
};
-const ResourceType* parseResourceType(const StringPiece16& str) {
+const ResourceType* parseResourceType(const StringPiece& str) {
auto iter = sResourceTypeMap.find(str);
if (iter == std::end(sResourceTypeMap)) {
return nullptr;
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 03ca42b..22d75a2 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -24,6 +24,7 @@
#include <iomanip>
#include <limits>
+#include <sstream>
#include <string>
#include <tuple>
#include <vector>
@@ -60,28 +61,28 @@
kXml,
};
-StringPiece16 toString(ResourceType type);
+StringPiece toString(ResourceType type);
/**
* Returns a pointer to a valid ResourceType, or nullptr if
* the string was invalid.
*/
-const ResourceType* parseResourceType(const StringPiece16& str);
+const ResourceType* parseResourceType(const StringPiece& str);
/**
* A resource's name. This can uniquely identify
* a resource in the ResourceTable.
*/
struct ResourceName {
- std::u16string package;
+ std::string package;
ResourceType type;
- std::u16string entry;
+ std::string entry;
ResourceName() : type(ResourceType::kRaw) {}
- ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e);
+ ResourceName(const StringPiece& p, ResourceType t, const StringPiece& e);
bool isValid() const;
- std::u16string toString() const;
+ std::string toString() const;
};
/**
@@ -91,15 +92,15 @@
* of the original string.
*/
struct ResourceNameRef {
- StringPiece16 package;
+ StringPiece package;
ResourceType type;
- StringPiece16 entry;
+ StringPiece entry;
ResourceNameRef() = default;
ResourceNameRef(const ResourceNameRef&) = default;
ResourceNameRef(ResourceNameRef&&) = default;
ResourceNameRef(const ResourceName& rhs);
- ResourceNameRef(const StringPiece16& p, ResourceType t, const StringPiece16& e);
+ ResourceNameRef(const StringPiece& p, ResourceType t, const StringPiece& e);
ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
ResourceNameRef& operator=(const ResourceName& rhs);
@@ -252,7 +253,7 @@
// ResourceName implementation.
//
-inline ResourceName::ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e) :
+inline ResourceName::ResourceName(const StringPiece& p, ResourceType t, const StringPiece& e) :
package(p.toString()), type(t), entry(e.toString()) {
}
@@ -275,14 +276,6 @@
!= std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline std::u16string ResourceName::toString() const {
- std::u16string result;
- if (!package.empty()) {
- result = package + u":";
- }
- return result + aapt::toString(type).toString() + u"/" + entry;
-}
-
inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
if (!name.package.empty()) {
out << name.package << ":";
@@ -290,6 +283,11 @@
return out << name.type << "/" << name.entry;
}
+inline std::string ResourceName::toString() const {
+ std::stringstream stream;
+ stream << *this;
+ return stream.str();
+}
//
// ResourceNameRef implementation.
@@ -299,8 +297,8 @@
package(rhs.package), type(rhs.type), entry(rhs.entry) {
}
-inline ResourceNameRef::ResourceNameRef(const StringPiece16& p, ResourceType t,
- const StringPiece16& e) :
+inline ResourceNameRef::ResourceNameRef(const StringPiece& p, ResourceType t,
+ const StringPiece& e) :
package(p), type(t), entry(e) {
}
@@ -312,7 +310,7 @@
}
inline ResourceName ResourceNameRef::toResourceName() const {
- return { package.toString(), type, entry.toString() };
+ return ResourceName(package, type, entry);
}
inline bool ResourceNameRef::isValid() const {
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index a84c306..45d3db9 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -28,33 +28,33 @@
namespace aapt {
-constexpr const char16_t* sXliffNamespaceUri = u"urn:oasis:names:tc:xliff:document:1.2";
+constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
/**
* Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
*/
-static bool shouldIgnoreElement(const StringPiece16& ns, const StringPiece16& name) {
- return ns.empty() && (name == u"skip" || name == u"eat-comment");
+static bool shouldIgnoreElement(const StringPiece& ns, const StringPiece& name) {
+ return ns.empty() && (name == "skip" || name == "eat-comment");
}
-static uint32_t parseFormatType(const StringPiece16& piece) {
- if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE;
- else if (piece == u"string") return android::ResTable_map::TYPE_STRING;
- else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER;
- else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN;
- else if (piece == u"color") return android::ResTable_map::TYPE_COLOR;
- else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT;
- else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
- else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION;
- else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM;
- else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS;
+static uint32_t parseFormatType(const StringPiece& piece) {
+ if (piece == "reference") return android::ResTable_map::TYPE_REFERENCE;
+ else if (piece == "string") return android::ResTable_map::TYPE_STRING;
+ else if (piece == "integer") return android::ResTable_map::TYPE_INTEGER;
+ else if (piece == "boolean") return android::ResTable_map::TYPE_BOOLEAN;
+ else if (piece == "color") return android::ResTable_map::TYPE_COLOR;
+ else if (piece == "float") return android::ResTable_map::TYPE_FLOAT;
+ else if (piece == "dimension") return android::ResTable_map::TYPE_DIMENSION;
+ else if (piece == "fraction") return android::ResTable_map::TYPE_FRACTION;
+ else if (piece == "enum") return android::ResTable_map::TYPE_ENUM;
+ else if (piece == "flags") return android::ResTable_map::TYPE_FLAGS;
return 0;
}
-static uint32_t parseFormatAttribute(const StringPiece16& str) {
+static uint32_t parseFormatAttribute(const StringPiece& str) {
uint32_t mask = 0;
- for (StringPiece16 part : util::tokenize(str, u'|')) {
- StringPiece16 trimmedPart = util::trimWhitespace(part);
+ for (StringPiece part : util::tokenize(str, '|')) {
+ StringPiece trimmedPart = util::trimWhitespace(part);
uint32_t type = parseFormatType(trimmedPart);
if (type == 0) {
return 0;
@@ -74,14 +74,14 @@
Source source;
ResourceId id;
Maybe<SymbolState> symbolState;
- std::u16string comment;
+ std::string comment;
std::unique_ptr<Value> value;
std::list<ParsedResource> childResources;
};
// Recursively adds resources to the ResourceTable.
static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
- StringPiece16 trimmedComment = util::trimWhitespace(res->comment);
+ StringPiece trimmedComment = util::trimWhitespace(res->comment);
if (trimmedComment.size() != res->comment.size()) {
// Only if there was a change do we re-assign.
res->comment = trimmedComment.toString();
@@ -130,7 +130,7 @@
/**
* Build a string from XML that converts nested elements into Span objects.
*/
-bool ResourceParser::flattenXmlSubtree(xml::XmlPullParser* parser, std::u16string* outRawString,
+bool ResourceParser::flattenXmlSubtree(xml::XmlPullParser* parser, std::string* outRawString,
StyleString* outStyleString) {
std::vector<Span> spanStack;
@@ -176,12 +176,12 @@
depth++;
// Build a span object out of the nested element.
- std::u16string spanName = parser->getElementName();
+ std::string spanName = parser->getElementName();
const auto endAttrIter = parser->endAttributes();
for (auto attrIter = parser->beginAttributes(); attrIter != endAttrIter; ++attrIter) {
- spanName += u";";
+ spanName += ";";
spanName += attrIter->name;
- spanName += u"=";
+ spanName += "=";
spanName += attrIter->value;
}
@@ -214,7 +214,7 @@
continue;
}
- if (!parser->getElementNamespace().empty() || parser->getElementName() != u"resources") {
+ if (!parser->getElementNamespace().empty() || parser->getElementName() != "resources") {
mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
<< "root element must be <resources>");
return false;
@@ -236,7 +236,7 @@
std::set<ResourceName> strippedResources;
bool error = false;
- std::u16string comment;
+ std::string comment;
const size_t depth = parser->getDepth();
while (xml::XmlPullParser::nextChildNode(parser, depth)) {
const xml::XmlPullParser::Event event = parser->getEvent();
@@ -261,9 +261,9 @@
continue;
}
- std::u16string elementName = parser->getElementName();
- if (elementName == u"skip" || elementName == u"eat-comment") {
- comment = u"";
+ std::string elementName = parser->getElementName();
+ if (elementName == "skip" || elementName == "eat-comment") {
+ comment = "";
continue;
}
@@ -273,8 +273,8 @@
parsedResource.comment = std::move(comment);
// Extract the product name if it exists.
- if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
- parsedResource.product = util::utf16ToUtf8(maybeProduct.value());
+ if (Maybe<StringPiece> maybeProduct = xml::findNonEmptyAttribute(parser, "product")) {
+ parsedResource.product = maybeProduct.value().toString();
}
// Parse the resource regardless of product.
@@ -310,43 +310,43 @@
using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*, ParsedResource*)>;
- static const auto elToItemMap = ImmutableMap<std::u16string, ItemTypeFormat>::createPreSorted({
- { u"bool", { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } },
- { u"color", { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } },
- { u"dimen", { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT
+ static const auto elToItemMap = ImmutableMap<std::string, ItemTypeFormat>::createPreSorted({
+ { "bool", { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } },
+ { "color", { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } },
+ { "dimen", { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT
| android::ResTable_map::TYPE_FRACTION
| android::ResTable_map::TYPE_DIMENSION } },
- { u"drawable", { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } },
- { u"fraction", { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT
+ { "drawable", { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } },
+ { "fraction", { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT
| android::ResTable_map::TYPE_FRACTION
| android::ResTable_map::TYPE_DIMENSION } },
- { u"integer", { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } },
- { u"string", { ResourceType::kString, android::ResTable_map::TYPE_STRING } },
+ { "integer", { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } },
+ { "string", { ResourceType::kString, android::ResTable_map::TYPE_STRING } },
});
- static const auto elToBagMap = ImmutableMap<std::u16string, BagParseFunc>::createPreSorted({
- { u"add-resource", std::mem_fn(&ResourceParser::parseAddResource) },
- { u"array", std::mem_fn(&ResourceParser::parseArray) },
- { u"attr", std::mem_fn(&ResourceParser::parseAttr) },
- { u"declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) },
- { u"integer-array", std::mem_fn(&ResourceParser::parseIntegerArray) },
- { u"java-symbol", std::mem_fn(&ResourceParser::parseSymbol) },
- { u"plurals", std::mem_fn(&ResourceParser::parsePlural) },
- { u"public", std::mem_fn(&ResourceParser::parsePublic) },
- { u"public-group", std::mem_fn(&ResourceParser::parsePublicGroup) },
- { u"string-array", std::mem_fn(&ResourceParser::parseStringArray) },
- { u"style", std::mem_fn(&ResourceParser::parseStyle) },
- { u"symbol", std::mem_fn(&ResourceParser::parseSymbol) },
+ static const auto elToBagMap = ImmutableMap<std::string, BagParseFunc>::createPreSorted({
+ { "add-resource", std::mem_fn(&ResourceParser::parseAddResource) },
+ { "array", std::mem_fn(&ResourceParser::parseArray) },
+ { "attr", std::mem_fn(&ResourceParser::parseAttr) },
+ { "declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) },
+ { "integer-array", std::mem_fn(&ResourceParser::parseIntegerArray) },
+ { "java-symbol", std::mem_fn(&ResourceParser::parseSymbol) },
+ { "plurals", std::mem_fn(&ResourceParser::parsePlural) },
+ { "public", std::mem_fn(&ResourceParser::parsePublic) },
+ { "public-group", std::mem_fn(&ResourceParser::parsePublicGroup) },
+ { "string-array", std::mem_fn(&ResourceParser::parseStringArray) },
+ { "style", std::mem_fn(&ResourceParser::parseStyle) },
+ { "symbol", std::mem_fn(&ResourceParser::parseSymbol) },
});
- std::u16string resourceType = parser->getElementName();
+ std::string resourceType = parser->getElementName();
// The value format accepted for this resource.
uint32_t resourceFormat = 0u;
- if (resourceType == u"item") {
+ if (resourceType == "item") {
// Items have their type encoded in the type attribute.
- if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
+ if (Maybe<StringPiece> maybeType = xml::findNonEmptyAttribute(parser, "type")) {
resourceType = maybeType.value().toString();
} else {
mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
@@ -354,7 +354,7 @@
return false;
}
- if (Maybe<StringPiece16> maybeFormat = xml::findNonEmptyAttribute(parser, u"format")) {
+ if (Maybe<StringPiece> maybeFormat = xml::findNonEmptyAttribute(parser, "format")) {
// An explicit format for this resource was specified. The resource will retain
// its type in its name, but the accepted value for this type is overridden.
resourceFormat = parseFormatType(maybeFormat.value());
@@ -368,9 +368,9 @@
// Get the name of the resource. This will be checked later, because not all
// XML elements require a name.
- Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+ Maybe<StringPiece> maybeName = xml::findNonEmptyAttribute(parser, "name");
- if (resourceType == u"id") {
+ if (resourceType == "id") {
if (!maybeName) {
mDiag->error(DiagMessage(outResource->source)
<< "<" << parser->getElementName() << "> missing 'name' attribute");
@@ -411,7 +411,7 @@
const auto bagIter = elToBagMap.find(resourceType);
if (bagIter != elToBagMap.end()) {
// Ensure we have a name (unless this is a <public-group>).
- if (resourceType != u"public-group") {
+ if (resourceType != "public-group") {
if (!maybeName) {
mDiag->error(DiagMessage(outResource->source)
<< "<" << parser->getElementName() << "> missing 'name' attribute");
@@ -480,7 +480,7 @@
const bool allowRawValue) {
const size_t beginXmlLine = parser->getLineNumber();
- std::u16string rawValue;
+ std::string rawValue;
StyleString styleString;
if (!flattenXmlSubtree(parser, &rawValue, &styleString)) {
return {};
@@ -505,7 +505,7 @@
if (processedItem) {
// Fix up the reference.
if (Reference* ref = valueCast<Reference>(processedItem.get())) {
- transformReferenceFromNamespace(parser, u"", ref);
+ transformReferenceFromNamespace(parser, "", ref);
}
return processedItem;
}
@@ -527,7 +527,7 @@
bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) {
bool formatted = true;
- if (Maybe<StringPiece16> formattedAttr = xml::findAttribute(parser, u"formatted")) {
+ if (Maybe<StringPiece> formattedAttr = xml::findAttribute(parser, "formatted")) {
if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) {
mDiag->error(DiagMessage(outResource->source)
<< "invalid value for 'formatted'. Must be a boolean");
@@ -536,7 +536,7 @@
}
bool translateable = mOptions.translatable;
- if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) {
+ if (Maybe<StringPiece> translateableAttr = xml::findAttribute(parser, "translatable")) {
if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
mDiag->error(DiagMessage(outResource->source)
<< "invalid value for 'translatable'. Must be a boolean");
@@ -574,7 +574,7 @@
}
bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) {
- Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
+ Maybe<StringPiece> maybeType = xml::findNonEmptyAttribute(parser, "type");
if (!maybeType) {
mDiag->error(DiagMessage(outResource->source) << "<public> must have a 'type' attribute");
return false;
@@ -589,10 +589,10 @@
outResource->name.type = *parsedType;
- if (Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"id")) {
+ if (Maybe<StringPiece> maybeId = xml::findNonEmptyAttribute(parser, "id")) {
android::Res_value val;
- bool result = android::ResTable::stringToInt(maybeId.value().data(),
- maybeId.value().size(), &val);
+ std::u16string idStr16 = util::utf8ToUtf16(maybeId.value());
+ bool result = android::ResTable::stringToInt(idStr16.data(), idStr16.size(), &val);
ResourceId resourceId(val.data);
if (!result || !resourceId.isValid()) {
mDiag->error(DiagMessage(outResource->source)
@@ -612,7 +612,7 @@
}
bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) {
- Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
+ Maybe<StringPiece> maybeType = xml::findNonEmptyAttribute(parser, "type");
if (!maybeType) {
mDiag->error(DiagMessage(outResource->source)
<< "<public-group> must have a 'type' attribute");
@@ -626,7 +626,7 @@
return false;
}
- Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"first-id");
+ Maybe<StringPiece> maybeId = xml::findNonEmptyAttribute(parser, "first-id");
if (!maybeId) {
mDiag->error(DiagMessage(outResource->source)
<< "<public-group> must have a 'first-id' attribute");
@@ -634,8 +634,8 @@
}
android::Res_value val;
- bool result = android::ResTable::stringToInt(maybeId.value().data(),
- maybeId.value().size(), &val);
+ std::u16string idStr16 = util::utf8ToUtf16(maybeId.value());
+ bool result = android::ResTable::stringToInt(idStr16.data(), idStr16.size(), &val);
ResourceId nextId(val.data);
if (!result || !nextId.isValid()) {
mDiag->error(DiagMessage(outResource->source)
@@ -643,7 +643,7 @@
return false;
}
- std::u16string comment;
+ std::string comment;
bool error = false;
const size_t depth = parser->getDepth();
while (xml::XmlPullParser::nextChildNode(parser, depth)) {
@@ -656,23 +656,23 @@
}
const Source itemSource = mSource.withLine(parser->getLineNumber());
- const std::u16string& elementNamespace = parser->getElementNamespace();
- const std::u16string& elementName = parser->getElementName();
- if (elementNamespace.empty() && elementName == u"public") {
- Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+ const std::string& elementNamespace = parser->getElementNamespace();
+ const std::string& elementName = parser->getElementName();
+ if (elementNamespace.empty() && elementName == "public") {
+ Maybe<StringPiece> maybeName = xml::findNonEmptyAttribute(parser, "name");
if (!maybeName) {
mDiag->error(DiagMessage(itemSource) << "<public> must have a 'name' attribute");
error = true;
continue;
}
- if (xml::findNonEmptyAttribute(parser, u"id")) {
+ if (xml::findNonEmptyAttribute(parser, "id")) {
mDiag->error(DiagMessage(itemSource) << "'id' is ignored within <public-group>");
error = true;
continue;
}
- if (xml::findNonEmptyAttribute(parser, u"type")) {
+ if (xml::findNonEmptyAttribute(parser, "type")) {
mDiag->error(DiagMessage(itemSource) << "'type' is ignored within <public-group>");
error = true;
continue;
@@ -698,7 +698,7 @@
}
bool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) {
- Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
+ Maybe<StringPiece> maybeType = xml::findNonEmptyAttribute(parser, "type");
if (!maybeType) {
mDiag->error(DiagMessage(outResource->source)
<< "<" << parser->getElementName() << "> must have a 'type' attribute");
@@ -751,7 +751,7 @@
uint32_t typeMask = 0;
- Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format");
+ Maybe<StringPiece> maybeFormat = xml::findAttribute(parser, "format");
if (maybeFormat) {
typeMask = parseFormatAttribute(maybeFormat.value());
if (typeMask == 0) {
@@ -763,11 +763,12 @@
Maybe<int32_t> maybeMin, maybeMax;
- if (Maybe<StringPiece16> maybeMinStr = xml::findAttribute(parser, u"min")) {
- StringPiece16 minStr = util::trimWhitespace(maybeMinStr.value());
+ if (Maybe<StringPiece> maybeMinStr = xml::findAttribute(parser, "min")) {
+ StringPiece minStr = util::trimWhitespace(maybeMinStr.value());
if (!minStr.empty()) {
+ std::u16string minStr16 = util::utf8ToUtf16(minStr);
android::Res_value value;
- if (android::ResTable::stringToInt(minStr.data(), minStr.size(), &value)) {
+ if (android::ResTable::stringToInt(minStr16.data(), minStr16.size(), &value)) {
maybeMin = static_cast<int32_t>(value.data);
}
}
@@ -779,11 +780,12 @@
}
}
- if (Maybe<StringPiece16> maybeMaxStr = xml::findAttribute(parser, u"max")) {
- StringPiece16 maxStr = util::trimWhitespace(maybeMaxStr.value());
+ if (Maybe<StringPiece> maybeMaxStr = xml::findAttribute(parser, "max")) {
+ StringPiece maxStr = util::trimWhitespace(maybeMaxStr.value());
if (!maxStr.empty()) {
+ std::u16string maxStr16 = util::utf8ToUtf16(maxStr);
android::Res_value value;
- if (android::ResTable::stringToInt(maxStr.data(), maxStr.size(), &value)) {
+ if (android::ResTable::stringToInt(maxStr16.data(), maxStr16.size(), &value)) {
maybeMax = static_cast<int32_t>(value.data);
}
}
@@ -809,7 +811,7 @@
std::set<Attribute::Symbol, SymbolComparator> items;
- std::u16string comment;
+ std::string comment;
bool error = false;
const size_t depth = parser->getDepth();
while (xml::XmlPullParser::nextChildNode(parser, depth)) {
@@ -822,10 +824,10 @@
}
const Source itemSource = mSource.withLine(parser->getLineNumber());
- const std::u16string& elementNamespace = parser->getElementNamespace();
- const std::u16string& elementName = parser->getElementName();
- if (elementNamespace.empty() && (elementName == u"flag" || elementName == u"enum")) {
- if (elementName == u"enum") {
+ const std::string& elementNamespace = parser->getElementNamespace();
+ const std::string& elementName = parser->getElementName();
+ if (elementNamespace.empty() && (elementName == "flag" || elementName == "enum")) {
+ if (elementName == "enum") {
if (typeMask & android::ResTable_map::TYPE_FLAGS) {
mDiag->error(DiagMessage(itemSource)
<< "can not define an <enum>; already defined a <flag>");
@@ -834,7 +836,7 @@
}
typeMask |= android::ResTable_map::TYPE_ENUM;
- } else if (elementName == u"flag") {
+ } else if (elementName == "flag") {
if (typeMask & android::ResTable_map::TYPE_ENUM) {
mDiag->error(DiagMessage(itemSource)
<< "can not define a <flag>; already defined an <enum>");
@@ -896,24 +898,24 @@
}
Maybe<Attribute::Symbol> ResourceParser::parseEnumOrFlagItem(xml::XmlPullParser* parser,
- const StringPiece16& tag) {
+ const StringPiece& tag) {
const Source source = mSource.withLine(parser->getLineNumber());
- Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+ Maybe<StringPiece> maybeName = xml::findNonEmptyAttribute(parser, "name");
if (!maybeName) {
mDiag->error(DiagMessage(source) << "no attribute 'name' found for tag <" << tag << ">");
return {};
}
- Maybe<StringPiece16> maybeValue = xml::findNonEmptyAttribute(parser, u"value");
+ Maybe<StringPiece> maybeValue = xml::findNonEmptyAttribute(parser, "value");
if (!maybeValue) {
mDiag->error(DiagMessage(source) << "no attribute 'value' found for tag <" << tag << ">");
return {};
}
+ std::u16string value16 = util::utf8ToUtf16(maybeValue.value());
android::Res_value val;
- if (!android::ResTable::stringToInt(maybeValue.value().data(),
- maybeValue.value().size(), &val)) {
+ if (!android::ResTable::stringToInt(value16.data(), value16.size(), &val)) {
mDiag->error(DiagMessage(source) << "invalid value '" << maybeValue.value()
<< "' for <" << tag << ">; must be an integer");
return {};
@@ -923,25 +925,25 @@
Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())), val.data };
}
-static Maybe<Reference> parseXmlAttributeName(StringPiece16 str) {
+static Maybe<Reference> parseXmlAttributeName(StringPiece str) {
str = util::trimWhitespace(str);
- const char16_t* start = str.data();
- const char16_t* const end = start + str.size();
- const char16_t* p = start;
+ const char* start = str.data();
+ const char* const end = start + str.size();
+ const char* p = start;
Reference ref;
- if (p != end && *p == u'*') {
+ if (p != end && *p == '*') {
ref.privateReference = true;
start++;
p++;
}
- StringPiece16 package;
- StringPiece16 name;
+ StringPiece package;
+ StringPiece name;
while (p != end) {
- if (*p == u':') {
- package = StringPiece16(start, p - start);
- name = StringPiece16(p + 1, end - (p + 1));
+ if (*p == ':') {
+ package = StringPiece(start, p - start);
+ name = StringPiece(p + 1, end - (p + 1));
break;
}
p++;
@@ -955,7 +957,7 @@
bool ResourceParser::parseStyleItem(xml::XmlPullParser* parser, Style* style) {
const Source source = mSource.withLine(parser->getLineNumber());
- Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+ Maybe<StringPiece> maybeName = xml::findNonEmptyAttribute(parser, "name");
if (!maybeName) {
mDiag->error(DiagMessage(source) << "<item> must have a 'name' attribute");
return false;
@@ -967,7 +969,7 @@
return false;
}
- transformReferenceFromNamespace(parser, u"", &maybeKey.value());
+ transformReferenceFromNamespace(parser, "", &maybeKey.value());
maybeKey.value().setSource(source);
std::unique_ptr<Item> value = parseXml(parser, 0, kAllowRawString);
@@ -985,7 +987,7 @@
std::unique_ptr<Style> style = util::make_unique<Style>();
- Maybe<StringPiece16> maybeParent = xml::findAttribute(parser, u"parent");
+ Maybe<StringPiece> maybeParent = xml::findAttribute(parser, "parent");
if (maybeParent) {
// If the parent is empty, we don't have a parent, but we also don't infer either.
if (!maybeParent.value().empty()) {
@@ -998,12 +1000,12 @@
// Transform the namespace prefix to the actual package name, and mark the reference as
// private if appropriate.
- transformReferenceFromNamespace(parser, u"", &style->parent.value());
+ transformReferenceFromNamespace(parser, "", &style->parent.value());
}
} else {
// No parent was specified, so try inferring it from the style name.
- std::u16string styleName = outResource->name.entry;
+ std::string styleName = outResource->name.entry;
size_t pos = styleName.find_last_of(u'.');
if (pos != std::string::npos) {
style->parentInferred = true;
@@ -1020,9 +1022,9 @@
continue;
}
- const std::u16string& elementNamespace = parser->getElementNamespace();
- const std::u16string& elementName = parser->getElementName();
- if (elementNamespace == u"" && elementName == u"item") {
+ const std::string& elementNamespace = parser->getElementNamespace();
+ const std::string& elementName = parser->getElementName();
+ if (elementNamespace == "" && elementName == "item") {
error |= !parseStyleItem(parser, style.get());
} else if (!shouldIgnoreElement(elementNamespace, elementName)) {
@@ -1059,7 +1061,7 @@
std::unique_ptr<Array> array = util::make_unique<Array>();
bool translateable = mOptions.translatable;
- if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) {
+ if (Maybe<StringPiece> translateableAttr = xml::findAttribute(parser, "translatable")) {
if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
mDiag->error(DiagMessage(outResource->source)
<< "invalid value for 'translatable'. Must be a boolean");
@@ -1077,9 +1079,9 @@
}
const Source itemSource = mSource.withLine(parser->getLineNumber());
- const std::u16string& elementNamespace = parser->getElementNamespace();
- const std::u16string& elementName = parser->getElementName();
- if (elementNamespace.empty() && elementName == u"item") {
+ const std::string& elementNamespace = parser->getElementNamespace();
+ const std::string& elementName = parser->getElementName();
+ if (elementNamespace.empty() && elementName == "item") {
std::unique_ptr<Item> item = parseXml(parser, typeMask, kNoRawString);
if (!item) {
mDiag->error(DiagMessage(itemSource) << "could not parse array item");
@@ -1118,10 +1120,10 @@
}
const Source itemSource = mSource.withLine(parser->getLineNumber());
- const std::u16string& elementNamespace = parser->getElementNamespace();
- const std::u16string& elementName = parser->getElementName();
- if (elementNamespace.empty() && elementName == u"item") {
- Maybe<StringPiece16> maybeQuantity = xml::findNonEmptyAttribute(parser, u"quantity");
+ const std::string& elementNamespace = parser->getElementNamespace();
+ const std::string& elementName = parser->getElementName();
+ if (elementNamespace.empty() && elementName == "item") {
+ Maybe<StringPiece> maybeQuantity = xml::findNonEmptyAttribute(parser, "quantity");
if (!maybeQuantity) {
mDiag->error(DiagMessage(itemSource) << "<item> in <plurals> requires attribute "
<< "'quantity'");
@@ -1129,19 +1131,19 @@
continue;
}
- StringPiece16 trimmedQuantity = util::trimWhitespace(maybeQuantity.value());
+ StringPiece trimmedQuantity = util::trimWhitespace(maybeQuantity.value());
size_t index = 0;
- if (trimmedQuantity == u"zero") {
+ if (trimmedQuantity == "zero") {
index = Plural::Zero;
- } else if (trimmedQuantity == u"one") {
+ } else if (trimmedQuantity == "one") {
index = Plural::One;
- } else if (trimmedQuantity == u"two") {
+ } else if (trimmedQuantity == "two") {
index = Plural::Two;
- } else if (trimmedQuantity == u"few") {
+ } else if (trimmedQuantity == "few") {
index = Plural::Few;
- } else if (trimmedQuantity == u"many") {
+ } else if (trimmedQuantity == "many") {
index = Plural::Many;
- } else if (trimmedQuantity == u"other") {
+ } else if (trimmedQuantity == "other") {
index = Plural::Other;
} else {
mDiag->error(DiagMessage(itemSource)
@@ -1196,7 +1198,7 @@
std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
- std::u16string comment;
+ std::string comment;
bool error = false;
const size_t depth = parser->getDepth();
while (xml::XmlPullParser::nextChildNode(parser, depth)) {
@@ -1209,10 +1211,10 @@
}
const Source itemSource = mSource.withLine(parser->getLineNumber());
- const std::u16string& elementNamespace = parser->getElementNamespace();
- const std::u16string& elementName = parser->getElementName();
- if (elementNamespace.empty() && elementName == u"attr") {
- Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+ const std::string& elementNamespace = parser->getElementNamespace();
+ const std::string& elementName = parser->getElementName();
+ if (elementNamespace.empty() && elementName == "attr") {
+ Maybe<StringPiece> maybeName = xml::findNonEmptyAttribute(parser, "name");
if (!maybeName) {
mDiag->error(DiagMessage(itemSource) << "<attr> tag must have a 'name' attribute");
error = true;
@@ -1230,7 +1232,7 @@
}
Reference& childRef = maybeRef.value();
- xml::transformReferenceFromNamespace(parser, u"", &childRef);
+ xml::transformReferenceFromNamespace(parser, "", &childRef);
// Create the ParsedResource that will add the attribute to the table.
ParsedResource childResource;
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index ee5b337..ece3090 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -63,7 +63,7 @@
* contains the escaped and whitespace trimmed text, while `outRawString`
* contains the unescaped text. Returns true on success.
*/
- bool flattenXmlSubtree(xml::XmlPullParser* parser, std::u16string* outRawString,
+ bool flattenXmlSubtree(xml::XmlPullParser* parser, std::string* outRawString,
StyleString* outStyleString);
/*
@@ -89,7 +89,7 @@
bool parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource, bool weak);
Maybe<Attribute::Symbol> parseEnumOrFlagItem(xml::XmlPullParser* parser,
- const StringPiece16& tag);
+ const StringPiece& tag);
bool parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parseStyleItem(xml::XmlPullParser* parser, Style* style);
bool parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 3450de9..b456c04 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -18,10 +18,9 @@
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
-#include "test/Context.h"
+#include "test/Test.h"
#include "xml/XmlPullParser.h"
-#include <gtest/gtest.h>
#include <sstream>
#include <string>
@@ -69,18 +68,18 @@
std::string input = "<string name=\"foo\"> \" hey there \" </string>";
ASSERT_TRUE(testParse(input));
- String* str = test::getValue<String>(&mTable, u"@string/foo");
+ String* str = test::getValue<String>(&mTable, "@string/foo");
ASSERT_NE(nullptr, str);
- EXPECT_EQ(std::u16string(u" hey there "), *str->value);
+ EXPECT_EQ(std::string(" hey there "), *str->value);
}
TEST_F(ResourceParserTest, ParseEscapedString) {
std::string input = "<string name=\"foo\">\\?123</string>";
ASSERT_TRUE(testParse(input));
- String* str = test::getValue<String>(&mTable, u"@string/foo");
+ String* str = test::getValue<String>(&mTable, "@string/foo");
ASSERT_NE(nullptr, str);
- EXPECT_EQ(std::u16string(u"?123"), *str->value);
+ EXPECT_EQ(std::string("?123"), *str->value);
}
TEST_F(ResourceParserTest, ParseFormattedString) {
@@ -97,9 +96,9 @@
" There are <xliff:g id=\"count\">%1$d</xliff:g> apples</string>";
ASSERT_TRUE(testParse(input));
- String* str = test::getValue<String>(&mTable, u"@string/foo");
+ String* str = test::getValue<String>(&mTable, "@string/foo");
ASSERT_NE(nullptr, str);
- EXPECT_EQ(StringPiece16(u"There are %1$d apples"), StringPiece16(*str->value));
+ EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value));
}
TEST_F(ResourceParserTest, ParseNull) {
@@ -110,7 +109,7 @@
// a non-existing value, and this causes problems in styles when trying to resolve
// an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
// with a data value of 0.
- BinaryPrimitive* integer = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo");
+ BinaryPrimitive* integer = test::getValue<BinaryPrimitive>(&mTable, "@integer/foo");
ASSERT_NE(nullptr, integer);
EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE), integer->value.dataType);
EXPECT_EQ(0u, integer->value.data);
@@ -120,7 +119,7 @@
std::string input = "<integer name=\"foo\">@empty</integer>";
ASSERT_TRUE(testParse(input));
- BinaryPrimitive* integer = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo");
+ BinaryPrimitive* integer = test::getValue<BinaryPrimitive>(&mTable, "@integer/foo");
ASSERT_NE(nullptr, integer);
EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType);
EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data);
@@ -131,11 +130,11 @@
"<attr name=\"bar\"/>";
ASSERT_TRUE(testParse(input));
- Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* attr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->typeMask);
- attr = test::getValue<Attribute>(&mTable, u"@attr/bar");
+ attr = test::getValue<Attribute>(&mTable, "@attr/bar");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask);
}
@@ -151,20 +150,20 @@
</declare-styleable>)EOF";
ASSERT_TRUE(testParse(input, watchConfig));
- EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, u"@attr/foo", watchConfig));
- EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, u"@attr/baz", watchConfig));
- EXPECT_EQ(nullptr, test::getValueForConfig<Styleable>(&mTable, u"@styleable/bar", watchConfig));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, "@attr/foo", watchConfig));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, "@attr/baz", watchConfig));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Styleable>(&mTable, "@styleable/bar", watchConfig));
- EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, u"@attr/foo"));
- EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, u"@attr/baz"));
- EXPECT_NE(nullptr, test::getValue<Styleable>(&mTable, u"@styleable/bar"));
+ EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, "@attr/foo"));
+ EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, "@attr/baz"));
+ EXPECT_NE(nullptr, test::getValue<Styleable>(&mTable, "@styleable/bar"));
}
TEST_F(ResourceParserTest, ParseAttrWithMinMax) {
std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
ASSERT_TRUE(testParse(input));
- Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* attr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->typeMask);
EXPECT_EQ(10, attr->minInt);
@@ -183,7 +182,7 @@
"<attr name=\"foo\" format=\"string\"/>";
ASSERT_TRUE(testParse(input));
- Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* attr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->typeMask);
}
@@ -197,7 +196,7 @@
"</declare-styleable>";
ASSERT_TRUE(testParse(input));
- Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* attr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->typeMask);
}
@@ -210,21 +209,21 @@
"</attr>";
ASSERT_TRUE(testParse(input));
- Attribute* enumAttr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* enumAttr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(enumAttr, nullptr);
EXPECT_EQ(enumAttr->typeMask, android::ResTable_map::TYPE_ENUM);
ASSERT_EQ(enumAttr->symbols.size(), 3u);
AAPT_ASSERT_TRUE(enumAttr->symbols[0].symbol.name);
- EXPECT_EQ(enumAttr->symbols[0].symbol.name.value().entry, u"bar");
+ EXPECT_EQ(enumAttr->symbols[0].symbol.name.value().entry, "bar");
EXPECT_EQ(enumAttr->symbols[0].value, 0u);
AAPT_ASSERT_TRUE(enumAttr->symbols[1].symbol.name);
- EXPECT_EQ(enumAttr->symbols[1].symbol.name.value().entry, u"bat");
+ EXPECT_EQ(enumAttr->symbols[1].symbol.name.value().entry, "bat");
EXPECT_EQ(enumAttr->symbols[1].value, 1u);
AAPT_ASSERT_TRUE(enumAttr->symbols[2].symbol.name);
- EXPECT_EQ(enumAttr->symbols[2].symbol.name.value().entry, u"baz");
+ EXPECT_EQ(enumAttr->symbols[2].symbol.name.value().entry, "baz");
EXPECT_EQ(enumAttr->symbols[2].value, 2u);
}
@@ -236,25 +235,25 @@
"</attr>";
ASSERT_TRUE(testParse(input));
- Attribute* flagAttr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* flagAttr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(nullptr, flagAttr);
EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS);
ASSERT_EQ(flagAttr->symbols.size(), 3u);
AAPT_ASSERT_TRUE(flagAttr->symbols[0].symbol.name);
- EXPECT_EQ(flagAttr->symbols[0].symbol.name.value().entry, u"bar");
+ EXPECT_EQ(flagAttr->symbols[0].symbol.name.value().entry, "bar");
EXPECT_EQ(flagAttr->symbols[0].value, 0u);
AAPT_ASSERT_TRUE(flagAttr->symbols[1].symbol.name);
- EXPECT_EQ(flagAttr->symbols[1].symbol.name.value().entry, u"bat");
+ EXPECT_EQ(flagAttr->symbols[1].symbol.name.value().entry, "bat");
EXPECT_EQ(flagAttr->symbols[1].value, 1u);
AAPT_ASSERT_TRUE(flagAttr->symbols[2].symbol.name);
- EXPECT_EQ(flagAttr->symbols[2].symbol.name.value().entry, u"baz");
+ EXPECT_EQ(flagAttr->symbols[2].symbol.name.value().entry, "baz");
EXPECT_EQ(flagAttr->symbols[2].value, 2u);
std::unique_ptr<BinaryPrimitive> flagValue = ResourceUtils::tryParseFlagSymbol(flagAttr,
- u"baz|bat");
+ "baz|bat");
ASSERT_NE(nullptr, flagValue);
EXPECT_EQ(flagValue->value.data, 1u | 2u);
}
@@ -276,32 +275,32 @@
"</style>";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo");
ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
- EXPECT_EQ(test::parseNameOrDie(u"@style/fu"), style->parent.value().name.value());
+ EXPECT_EQ(test::parseNameOrDie("@style/fu"), style->parent.value().name.value());
ASSERT_EQ(3u, style->entries.size());
AAPT_ASSERT_TRUE(style->entries[0].key.name);
- EXPECT_EQ(test::parseNameOrDie(u"@attr/bar"), style->entries[0].key.name.value());
+ EXPECT_EQ(test::parseNameOrDie("@attr/bar"), style->entries[0].key.name.value());
AAPT_ASSERT_TRUE(style->entries[1].key.name);
- EXPECT_EQ(test::parseNameOrDie(u"@attr/bat"), style->entries[1].key.name.value());
+ EXPECT_EQ(test::parseNameOrDie("@attr/bat"), style->entries[1].key.name.value());
AAPT_ASSERT_TRUE(style->entries[2].key.name);
- EXPECT_EQ(test::parseNameOrDie(u"@attr/baz"), style->entries[2].key.name.value());
+ EXPECT_EQ(test::parseNameOrDie("@attr/baz"), style->entries[2].key.name.value());
}
TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo");
ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
- EXPECT_EQ(test::parseNameOrDie(u"@com.app:style/Theme"), style->parent.value().name.value());
+ EXPECT_EQ(test::parseNameOrDie("@com.app:style/Theme"), style->parent.value().name.value());
}
TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
@@ -309,11 +308,11 @@
" name=\"foo\" parent=\"app:Theme\"/>";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo");
ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
- EXPECT_EQ(test::parseNameOrDie(u"@android:style/Theme"), style->parent.value().name.value());
+ EXPECT_EQ(test::parseNameOrDie("@android:style/Theme"), style->parent.value().name.value());
}
TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
@@ -323,21 +322,21 @@
"</style>";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo");
ASSERT_NE(nullptr, style);
ASSERT_EQ(1u, style->entries.size());
- EXPECT_EQ(test::parseNameOrDie(u"@android:attr/bar"), style->entries[0].key.name.value());
+ EXPECT_EQ(test::parseNameOrDie("@android:attr/bar"), style->entries[0].key.name.value());
}
TEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
std::string input = "<style name=\"foo.bar\"/>";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo.bar");
ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
- EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie(u"@style/foo"));
+ EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie("@style/foo"));
EXPECT_TRUE(style->parentInferred);
}
@@ -345,7 +344,7 @@
std::string input = "<style name=\"foo.bar\" parent=\"\"/>";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo.bar");
ASSERT_NE(nullptr, style);
AAPT_EXPECT_FALSE(style->parent);
EXPECT_FALSE(style->parentInferred);
@@ -355,7 +354,7 @@
std::string input = R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
ASSERT_TRUE(testParse(input));
- Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ Style* style = test::getValue<Style>(&mTable, "@style/foo");
ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
EXPECT_TRUE(style->parent.value().privateReference);
@@ -365,7 +364,7 @@
std::string input = "<string name=\"foo\">@+id/bar</string>";
ASSERT_TRUE(testParse(input));
- Id* id = test::getValue<Id>(&mTable, u"@id/bar");
+ Id* id = test::getValue<Id>(&mTable, "@id/bar");
ASSERT_NE(id, nullptr);
}
@@ -380,31 +379,31 @@
ASSERT_TRUE(testParse(input));
Maybe<ResourceTable::SearchResult> result =
- mTable.findResource(test::parseNameOrDie(u"@styleable/foo"));
+ mTable.findResource(test::parseNameOrDie("@styleable/foo"));
AAPT_ASSERT_TRUE(result);
EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state);
- Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/bar");
+ Attribute* attr = test::getValue<Attribute>(&mTable, "@attr/bar");
ASSERT_NE(attr, nullptr);
EXPECT_TRUE(attr->isWeak());
- attr = test::getValue<Attribute>(&mTable, u"@attr/bat");
+ attr = test::getValue<Attribute>(&mTable, "@attr/bat");
ASSERT_NE(attr, nullptr);
EXPECT_TRUE(attr->isWeak());
- attr = test::getValue<Attribute>(&mTable, u"@attr/baz");
+ attr = test::getValue<Attribute>(&mTable, "@attr/baz");
ASSERT_NE(attr, nullptr);
EXPECT_TRUE(attr->isWeak());
EXPECT_EQ(1u, attr->symbols.size());
- EXPECT_NE(nullptr, test::getValue<Id>(&mTable, u"@id/foo"));
+ EXPECT_NE(nullptr, test::getValue<Id>(&mTable, "@id/foo"));
- Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo");
+ Styleable* styleable = test::getValue<Styleable>(&mTable, "@styleable/foo");
ASSERT_NE(styleable, nullptr);
ASSERT_EQ(3u, styleable->entries.size());
- EXPECT_EQ(test::parseNameOrDie(u"@attr/bar"), styleable->entries[0].name.value());
- EXPECT_EQ(test::parseNameOrDie(u"@attr/bat"), styleable->entries[1].name.value());
+ EXPECT_EQ(test::parseNameOrDie("@attr/bar"), styleable->entries[0].name.value());
+ EXPECT_EQ(test::parseNameOrDie("@attr/bat"), styleable->entries[1].name.value());
}
TEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
@@ -413,17 +412,17 @@
" <attr name=\"privAndroid:bat\" />\n"
"</declare-styleable>";
ASSERT_TRUE(testParse(input));
- Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo");
+ Styleable* styleable = test::getValue<Styleable>(&mTable, "@styleable/foo");
ASSERT_NE(nullptr, styleable);
ASSERT_EQ(2u, styleable->entries.size());
EXPECT_TRUE(styleable->entries[0].privateReference);
AAPT_ASSERT_TRUE(styleable->entries[0].name);
- EXPECT_EQ(std::u16string(u"android"), styleable->entries[0].name.value().package);
+ EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package);
EXPECT_TRUE(styleable->entries[1].privateReference);
AAPT_ASSERT_TRUE(styleable->entries[1].name);
- EXPECT_EQ(std::u16string(u"android"), styleable->entries[1].name.value().package);
+ EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package);
}
TEST_F(ResourceParserTest, ParseArray) {
@@ -434,7 +433,7 @@
"</array>";
ASSERT_TRUE(testParse(input));
- Array* array = test::getValue<Array>(&mTable, u"@array/foo");
+ Array* array = test::getValue<Array>(&mTable, "@array/foo");
ASSERT_NE(array, nullptr);
ASSERT_EQ(3u, array->items.size());
@@ -448,7 +447,7 @@
" <item>\"Werk\"</item>\n"
"</string-array>\n";
ASSERT_TRUE(testParse(input));
- EXPECT_NE(nullptr, test::getValue<Array>(&mTable, u"@array/foo"));
+ EXPECT_NE(nullptr, test::getValue<Array>(&mTable, "@array/foo"));
}
TEST_F(ResourceParserTest, ParsePlural) {
@@ -464,9 +463,9 @@
"<string name=\"foo\">Hi</string>";
ASSERT_TRUE(testParse(input));
- String* value = test::getValue<String>(&mTable, u"@string/foo");
+ String* value = test::getValue<String>(&mTable, "@string/foo");
ASSERT_NE(nullptr, value);
- EXPECT_EQ(value->getComment(), u"This is a comment");
+ EXPECT_EQ(value->getComment(), "This is a comment");
}
TEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
@@ -476,9 +475,9 @@
ASSERT_TRUE(testParse(input));
- String* value = test::getValue<String>(&mTable, u"@string/foo");
+ String* value = test::getValue<String>(&mTable, "@string/foo");
ASSERT_NE(nullptr, value);
- EXPECT_EQ(value->getComment(), u"Two");
+ EXPECT_EQ(value->getComment(), "Two");
}
TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
@@ -490,9 +489,9 @@
ASSERT_TRUE(testParse(input));
- String* value = test::getValue<String>(&mTable, u"@string/foo");
+ String* value = test::getValue<String>(&mTable, "@string/foo");
ASSERT_NE(nullptr, value);
- EXPECT_EQ(value->getComment(), u"One");
+ EXPECT_EQ(value->getComment(), "One");
}
TEST_F(ResourceParserTest, ParseNestedComments) {
@@ -510,17 +509,17 @@
</attr>)EOF";
ASSERT_TRUE(testParse(input));
- Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo");
+ Styleable* styleable = test::getValue<Styleable>(&mTable, "@styleable/foo");
ASSERT_NE(nullptr, styleable);
ASSERT_EQ(1u, styleable->entries.size());
- EXPECT_EQ(StringPiece16(u"The name of the bar"), styleable->entries.front().getComment());
+ EXPECT_EQ(StringPiece("The name of the bar"), styleable->entries.front().getComment());
- Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo");
+ Attribute* attr = test::getValue<Attribute>(&mTable, "@attr/foo");
ASSERT_NE(nullptr, attr);
ASSERT_EQ(1u, attr->symbols.size());
- EXPECT_EQ(StringPiece16(u"The very first"), attr->symbols.front().symbol.getComment());
+ EXPECT_EQ(StringPiece("The very first"), attr->symbols.front().symbol.getComment());
}
/*
@@ -531,7 +530,7 @@
std::string input = "<public type=\"id\" name=\"foo\"/>";
ASSERT_TRUE(testParse(input));
- Id* id = test::getValue<Id>(&mTable, u"@id/foo");
+ Id* id = test::getValue<Id>(&mTable, "@id/foo");
ASSERT_NE(nullptr, id);
}
@@ -546,22 +545,22 @@
)EOF";
ASSERT_TRUE(testParse(input));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/foo",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, "@string/foo",
ConfigDescription::defaultConfig(),
"phone"));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/foo",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, "@string/foo",
ConfigDescription::defaultConfig(),
"no-sdcard"));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/bar",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, "@string/bar",
ConfigDescription::defaultConfig(),
""));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/baz",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, "@string/baz",
ConfigDescription::defaultConfig(),
""));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/bit",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, "@string/bit",
ConfigDescription::defaultConfig(),
"phablet"));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/bot",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, "@string/bot",
ConfigDescription::defaultConfig(),
"default"));
}
@@ -575,7 +574,7 @@
ASSERT_TRUE(testParse(input));
Maybe<ResourceTable::SearchResult> result = mTable.findResource(
- test::parseNameOrDie(u"@attr/foo"));
+ test::parseNameOrDie("@attr/foo"));
AAPT_ASSERT_TRUE(result);
AAPT_ASSERT_TRUE(result.value().package->id);
@@ -586,7 +585,7 @@
result.value().entry->id.value());
EXPECT_EQ(ResourceId(0x01010040), actualId);
- result = mTable.findResource(test::parseNameOrDie(u"@attr/bar"));
+ result = mTable.findResource(test::parseNameOrDie("@attr/bar"));
AAPT_ASSERT_TRUE(result);
AAPT_ASSERT_TRUE(result.value().package->id);
@@ -611,7 +610,7 @@
ASSERT_TRUE(testParse(input));
Maybe<ResourceTable::SearchResult> result = mTable.findResource(
- test::parseNameOrDie(u"@string/bar"));
+ test::parseNameOrDie("@string/bar"));
AAPT_ASSERT_TRUE(result);
const ResourceEntry* entry = result.value().entry;
ASSERT_NE(nullptr, entry);
@@ -622,7 +621,7 @@
std::string input = R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
ASSERT_TRUE(testParse(input));
- BinaryPrimitive* val = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo");
+ BinaryPrimitive* val = test::getValue<BinaryPrimitive>(&mTable, "@integer/foo");
ASSERT_NE(nullptr, val);
EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index e700ed9..4d418d9 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -35,11 +35,11 @@
template <typename T>
static bool lessThanStructWithName(const std::unique_ptr<T>& lhs,
- const StringPiece16& rhs) {
+ const StringPiece& rhs) {
return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
}
-ResourceTablePackage* ResourceTable::findPackage(const StringPiece16& name) {
+ResourceTablePackage* ResourceTable::findPackage(const StringPiece& name) {
const auto last = packages.end();
auto iter = std::lower_bound(packages.begin(), last, name,
lessThanStructWithName<ResourceTablePackage>);
@@ -58,7 +58,7 @@
return nullptr;
}
-ResourceTablePackage* ResourceTable::createPackage(const StringPiece16& name, Maybe<uint8_t> id) {
+ResourceTablePackage* ResourceTable::createPackage(const StringPiece& name, Maybe<uint8_t> id) {
ResourceTablePackage* package = findOrCreatePackage(name);
if (id && !package->id) {
package->id = id;
@@ -71,7 +71,7 @@
return package;
}
-ResourceTablePackage* ResourceTable::findOrCreatePackage(const StringPiece16& name) {
+ResourceTablePackage* ResourceTable::findOrCreatePackage(const StringPiece& name) {
const auto last = packages.end();
auto iter = std::lower_bound(packages.begin(), last, name,
lessThanStructWithName<ResourceTablePackage>);
@@ -102,7 +102,7 @@
return types.emplace(iter, new ResourceTableType(type))->get();
}
-ResourceEntry* ResourceTableType::findEntry(const StringPiece16& name) {
+ResourceEntry* ResourceTableType::findEntry(const StringPiece& name) {
const auto last = entries.end();
auto iter = std::lower_bound(entries.begin(), last, name,
lessThanStructWithName<ResourceEntry>);
@@ -112,7 +112,7 @@
return nullptr;
}
-ResourceEntry* ResourceTableType::findOrCreateEntry(const StringPiece16& name) {
+ResourceEntry* ResourceTableType::findOrCreateEntry(const StringPiece& name) {
auto last = entries.end();
auto iter = std::lower_bound(entries.begin(), last, name,
lessThanStructWithName<ResourceEntry>);
@@ -261,8 +261,8 @@
return 0;
}
-static constexpr const char16_t* kValidNameChars = u"._-";
-static constexpr const char16_t* kValidNameMangledChars = u"._-$";
+static constexpr const char* kValidNameChars = "._-";
+static constexpr const char* kValidNameMangledChars = "._-$";
bool ResourceTable::addResource(const ResourceNameRef& name,
const ConfigDescription& config,
@@ -286,7 +286,7 @@
bool ResourceTable::addFileReference(const ResourceNameRef& name,
const ConfigDescription& config,
const Source& source,
- const StringPiece16& path,
+ const StringPiece& path,
IDiagnostics* diag) {
return addFileReferenceImpl(name, config, source, path, nullptr, kValidNameChars, diag);
}
@@ -294,7 +294,7 @@
bool ResourceTable::addFileReferenceAllowMangled(const ResourceNameRef& name,
const ConfigDescription& config,
const Source& source,
- const StringPiece16& path,
+ const StringPiece& path,
io::IFile* file,
IDiagnostics* diag) {
return addFileReferenceImpl(name, config, source, path, file, kValidNameMangledChars, diag);
@@ -303,9 +303,9 @@
bool ResourceTable::addFileReferenceImpl(const ResourceNameRef& name,
const ConfigDescription& config,
const Source& source,
- const StringPiece16& path,
+ const StringPiece& path,
io::IFile* file,
- const char16_t* validChars,
+ const char* validChars,
IDiagnostics* diag) {
std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
stringPool.makeRef(path));
@@ -339,7 +339,7 @@
const ConfigDescription& config,
const StringPiece& product,
std::unique_ptr<Value> value,
- const char16_t* validChars,
+ const char* validChars,
std::function<int(Value*,Value*)> conflictResolver,
IDiagnostics* diag) {
assert(value && "value can't be nullptr");
@@ -353,7 +353,7 @@
<< "' has invalid entry name '"
<< name.entry
<< "'. Invalid character '"
- << StringPiece16(badCharIter, 1)
+ << StringPiece(badCharIter, 1)
<< "'");
return false;
}
@@ -438,7 +438,7 @@
}
bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
- const Symbol& symbol, const char16_t* validChars,
+ const Symbol& symbol, const char* validChars,
IDiagnostics* diag) {
assert(diag && "diagnostics can't be nullptr");
@@ -450,7 +450,7 @@
<< "' has invalid entry name '"
<< name.entry
<< "'. Invalid character '"
- << StringPiece16(badCharIter, 1)
+ << StringPiece(badCharIter, 1)
<< "'");
return false;
}
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 5690ea6..a5efe35 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -48,7 +48,7 @@
struct Symbol {
SymbolState state = SymbolState::kUndefined;
Source source;
- std::u16string comment;
+ std::string comment;
};
class ResourceConfigValue {
@@ -86,7 +86,7 @@
* this determines the order of this resource
* when doing lookups.
*/
- const std::u16string name;
+ const std::string name;
/**
* The entry ID for this resource.
@@ -103,7 +103,7 @@
*/
std::vector<std::unique_ptr<ResourceConfigValue>> values;
- ResourceEntry(const StringPiece16& name) : name(name.toString()) { }
+ ResourceEntry(const StringPiece& name) : name(name.toString()) { }
ResourceConfigValue* findValue(const ConfigDescription& config);
ResourceConfigValue* findValue(const ConfigDescription& config, const StringPiece& product);
@@ -147,8 +147,8 @@
explicit ResourceTableType(const ResourceType type) : type(type) { }
- ResourceEntry* findEntry(const StringPiece16& name);
- ResourceEntry* findOrCreateEntry(const StringPiece16& name);
+ ResourceEntry* findEntry(const StringPiece& name);
+ ResourceEntry* findOrCreateEntry(const StringPiece& name);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
@@ -165,7 +165,7 @@
public:
PackageType type = PackageType::App;
Maybe<uint8_t> id;
- std::u16string name;
+ std::string name;
std::vector<std::unique_ptr<ResourceTableType>> types;
@@ -209,13 +209,13 @@
bool addFileReference(const ResourceNameRef& name,
const ConfigDescription& config,
const Source& source,
- const StringPiece16& path,
+ const StringPiece& path,
IDiagnostics* diag);
bool addFileReferenceAllowMangled(const ResourceNameRef& name,
const ConfigDescription& config,
const Source& source,
- const StringPiece16& path,
+ const StringPiece& path,
io::IFile* file,
IDiagnostics* diag);
@@ -276,21 +276,21 @@
* exist. The empty string is a valid package and typically is used to represent the
* 'current' package before it is known to the ResourceTable.
*/
- ResourceTablePackage* findPackage(const StringPiece16& name);
+ ResourceTablePackage* findPackage(const StringPiece& name);
ResourceTablePackage* findPackageById(uint8_t id);
- ResourceTablePackage* createPackage(const StringPiece16& name, Maybe<uint8_t> id = {});
+ ResourceTablePackage* createPackage(const StringPiece& name, Maybe<uint8_t> id = {});
private:
- ResourceTablePackage* findOrCreatePackage(const StringPiece16& name);
+ ResourceTablePackage* findOrCreatePackage(const StringPiece& name);
bool addFileReferenceImpl(const ResourceNameRef& name,
const ConfigDescription& config,
const Source& source,
- const StringPiece16& path,
+ const StringPiece& path,
io::IFile* file,
- const char16_t* validChars,
+ const char* validChars,
IDiagnostics* diag);
bool addResourceImpl(const ResourceNameRef& name,
@@ -298,14 +298,14 @@
const ConfigDescription& config,
const StringPiece& product,
std::unique_ptr<Value> value,
- const char16_t* validChars,
+ const char* validChars,
std::function<int(Value*,Value*)> conflictResolver,
IDiagnostics* diag);
bool setSymbolStateImpl(const ResourceNameRef& name,
ResourceId resId,
const Symbol& symbol,
- const char16_t* validChars,
+ const char* validChars,
IDiagnostics* diag);
DISALLOW_COPY_AND_ASSIGN(ResourceTable);
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index d6c52ab..cf6660c 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -17,12 +17,10 @@
#include "Diagnostics.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
+#include "test/Test.h"
#include "util/Util.h"
-#include "test/Builders.h"
-
#include <algorithm>
-#include <gtest/gtest.h>
#include <ostream>
#include <string>
@@ -32,13 +30,13 @@
ResourceTable table;
EXPECT_FALSE(table.addResource(
- ResourceNameRef(u"android", ResourceType::kId, u"hey,there"),
+ test::parseNameOrDie("@android:id/hey,there"),
ConfigDescription{}, "",
test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
test::getDiagnostics()));
EXPECT_FALSE(table.addResource(
- ResourceNameRef(u"android", ResourceType::kId, u"hey:there"),
+ test::parseNameOrDie("@android:id/hey:there"),
ConfigDescription{}, "",
test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
test::getDiagnostics()));
@@ -47,14 +45,13 @@
TEST(ResourceTableTest, AddOneResource) {
ResourceTable table;
- EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"),
- ConfigDescription{},
- "",
- test::ValueBuilder<Id>()
- .setSource("test/path/file.xml", 23u).build(),
- test::getDiagnostics()));
+ EXPECT_TRUE(table.addResource(
+ test::parseNameOrDie("@android:attr/id"),
+ ConfigDescription{}, "",
+ test::ValueBuilder<Id>().setSource("test/path/file.xml", 23u).build(),
+ test::getDiagnostics()));
- ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/id"));
+ ASSERT_NE(nullptr, test::getValue<Id>(&table, "@android:attr/id"));
}
TEST(ResourceTableTest, AddMultipleResources) {
@@ -65,56 +62,58 @@
memcpy(languageConfig.language, "pl", sizeof(languageConfig.language));
EXPECT_TRUE(table.addResource(
- test::parseNameOrDie(u"@android:attr/layout_width"),
- config,
- "",
+ test::parseNameOrDie("@android:attr/layout_width"),
+ config, "",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 10u).build(),
test::getDiagnostics()));
EXPECT_TRUE(table.addResource(
- test::parseNameOrDie(u"@android:attr/id"),
- config,
- "",
+ test::parseNameOrDie("@android:attr/id"),
+ config, "",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 12u).build(),
test::getDiagnostics()));
EXPECT_TRUE(table.addResource(
- test::parseNameOrDie(u"@android:string/ok"),
- config,
- "",
+ test::parseNameOrDie("@android:string/ok"),
+ config, "",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 14u).build(),
test::getDiagnostics()));
EXPECT_TRUE(table.addResource(
- test::parseNameOrDie(u"@android:string/ok"),
- languageConfig,
- "",
+ test::parseNameOrDie("@android:string/ok"),
+ languageConfig, "",
test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
.setSource("test/path/file.xml", 20u)
.build(),
test::getDiagnostics()));
- ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/layout_width"));
- ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/id"));
- ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:string/ok"));
- ASSERT_NE(nullptr, test::getValueForConfig<BinaryPrimitive>(&table, u"@android:string/ok",
+ ASSERT_NE(nullptr, test::getValue<Id>(&table, "@android:attr/layout_width"));
+ ASSERT_NE(nullptr, test::getValue<Id>(&table, "@android:attr/id"));
+ ASSERT_NE(nullptr, test::getValue<Id>(&table, "@android:string/ok"));
+ ASSERT_NE(nullptr, test::getValueForConfig<BinaryPrimitive>(&table, "@android:string/ok",
languageConfig));
}
TEST(ResourceTableTest, OverrideWeakResourceValue) {
ResourceTable table;
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
- "", util::make_unique<Attribute>(true), test::getDiagnostics()));
+ ASSERT_TRUE(table.addResource(
+ test::parseNameOrDie("@android:attr/foo"),
+ ConfigDescription{}, "",
+ util::make_unique<Attribute>(true),
+ test::getDiagnostics()));
- Attribute* attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
+ Attribute* attr = test::getValue<Attribute>(&table, "@android:attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_TRUE(attr->isWeak());
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
- "", util::make_unique<Attribute>(false), test::getDiagnostics()));
+ ASSERT_TRUE(table.addResource(
+ test::parseNameOrDie("@android:attr/foo"),
+ ConfigDescription{}, "",
+ util::make_unique<Attribute>(false),
+ test::getDiagnostics()));
- attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
+ attr = test::getValue<Attribute>(&table, "@android:attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_FALSE(attr->isWeak());
}
@@ -122,26 +121,24 @@
TEST(ResourceTableTest, ProductVaryingValues) {
ResourceTable table;
- EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/foo"),
- test::parseConfigOrDie("land"),
- "tablet",
+ EXPECT_TRUE(table.addResource(test::parseNameOrDie("@android:string/foo"),
+ test::parseConfigOrDie("land"), "tablet",
util::make_unique<Id>(),
test::getDiagnostics()));
- EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/foo"),
- test::parseConfigOrDie("land"),
- "phone",
+ EXPECT_TRUE(table.addResource(test::parseNameOrDie("@android:string/foo"),
+ test::parseConfigOrDie("land"), "phone",
util::make_unique<Id>(),
test::getDiagnostics()));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/foo",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/foo",
test::parseConfigOrDie("land"),
"tablet"));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/foo",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/foo",
test::parseConfigOrDie("land"),
"phone"));
Maybe<ResourceTable::SearchResult> sr = table.findResource(
- test::parseNameOrDie(u"@android:string/foo"));
+ test::parseNameOrDie("@android:string/foo"));
AAPT_ASSERT_TRUE(sr);
std::vector<ResourceConfigValue*> values = sr.value().entry->findAllValues(
test::parseConfigOrDie("land"));
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 302c04f..31d6435a6 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -27,19 +27,52 @@
namespace aapt {
namespace ResourceUtils {
-bool extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
- StringPiece16* outType, StringPiece16* outEntry) {
+Maybe<ResourceName> toResourceName(const android::ResTable::resource_name& nameIn) {
+ ResourceName nameOut;
+ if (!nameIn.package) {
+ return {};
+ }
+
+ nameOut.package = util::utf16ToUtf8(StringPiece16(nameIn.package, nameIn.packageLen));
+
+ const ResourceType* type;
+ if (nameIn.type) {
+ type = parseResourceType(util::utf16ToUtf8(StringPiece16(nameIn.type, nameIn.typeLen)));
+ } else if (nameIn.type8) {
+ type = parseResourceType(StringPiece(nameIn.type8, nameIn.typeLen));
+ } else {
+ return {};
+ }
+
+ if (!type) {
+ return {};
+ }
+
+ nameOut.type = *type;
+
+ if (nameIn.name) {
+ nameOut.entry = util::utf16ToUtf8(StringPiece16(nameIn.name, nameIn.nameLen));
+ } else if (nameIn.name8) {
+ nameOut.entry = StringPiece(nameIn.name8, nameIn.nameLen).toString();
+ } else {
+ return {};
+ }
+ return nameOut;
+}
+
+bool extractResourceName(const StringPiece& str, StringPiece* outPackage,
+ StringPiece* outType, StringPiece* outEntry) {
bool hasPackageSeparator = false;
bool hasTypeSeparator = false;
- const char16_t* start = str.data();
- const char16_t* end = start + str.size();
- const char16_t* current = start;
+ const char* start = str.data();
+ const char* end = start + str.size();
+ const char* current = start;
while (current != end) {
- if (outType->size() == 0 && *current == u'/') {
+ if (outType->size() == 0 && *current == '/') {
hasTypeSeparator = true;
outType->assign(start, current - start);
start = current + 1;
- } else if (outPackage->size() == 0 && *current == u':') {
+ } else if (outPackage->size() == 0 && *current == ':') {
hasPackageSeparator = true;
outPackage->assign(start, current - start);
start = current + 1;
@@ -51,21 +84,21 @@
return !(hasPackageSeparator && outPackage->empty()) && !(hasTypeSeparator && outType->empty());
}
-bool parseResourceName(const StringPiece16& str, ResourceNameRef* outRef, bool* outPrivate) {
+bool parseResourceName(const StringPiece& str, ResourceNameRef* outRef, bool* outPrivate) {
if (str.empty()) {
return false;
}
size_t offset = 0;
bool priv = false;
- if (str.data()[0] == u'*') {
+ if (str.data()[0] == '*') {
priv = true;
offset = 1;
}
- StringPiece16 package;
- StringPiece16 type;
- StringPiece16 entry;
+ StringPiece package;
+ StringPiece type;
+ StringPiece entry;
if (!extractResourceName(str.substr(offset, str.size() - offset), &package, &type, &entry)) {
return false;
}
@@ -91,18 +124,18 @@
return true;
}
-bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool* outCreate,
+bool tryParseReference(const StringPiece& str, ResourceNameRef* outRef, bool* outCreate,
bool* outPrivate) {
- StringPiece16 trimmedStr(util::trimWhitespace(str));
+ StringPiece trimmedStr(util::trimWhitespace(str));
if (trimmedStr.empty()) {
return false;
}
bool create = false;
bool priv = false;
- if (trimmedStr.data()[0] == u'@') {
+ if (trimmedStr.data()[0] == '@') {
size_t offset = 1;
- if (trimmedStr.data()[1] == u'+') {
+ if (trimmedStr.data()[1] == '+') {
create = true;
offset += 1;
}
@@ -137,26 +170,26 @@
return false;
}
-bool isReference(const StringPiece16& str) {
+bool isReference(const StringPiece& str) {
return tryParseReference(str, nullptr, nullptr, nullptr);
}
-bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outRef) {
- StringPiece16 trimmedStr(util::trimWhitespace(str));
+bool tryParseAttributeReference(const StringPiece& str, ResourceNameRef* outRef) {
+ StringPiece trimmedStr(util::trimWhitespace(str));
if (trimmedStr.empty()) {
return false;
}
- if (*trimmedStr.data() == u'?') {
- StringPiece16 package;
- StringPiece16 type;
- StringPiece16 entry;
+ if (*trimmedStr.data() == '?') {
+ StringPiece package;
+ StringPiece type;
+ StringPiece entry;
if (!extractResourceName(trimmedStr.substr(1, trimmedStr.size() - 1),
&package, &type, &entry)) {
return false;
}
- if (!type.empty() && type != u"attr") {
+ if (!type.empty() && type != "attr") {
return false;
}
@@ -174,7 +207,7 @@
return false;
}
-bool isAttributeReference(const StringPiece16& str) {
+bool isAttributeReference(const StringPiece& str) {
return tryParseAttributeReference(str, nullptr);
}
@@ -186,23 +219,23 @@
* <[*]package>:[style/]<entry>
* [[*]package:style/]<entry>
*/
-Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) {
+Maybe<Reference> parseStyleParentReference(const StringPiece& str, std::string* outError) {
if (str.empty()) {
return {};
}
- StringPiece16 name = str;
+ StringPiece name = str;
bool hasLeadingIdentifiers = false;
bool privateRef = false;
// Skip over these identifiers. A style's parent is a normal reference.
- if (name.data()[0] == u'@' || name.data()[0] == u'?') {
+ if (name.data()[0] == '@' || name.data()[0] == '?') {
hasLeadingIdentifiers = true;
name = name.substr(1, name.size() - 1);
}
- if (name.data()[0] == u'*') {
+ if (name.data()[0] == '*') {
privateRef = true;
name = name.substr(1, name.size() - 1);
}
@@ -210,7 +243,7 @@
ResourceNameRef ref;
ref.type = ResourceType::kStyle;
- StringPiece16 typeStr;
+ StringPiece typeStr;
extractResourceName(name, &ref.package, &typeStr, &ref.entry);
if (!typeStr.empty()) {
// If we have a type, make sure it is a Style.
@@ -235,7 +268,7 @@
return result;
}
-std::unique_ptr<Reference> tryParseReference(const StringPiece16& str, bool* outCreate) {
+std::unique_ptr<Reference> tryParseReference(const StringPiece& str, bool* outCreate) {
ResourceNameRef ref;
bool privateRef = false;
if (tryParseReference(str, &ref, outCreate, &privateRef)) {
@@ -253,14 +286,14 @@
return {};
}
-std::unique_ptr<BinaryPrimitive> tryParseNullOrEmpty(const StringPiece16& str) {
- StringPiece16 trimmedStr(util::trimWhitespace(str));
+std::unique_ptr<BinaryPrimitive> tryParseNullOrEmpty(const StringPiece& str) {
+ StringPiece trimmedStr(util::trimWhitespace(str));
android::Res_value value = { };
- if (trimmedStr == u"@null") {
+ if (trimmedStr == "@null") {
// TYPE_NULL with data set to 0 is interpreted by the runtime as an error.
// Instead we set the data type to TYPE_REFERENCE with a value of 0.
value.dataType = android::Res_value::TYPE_REFERENCE;
- } else if (trimmedStr == u"@empty") {
+ } else if (trimmedStr == "@empty") {
// TYPE_NULL with value of DATA_NULL_EMPTY is handled fine by the runtime.
value.dataType = android::Res_value::TYPE_NULL;
value.data = android::Res_value::DATA_NULL_EMPTY;
@@ -271,8 +304,8 @@
}
std::unique_ptr<BinaryPrimitive> tryParseEnumSymbol(const Attribute* enumAttr,
- const StringPiece16& str) {
- StringPiece16 trimmedStr(util::trimWhitespace(str));
+ const StringPiece& str) {
+ StringPiece trimmedStr(util::trimWhitespace(str));
for (const Attribute::Symbol& symbol : enumAttr->symbols) {
// Enum symbols are stored as @package:id/symbol resources,
// so we need to match against the 'entry' part of the identifier.
@@ -288,7 +321,7 @@
}
std::unique_ptr<BinaryPrimitive> tryParseFlagSymbol(const Attribute* flagAttr,
- const StringPiece16& str) {
+ const StringPiece& str) {
android::Res_value flags = { };
flags.dataType = android::Res_value::TYPE_INT_HEX;
flags.data = 0u;
@@ -298,8 +331,8 @@
return util::make_unique<BinaryPrimitive>(flags);
}
- for (StringPiece16 part : util::tokenize(str, u'|')) {
- StringPiece16 trimmedPart = util::trimWhitespace(part);
+ for (StringPiece part : util::tokenize(str, '|')) {
+ StringPiece trimmedPart = util::trimWhitespace(part);
bool flagSet = false;
for (const Attribute::Symbol& symbol : flagAttr->symbols) {
@@ -320,24 +353,24 @@
return util::make_unique<BinaryPrimitive>(flags);
}
-static uint32_t parseHex(char16_t c, bool* outError) {
- if (c >= u'0' && c <= u'9') {
- return c - u'0';
- } else if (c >= u'a' && c <= u'f') {
- return c - u'a' + 0xa;
- } else if (c >= u'A' && c <= u'F') {
- return c - u'A' + 0xa;
+static uint32_t parseHex(char c, bool* outError) {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 0xa;
+ } else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 0xa;
} else {
*outError = true;
return 0xffffffffu;
}
}
-std::unique_ptr<BinaryPrimitive> tryParseColor(const StringPiece16& str) {
- StringPiece16 colorStr(util::trimWhitespace(str));
- const char16_t* start = colorStr.data();
+std::unique_ptr<BinaryPrimitive> tryParseColor(const StringPiece& str) {
+ StringPiece colorStr(util::trimWhitespace(str));
+ const char* start = colorStr.data();
const size_t len = colorStr.size();
- if (len == 0 || start[0] != u'#') {
+ if (len == 0 || start[0] != '#') {
return {};
}
@@ -387,14 +420,14 @@
return error ? std::unique_ptr<BinaryPrimitive>() : util::make_unique<BinaryPrimitive>(value);
}
-bool tryParseBool(const StringPiece16& str, bool* outValue) {
- StringPiece16 trimmedStr(util::trimWhitespace(str));
- if (trimmedStr == u"true" || trimmedStr == u"TRUE" || trimmedStr == u"True") {
+bool tryParseBool(const StringPiece& str, bool* outValue) {
+ StringPiece trimmedStr(util::trimWhitespace(str));
+ if (trimmedStr == "true" || trimmedStr == "TRUE" || trimmedStr == "True") {
if (outValue) {
*outValue = true;
}
return true;
- } else if (trimmedStr == u"false" || trimmedStr == u"FALSE" || trimmedStr == u"False") {
+ } else if (trimmedStr == "false" || trimmedStr == "FALSE" || trimmedStr == "False") {
if (outValue) {
*outValue = false;
}
@@ -403,22 +436,24 @@
return false;
}
-Maybe<int> tryParseSdkVersion(const StringPiece16& str) {
- StringPiece16 trimmedStr(util::trimWhitespace(str));
+Maybe<int> tryParseSdkVersion(const StringPiece& str) {
+ StringPiece trimmedStr(util::trimWhitespace(str));
+
+ std::u16string str16 = util::utf8ToUtf16(trimmedStr);
android::Res_value value;
- if (android::ResTable::stringToInt(trimmedStr.data(), trimmedStr.size(), &value)) {
+ if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return static_cast<int>(value.data);
}
// Try parsing the code name.
- std::pair<StringPiece16, int> entry = getDevelopmentSdkCodeNameAndVersion();
+ std::pair<StringPiece, int> entry = getDevelopmentSdkCodeNameAndVersion();
if (entry.first == trimmedStr) {
return entry.second;
}
return {};
}
-std::unique_ptr<BinaryPrimitive> tryParseBool(const StringPiece16& str) {
+std::unique_ptr<BinaryPrimitive> tryParseBool(const StringPiece& str) {
bool result = false;
if (tryParseBool(str, &result)) {
android::Res_value value = {};
@@ -434,17 +469,19 @@
return {};
}
-std::unique_ptr<BinaryPrimitive> tryParseInt(const StringPiece16& str) {
+std::unique_ptr<BinaryPrimitive> tryParseInt(const StringPiece& str) {
+ std::u16string str16 = util::utf8ToUtf16(str);
android::Res_value value;
- if (!android::ResTable::stringToInt(str.data(), str.size(), &value)) {
+ if (!android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return {};
}
return util::make_unique<BinaryPrimitive>(value);
}
-std::unique_ptr<BinaryPrimitive> tryParseFloat(const StringPiece16& str) {
+std::unique_ptr<BinaryPrimitive> tryParseFloat(const StringPiece& str) {
+ std::u16string str16 = util::utf8ToUtf16(str);
android::Res_value value;
- if (!android::ResTable::stringToFloat(str.data(), str.size(), &value)) {
+ if (!android::ResTable::stringToFloat(str16.data(), str16.size(), &value)) {
return {};
}
return util::make_unique<BinaryPrimitive>(value);
@@ -490,7 +527,8 @@
}
std::unique_ptr<Item> parseItemForAttribute(
- const StringPiece16& value, uint32_t typeMask,
+ const StringPiece& value,
+ uint32_t typeMask,
std::function<void(const ResourceName&)> onCreateReference) {
std::unique_ptr<BinaryPrimitive> nullOrEmpty = tryParseNullOrEmpty(value);
if (nullOrEmpty) {
@@ -549,7 +587,7 @@
* allows.
*/
std::unique_ptr<Item> parseItemForAttribute(
- const StringPiece16& str, const Attribute* attr,
+ const StringPiece& str, const Attribute* attr,
std::function<void(const ResourceName&)> onCreateReference) {
const uint32_t typeMask = attr->typeMask;
std::unique_ptr<Item> value = parseItemForAttribute(str, typeMask, onCreateReference);
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 3a03caf..871ed7c 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -28,6 +28,11 @@
namespace aapt {
namespace ResourceUtils {
+/**
+ * Convert an android::ResTable::resource_name to an aapt::ResourceName struct.
+ */
+Maybe<ResourceName> toResourceName(const android::ResTable::resource_name& name);
+
/*
* Extracts the package, type, and name from a string of the format:
*
@@ -37,15 +42,15 @@
* individual extracted piece to verify that the pieces are valid.
* Returns false if there was no package but a ':' was present.
*/
-bool extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
- StringPiece16* outType, StringPiece16* outEntry);
+bool extractResourceName(const StringPiece& str, StringPiece* outPackage,
+ StringPiece* outType, StringPiece* outEntry);
/**
* Returns true if the string was parsed as a resource name ([*][package:]type/name), with
* `outResource` set to the parsed resource name and `outPrivate` set to true if a '*' prefix
* was present.
*/
-bool parseResourceName(const StringPiece16& str, ResourceNameRef* outResource,
+bool parseResourceName(const StringPiece& str, ResourceNameRef* outResource,
bool* outPrivate = nullptr);
/*
@@ -55,34 +60,34 @@
* If '+' was present in the reference, `outCreate` is set to true.
* If '*' was present in the reference, `outPrivate` is set to true.
*/
-bool tryParseReference(const StringPiece16& str, ResourceNameRef* outReference,
+bool tryParseReference(const StringPiece& str, ResourceNameRef* outReference,
bool* outCreate = nullptr, bool* outPrivate = nullptr);
/*
* Returns true if the string is in the form of a resource reference (@[+][package:]type/name).
*/
-bool isReference(const StringPiece16& str);
+bool isReference(const StringPiece& str);
/*
* Returns true if the string was parsed as an attribute reference (?[package:][type/]name),
* with `outReference` set to the parsed reference.
*/
-bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outReference);
+bool tryParseAttributeReference(const StringPiece& str, ResourceNameRef* outReference);
/**
* Returns true if the string is in the form of an attribute reference(?[package:][type/]name).
*/
-bool isAttributeReference(const StringPiece16& str);
+bool isAttributeReference(const StringPiece& str);
/**
* Returns true if the value is a boolean, putting the result in `outValue`.
*/
-bool tryParseBool(const StringPiece16& str, bool* outValue);
+bool tryParseBool(const StringPiece& str, bool* outValue);
/**
* Parses an SDK version, which can be an integer, or a letter from A-Z.
*/
-Maybe<int> tryParseSdkVersion(const StringPiece16& str);
+Maybe<int> tryParseSdkVersion(const StringPiece& str);
/*
* Returns a Reference, or None Maybe instance if the string `str` was parsed as a
@@ -93,58 +98,58 @@
* ?[package:]style/<entry> or
* <package>:[style/]<entry>
*/
-Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError);
+Maybe<Reference> parseStyleParentReference(const StringPiece& str, std::string* outError);
/*
* Returns a Reference object if the string was parsed as a resource or attribute reference,
* ( @[+][package:]type/name | ?[package:]type/name ) setting outCreate to true if
* the '+' was present in the string.
*/
-std::unique_ptr<Reference> tryParseReference(const StringPiece16& str, bool* outCreate = nullptr);
+std::unique_ptr<Reference> tryParseReference(const StringPiece& str, bool* outCreate = nullptr);
/*
* Returns a BinaryPrimitve object representing @null or @empty if the string was parsed
* as one.
*/
-std::unique_ptr<BinaryPrimitive> tryParseNullOrEmpty(const StringPiece16& str);
+std::unique_ptr<BinaryPrimitive> tryParseNullOrEmpty(const StringPiece& str);
/*
* Returns a BinaryPrimitve object representing a color if the string was parsed
* as one.
*/
-std::unique_ptr<BinaryPrimitive> tryParseColor(const StringPiece16& str);
+std::unique_ptr<BinaryPrimitive> tryParseColor(const StringPiece& str);
/*
* Returns a BinaryPrimitve object representing a boolean if the string was parsed
* as one.
*/
-std::unique_ptr<BinaryPrimitive> tryParseBool(const StringPiece16& str);
+std::unique_ptr<BinaryPrimitive> tryParseBool(const StringPiece& str);
/*
* Returns a BinaryPrimitve object representing an integer if the string was parsed
* as one.
*/
-std::unique_ptr<BinaryPrimitive> tryParseInt(const StringPiece16& str);
+std::unique_ptr<BinaryPrimitive> tryParseInt(const StringPiece& str);
/*
* Returns a BinaryPrimitve object representing a floating point number
* (float, dimension, etc) if the string was parsed as one.
*/
-std::unique_ptr<BinaryPrimitive> tryParseFloat(const StringPiece16& str);
+std::unique_ptr<BinaryPrimitive> tryParseFloat(const StringPiece& str);
/*
* Returns a BinaryPrimitve object representing an enum symbol if the string was parsed
* as one.
*/
std::unique_ptr<BinaryPrimitive> tryParseEnumSymbol(const Attribute* enumAttr,
- const StringPiece16& str);
+ const StringPiece& str);
/*
* Returns a BinaryPrimitve object representing a flag symbol if the string was parsed
* as one.
*/
std::unique_ptr<BinaryPrimitive> tryParseFlagSymbol(const Attribute* enumAttr,
- const StringPiece16& str);
+ const StringPiece& str);
/*
* Try to convert a string to an Item for the given attribute. The attribute will
* restrict what values the string can be converted to.
@@ -152,11 +157,11 @@
* reference to an ID that must be created (@+id/foo).
*/
std::unique_ptr<Item> parseItemForAttribute(
- const StringPiece16& value, const Attribute* attr,
+ const StringPiece& value, const Attribute* attr,
std::function<void(const ResourceName&)> onCreateReference = {});
std::unique_ptr<Item> parseItemForAttribute(
- const StringPiece16& value, uint32_t typeMask,
+ const StringPiece& value, uint32_t typeMask,
std::function<void(const ResourceName&)> onCreateReference = {});
uint32_t androidTypeToAttributeTypeMask(uint16_t type);
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 7425f97..fb76914 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -16,69 +16,66 @@
#include "Resource.h"
#include "ResourceUtils.h"
-#include "test/Builders.h"
-#include "test/Common.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
TEST(ResourceUtilsTest, ParseBool) {
bool val = false;
- EXPECT_TRUE(ResourceUtils::tryParseBool(u"true", &val));
+ EXPECT_TRUE(ResourceUtils::tryParseBool("true", &val));
EXPECT_TRUE(val);
- EXPECT_TRUE(ResourceUtils::tryParseBool(u"TRUE", &val));
+ EXPECT_TRUE(ResourceUtils::tryParseBool("TRUE", &val));
EXPECT_TRUE(val);
- EXPECT_TRUE(ResourceUtils::tryParseBool(u"True", &val));
+ EXPECT_TRUE(ResourceUtils::tryParseBool("True", &val));
EXPECT_TRUE(val);
- EXPECT_TRUE(ResourceUtils::tryParseBool(u"false", &val));
+ EXPECT_TRUE(ResourceUtils::tryParseBool("false", &val));
EXPECT_FALSE(val);
- EXPECT_TRUE(ResourceUtils::tryParseBool(u"FALSE", &val));
+ EXPECT_TRUE(ResourceUtils::tryParseBool("FALSE", &val));
EXPECT_FALSE(val);
- EXPECT_TRUE(ResourceUtils::tryParseBool(u"False", &val));
+ EXPECT_TRUE(ResourceUtils::tryParseBool("False", &val));
EXPECT_FALSE(val);
}
TEST(ResourceUtilsTest, ParseResourceName) {
ResourceNameRef actual;
bool actualPriv = false;
- EXPECT_TRUE(ResourceUtils::parseResourceName(u"android:color/foo", &actual, &actualPriv));
- EXPECT_EQ(ResourceNameRef(u"android", ResourceType::kColor, u"foo"), actual);
+ EXPECT_TRUE(ResourceUtils::parseResourceName("android:color/foo", &actual, &actualPriv));
+ EXPECT_EQ(ResourceNameRef("android", ResourceType::kColor, "foo"), actual);
EXPECT_FALSE(actualPriv);
- EXPECT_TRUE(ResourceUtils::parseResourceName(u"color/foo", &actual, &actualPriv));
- EXPECT_EQ(ResourceNameRef({}, ResourceType::kColor, u"foo"), actual);
+ EXPECT_TRUE(ResourceUtils::parseResourceName("color/foo", &actual, &actualPriv));
+ EXPECT_EQ(ResourceNameRef({}, ResourceType::kColor, "foo"), actual);
EXPECT_FALSE(actualPriv);
- EXPECT_TRUE(ResourceUtils::parseResourceName(u"*android:color/foo", &actual, &actualPriv));
- EXPECT_EQ(ResourceNameRef(u"android", ResourceType::kColor, u"foo"), actual);
+ EXPECT_TRUE(ResourceUtils::parseResourceName("*android:color/foo", &actual, &actualPriv));
+ EXPECT_EQ(ResourceNameRef("android", ResourceType::kColor, "foo"), actual);
EXPECT_TRUE(actualPriv);
- EXPECT_FALSE(ResourceUtils::parseResourceName(StringPiece16(), &actual, &actualPriv));
+ EXPECT_FALSE(ResourceUtils::parseResourceName(StringPiece(), &actual, &actualPriv));
}
TEST(ResourceUtilsTest, ParseReferenceWithNoPackage) {
- ResourceNameRef expected({}, ResourceType::kColor, u"foo");
+ ResourceNameRef expected({}, ResourceType::kColor, "foo");
ResourceNameRef actual;
bool create = false;
bool privateRef = false;
- EXPECT_TRUE(ResourceUtils::tryParseReference(u"@color/foo", &actual, &create, &privateRef));
+ EXPECT_TRUE(ResourceUtils::tryParseReference("@color/foo", &actual, &create, &privateRef));
EXPECT_EQ(expected, actual);
EXPECT_FALSE(create);
EXPECT_FALSE(privateRef);
}
TEST(ResourceUtilsTest, ParseReferenceWithPackage) {
- ResourceNameRef expected(u"android", ResourceType::kColor, u"foo");
+ ResourceNameRef expected("android", ResourceType::kColor, "foo");
ResourceNameRef actual;
bool create = false;
bool privateRef = false;
- EXPECT_TRUE(ResourceUtils::tryParseReference(u"@android:color/foo", &actual, &create,
+ EXPECT_TRUE(ResourceUtils::tryParseReference("@android:color/foo", &actual, &create,
&privateRef));
EXPECT_EQ(expected, actual);
EXPECT_FALSE(create);
@@ -86,11 +83,11 @@
}
TEST(ResourceUtilsTest, ParseReferenceWithSurroundingWhitespace) {
- ResourceNameRef expected(u"android", ResourceType::kColor, u"foo");
+ ResourceNameRef expected("android", ResourceType::kColor, "foo");
ResourceNameRef actual;
bool create = false;
bool privateRef = false;
- EXPECT_TRUE(ResourceUtils::tryParseReference(u"\t @android:color/foo\n \n\t", &actual,
+ EXPECT_TRUE(ResourceUtils::tryParseReference("\t @android:color/foo\n \n\t", &actual,
&create, &privateRef));
EXPECT_EQ(expected, actual);
EXPECT_FALSE(create);
@@ -98,11 +95,11 @@
}
TEST(ResourceUtilsTest, ParseAutoCreateIdReference) {
- ResourceNameRef expected(u"android", ResourceType::kId, u"foo");
+ ResourceNameRef expected("android", ResourceType::kId, "foo");
ResourceNameRef actual;
bool create = false;
bool privateRef = false;
- EXPECT_TRUE(ResourceUtils::tryParseReference(u"@+android:id/foo", &actual, &create,
+ EXPECT_TRUE(ResourceUtils::tryParseReference("@+android:id/foo", &actual, &create,
&privateRef));
EXPECT_EQ(expected, actual);
EXPECT_TRUE(create);
@@ -110,11 +107,11 @@
}
TEST(ResourceUtilsTest, ParsePrivateReference) {
- ResourceNameRef expected(u"android", ResourceType::kId, u"foo");
+ ResourceNameRef expected("android", ResourceType::kId, "foo");
ResourceNameRef actual;
bool create = false;
bool privateRef = false;
- EXPECT_TRUE(ResourceUtils::tryParseReference(u"@*android:id/foo", &actual, &create,
+ EXPECT_TRUE(ResourceUtils::tryParseReference("@*android:id/foo", &actual, &create,
&privateRef));
EXPECT_EQ(expected, actual);
EXPECT_FALSE(create);
@@ -125,68 +122,68 @@
bool create = false;
bool privateRef = false;
ResourceNameRef actual;
- EXPECT_FALSE(ResourceUtils::tryParseReference(u"@+android:color/foo", &actual, &create,
+ EXPECT_FALSE(ResourceUtils::tryParseReference("@+android:color/foo", &actual, &create,
&privateRef));
}
TEST(ResourceUtilsTest, ParseAttributeReferences) {
- EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?android"));
- EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?android:foo"));
- EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?attr/foo"));
- EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?android:attr/foo"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference("?android"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference("?android:foo"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference("?attr/foo"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference("?android:attr/foo"));
}
TEST(ResourceUtilsTest, FailParseIncompleteReference) {
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?style/foo"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?android:style/foo"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?android:"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?android:attr/"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:attr/"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:attr/foo"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:/"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:/foo"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?attr/"));
- EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?style/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?android:style/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?android:"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?android:attr/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?:attr/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?:attr/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?:/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?:/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?attr/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference("?/foo"));
}
TEST(ResourceUtilsTest, ParseStyleParentReference) {
- const ResourceName kAndroidStyleFooName(u"android", ResourceType::kStyle, u"foo");
- const ResourceName kStyleFooName({}, ResourceType::kStyle, u"foo");
+ const ResourceName kAndroidStyleFooName("android", ResourceType::kStyle, "foo");
+ const ResourceName kStyleFooName({}, ResourceType::kStyle, "foo");
std::string errStr;
- Maybe<Reference> ref = ResourceUtils::parseStyleParentReference(u"@android:style/foo", &errStr);
+ Maybe<Reference> ref = ResourceUtils::parseStyleParentReference("@android:style/foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"@style/foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("@style/foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"?android:style/foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("?android:style/foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"?style/foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("?style/foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"android:style/foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("android:style/foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"android:foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("android:foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"@android:foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("@android:foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kStyleFooName);
- ref = ResourceUtils::parseStyleParentReference(u"*android:style/foo", &errStr);
+ ref = ResourceUtils::parseStyleParentReference("*android:style/foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
EXPECT_TRUE(ref.value().privateReference);
@@ -195,11 +192,11 @@
TEST(ResourceUtilsTest, ParseEmptyFlag) {
std::unique_ptr<Attribute> attr = test::AttributeBuilder(false)
.setTypeMask(android::ResTable_map::TYPE_FLAGS)
- .addItem(u"one", 0x01)
- .addItem(u"two", 0x02)
+ .addItem("one", 0x01)
+ .addItem("two", 0x02)
.build();
- std::unique_ptr<BinaryPrimitive> result = ResourceUtils::tryParseFlagSymbol(attr.get(), u"");
+ std::unique_ptr<BinaryPrimitive> result = ResourceUtils::tryParseFlagSymbol(attr.get(), "");
ASSERT_NE(nullptr, result);
EXPECT_EQ(0u, result->value.data);
}
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index aa1b550..8ae71ad 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -84,15 +84,15 @@
/**
* Returns the comment that was associated with this resource.
*/
- StringPiece16 getComment() const {
+ const std::string& getComment() const {
return mComment;
}
- void setComment(const StringPiece16& str) {
+ void setComment(const StringPiece& str) {
mComment = str.toString();
}
- void setComment(std::u16string&& str) {
+ void setComment(std::string&& str) {
mComment = std::move(str);
}
@@ -115,7 +115,7 @@
protected:
Source mSource;
- std::u16string mComment;
+ std::string mComment;
bool mWeak = false;
bool mTranslateable = true;
};
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 48dc521..06cddc7 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -14,102 +14,101 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include "Resource.h"
+#include "test/Test.h"
namespace aapt {
TEST(ResourceTypeTest, ParseResourceTypes) {
- const ResourceType* type = parseResourceType(u"anim");
+ const ResourceType* type = parseResourceType("anim");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kAnim);
- type = parseResourceType(u"animator");
+ type = parseResourceType("animator");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kAnimator);
- type = parseResourceType(u"array");
+ type = parseResourceType("array");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kArray);
- type = parseResourceType(u"attr");
+ type = parseResourceType("attr");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kAttr);
- type = parseResourceType(u"^attr-private");
+ type = parseResourceType("^attr-private");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kAttrPrivate);
- type = parseResourceType(u"bool");
+ type = parseResourceType("bool");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kBool);
- type = parseResourceType(u"color");
+ type = parseResourceType("color");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kColor);
- type = parseResourceType(u"dimen");
+ type = parseResourceType("dimen");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kDimen);
- type = parseResourceType(u"drawable");
+ type = parseResourceType("drawable");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kDrawable);
- type = parseResourceType(u"fraction");
+ type = parseResourceType("fraction");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kFraction);
- type = parseResourceType(u"id");
+ type = parseResourceType("id");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kId);
- type = parseResourceType(u"integer");
+ type = parseResourceType("integer");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kInteger);
- type = parseResourceType(u"interpolator");
+ type = parseResourceType("interpolator");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kInterpolator);
- type = parseResourceType(u"layout");
+ type = parseResourceType("layout");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kLayout);
- type = parseResourceType(u"menu");
+ type = parseResourceType("menu");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kMenu);
- type = parseResourceType(u"mipmap");
+ type = parseResourceType("mipmap");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kMipmap);
- type = parseResourceType(u"plurals");
+ type = parseResourceType("plurals");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kPlurals);
- type = parseResourceType(u"raw");
+ type = parseResourceType("raw");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kRaw);
- type = parseResourceType(u"string");
+ type = parseResourceType("string");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kString);
- type = parseResourceType(u"style");
+ type = parseResourceType("style");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kStyle);
- type = parseResourceType(u"transition");
+ type = parseResourceType("transition");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kTransition);
- type = parseResourceType(u"xml");
+ type = parseResourceType("xml");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kXml);
- type = parseResourceType(u"blahaha");
+ type = parseResourceType("blahaha");
EXPECT_EQ(type, nullptr);
}
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 7312ee3..91e755d 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -23,7 +23,7 @@
namespace aapt {
-static const char16_t* sDevelopmentSdkCodeName = u"O";
+static const char* sDevelopmentSdkCodeName = "O";
static int sDevelopmentSdkLevel = 26;
static const std::vector<std::pair<uint16_t, size_t>> sAttrIdMap = {
@@ -63,671 +63,671 @@
return iter->second;
}
-static const std::unordered_map<std::u16string, size_t> sAttrMap = {
- { u"marqueeRepeatLimit", 2 },
- { u"windowNoDisplay", 3 },
- { u"backgroundDimEnabled", 3 },
- { u"inputType", 3 },
- { u"isDefault", 3 },
- { u"windowDisablePreview", 3 },
- { u"privateImeOptions", 3 },
- { u"editorExtras", 3 },
- { u"settingsActivity", 3 },
- { u"fastScrollEnabled", 3 },
- { u"reqTouchScreen", 3 },
- { u"reqKeyboardType", 3 },
- { u"reqHardKeyboard", 3 },
- { u"reqNavigation", 3 },
- { u"windowSoftInputMode", 3 },
- { u"imeFullscreenBackground", 3 },
- { u"noHistory", 3 },
- { u"headerDividersEnabled", 3 },
- { u"footerDividersEnabled", 3 },
- { u"candidatesTextStyleSpans", 3 },
- { u"smoothScrollbar", 3 },
- { u"reqFiveWayNav", 3 },
- { u"keyBackground", 3 },
- { u"keyTextSize", 3 },
- { u"labelTextSize", 3 },
- { u"keyTextColor", 3 },
- { u"keyPreviewLayout", 3 },
- { u"keyPreviewOffset", 3 },
- { u"keyPreviewHeight", 3 },
- { u"verticalCorrection", 3 },
- { u"popupLayout", 3 },
- { u"state_long_pressable", 3 },
- { u"keyWidth", 3 },
- { u"keyHeight", 3 },
- { u"horizontalGap", 3 },
- { u"verticalGap", 3 },
- { u"rowEdgeFlags", 3 },
- { u"codes", 3 },
- { u"popupKeyboard", 3 },
- { u"popupCharacters", 3 },
- { u"keyEdgeFlags", 3 },
- { u"isModifier", 3 },
- { u"isSticky", 3 },
- { u"isRepeatable", 3 },
- { u"iconPreview", 3 },
- { u"keyOutputText", 3 },
- { u"keyLabel", 3 },
- { u"keyIcon", 3 },
- { u"keyboardMode", 3 },
- { u"isScrollContainer", 3 },
- { u"fillEnabled", 3 },
- { u"updatePeriodMillis", 3 },
- { u"initialLayout", 3 },
- { u"voiceSearchMode", 3 },
- { u"voiceLanguageModel", 3 },
- { u"voicePromptText", 3 },
- { u"voiceLanguage", 3 },
- { u"voiceMaxResults", 3 },
- { u"bottomOffset", 3 },
- { u"topOffset", 3 },
- { u"allowSingleTap", 3 },
- { u"handle", 3 },
- { u"content", 3 },
- { u"animateOnClick", 3 },
- { u"configure", 3 },
- { u"hapticFeedbackEnabled", 3 },
- { u"innerRadius", 3 },
- { u"thickness", 3 },
- { u"sharedUserLabel", 3 },
- { u"dropDownWidth", 3 },
- { u"dropDownAnchor", 3 },
- { u"imeOptions", 3 },
- { u"imeActionLabel", 3 },
- { u"imeActionId", 3 },
- { u"imeExtractEnterAnimation", 3 },
- { u"imeExtractExitAnimation", 3 },
- { u"tension", 4 },
- { u"extraTension", 4 },
- { u"anyDensity", 4 },
- { u"searchSuggestThreshold", 4 },
- { u"includeInGlobalSearch", 4 },
- { u"onClick", 4 },
- { u"targetSdkVersion", 4 },
- { u"maxSdkVersion", 4 },
- { u"testOnly", 4 },
- { u"contentDescription", 4 },
- { u"gestureStrokeWidth", 4 },
- { u"gestureColor", 4 },
- { u"uncertainGestureColor", 4 },
- { u"fadeOffset", 4 },
- { u"fadeDuration", 4 },
- { u"gestureStrokeType", 4 },
- { u"gestureStrokeLengthThreshold", 4 },
- { u"gestureStrokeSquarenessThreshold", 4 },
- { u"gestureStrokeAngleThreshold", 4 },
- { u"eventsInterceptionEnabled", 4 },
- { u"fadeEnabled", 4 },
- { u"backupAgent", 4 },
- { u"allowBackup", 4 },
- { u"glEsVersion", 4 },
- { u"queryAfterZeroResults", 4 },
- { u"dropDownHeight", 4 },
- { u"smallScreens", 4 },
- { u"normalScreens", 4 },
- { u"largeScreens", 4 },
- { u"progressBarStyleInverse", 4 },
- { u"progressBarStyleSmallInverse", 4 },
- { u"progressBarStyleLargeInverse", 4 },
- { u"searchSettingsDescription", 4 },
- { u"textColorPrimaryInverseDisableOnly", 4 },
- { u"autoUrlDetect", 4 },
- { u"resizeable", 4 },
- { u"required", 5 },
- { u"accountType", 5 },
- { u"contentAuthority", 5 },
- { u"userVisible", 5 },
- { u"windowShowWallpaper", 5 },
- { u"wallpaperOpenEnterAnimation", 5 },
- { u"wallpaperOpenExitAnimation", 5 },
- { u"wallpaperCloseEnterAnimation", 5 },
- { u"wallpaperCloseExitAnimation", 5 },
- { u"wallpaperIntraOpenEnterAnimation", 5 },
- { u"wallpaperIntraOpenExitAnimation", 5 },
- { u"wallpaperIntraCloseEnterAnimation", 5 },
- { u"wallpaperIntraCloseExitAnimation", 5 },
- { u"supportsUploading", 5 },
- { u"killAfterRestore", 5 },
- { u"restoreNeedsApplication", 5 },
- { u"smallIcon", 5 },
- { u"accountPreferences", 5 },
- { u"textAppearanceSearchResultSubtitle", 5 },
- { u"textAppearanceSearchResultTitle", 5 },
- { u"summaryColumn", 5 },
- { u"detailColumn", 5 },
- { u"detailSocialSummary", 5 },
- { u"thumbnail", 5 },
- { u"detachWallpaper", 5 },
- { u"finishOnCloseSystemDialogs", 5 },
- { u"scrollbarFadeDuration", 5 },
- { u"scrollbarDefaultDelayBeforeFade", 5 },
- { u"fadeScrollbars", 5 },
- { u"colorBackgroundCacheHint", 5 },
- { u"dropDownHorizontalOffset", 5 },
- { u"dropDownVerticalOffset", 5 },
- { u"quickContactBadgeStyleWindowSmall", 6 },
- { u"quickContactBadgeStyleWindowMedium", 6 },
- { u"quickContactBadgeStyleWindowLarge", 6 },
- { u"quickContactBadgeStyleSmallWindowSmall", 6 },
- { u"quickContactBadgeStyleSmallWindowMedium", 6 },
- { u"quickContactBadgeStyleSmallWindowLarge", 6 },
- { u"author", 7 },
- { u"autoStart", 7 },
- { u"expandableListViewWhiteStyle", 8 },
- { u"installLocation", 8 },
- { u"vmSafeMode", 8 },
- { u"webTextViewStyle", 8 },
- { u"restoreAnyVersion", 8 },
- { u"tabStripLeft", 8 },
- { u"tabStripRight", 8 },
- { u"tabStripEnabled", 8 },
- { u"logo", 9 },
- { u"xlargeScreens", 9 },
- { u"immersive", 9 },
- { u"overScrollMode", 9 },
- { u"overScrollHeader", 9 },
- { u"overScrollFooter", 9 },
- { u"filterTouchesWhenObscured", 9 },
- { u"textSelectHandleLeft", 9 },
- { u"textSelectHandleRight", 9 },
- { u"textSelectHandle", 9 },
- { u"textSelectHandleWindowStyle", 9 },
- { u"popupAnimationStyle", 9 },
- { u"screenSize", 9 },
- { u"screenDensity", 9 },
- { u"allContactsName", 11 },
- { u"windowActionBar", 11 },
- { u"actionBarStyle", 11 },
- { u"navigationMode", 11 },
- { u"displayOptions", 11 },
- { u"subtitle", 11 },
- { u"customNavigationLayout", 11 },
- { u"hardwareAccelerated", 11 },
- { u"measureWithLargestChild", 11 },
- { u"animateFirstView", 11 },
- { u"dropDownSpinnerStyle", 11 },
- { u"actionDropDownStyle", 11 },
- { u"actionButtonStyle", 11 },
- { u"showAsAction", 11 },
- { u"previewImage", 11 },
- { u"actionModeBackground", 11 },
- { u"actionModeCloseDrawable", 11 },
- { u"windowActionModeOverlay", 11 },
- { u"valueFrom", 11 },
- { u"valueTo", 11 },
- { u"valueType", 11 },
- { u"propertyName", 11 },
- { u"ordering", 11 },
- { u"fragment", 11 },
- { u"windowActionBarOverlay", 11 },
- { u"fragmentOpenEnterAnimation", 11 },
- { u"fragmentOpenExitAnimation", 11 },
- { u"fragmentCloseEnterAnimation", 11 },
- { u"fragmentCloseExitAnimation", 11 },
- { u"fragmentFadeEnterAnimation", 11 },
- { u"fragmentFadeExitAnimation", 11 },
- { u"actionBarSize", 11 },
- { u"imeSubtypeLocale", 11 },
- { u"imeSubtypeMode", 11 },
- { u"imeSubtypeExtraValue", 11 },
- { u"splitMotionEvents", 11 },
- { u"listChoiceBackgroundIndicator", 11 },
- { u"spinnerMode", 11 },
- { u"animateLayoutChanges", 11 },
- { u"actionBarTabStyle", 11 },
- { u"actionBarTabBarStyle", 11 },
- { u"actionBarTabTextStyle", 11 },
- { u"actionOverflowButtonStyle", 11 },
- { u"actionModeCloseButtonStyle", 11 },
- { u"titleTextStyle", 11 },
- { u"subtitleTextStyle", 11 },
- { u"iconifiedByDefault", 11 },
- { u"actionLayout", 11 },
- { u"actionViewClass", 11 },
- { u"activatedBackgroundIndicator", 11 },
- { u"state_activated", 11 },
- { u"listPopupWindowStyle", 11 },
- { u"popupMenuStyle", 11 },
- { u"textAppearanceLargePopupMenu", 11 },
- { u"textAppearanceSmallPopupMenu", 11 },
- { u"breadCrumbTitle", 11 },
- { u"breadCrumbShortTitle", 11 },
- { u"listDividerAlertDialog", 11 },
- { u"textColorAlertDialogListItem", 11 },
- { u"loopViews", 11 },
- { u"dialogTheme", 11 },
- { u"alertDialogTheme", 11 },
- { u"dividerVertical", 11 },
- { u"homeAsUpIndicator", 11 },
- { u"enterFadeDuration", 11 },
- { u"exitFadeDuration", 11 },
- { u"selectableItemBackground", 11 },
- { u"autoAdvanceViewId", 11 },
- { u"useIntrinsicSizeAsMinimum", 11 },
- { u"actionModeCutDrawable", 11 },
- { u"actionModeCopyDrawable", 11 },
- { u"actionModePasteDrawable", 11 },
- { u"textEditPasteWindowLayout", 11 },
- { u"textEditNoPasteWindowLayout", 11 },
- { u"textIsSelectable", 11 },
- { u"windowEnableSplitTouch", 11 },
- { u"indeterminateProgressStyle", 11 },
- { u"progressBarPadding", 11 },
- { u"animationResolution", 11 },
- { u"state_accelerated", 11 },
- { u"baseline", 11 },
- { u"homeLayout", 11 },
- { u"opacity", 11 },
- { u"alpha", 11 },
- { u"transformPivotX", 11 },
- { u"transformPivotY", 11 },
- { u"translationX", 11 },
- { u"translationY", 11 },
- { u"scaleX", 11 },
- { u"scaleY", 11 },
- { u"rotation", 11 },
- { u"rotationX", 11 },
- { u"rotationY", 11 },
- { u"showDividers", 11 },
- { u"dividerPadding", 11 },
- { u"borderlessButtonStyle", 11 },
- { u"dividerHorizontal", 11 },
- { u"itemPadding", 11 },
- { u"buttonBarStyle", 11 },
- { u"buttonBarButtonStyle", 11 },
- { u"segmentedButtonStyle", 11 },
- { u"staticWallpaperPreview", 11 },
- { u"allowParallelSyncs", 11 },
- { u"isAlwaysSyncable", 11 },
- { u"verticalScrollbarPosition", 11 },
- { u"fastScrollAlwaysVisible", 11 },
- { u"fastScrollThumbDrawable", 11 },
- { u"fastScrollPreviewBackgroundLeft", 11 },
- { u"fastScrollPreviewBackgroundRight", 11 },
- { u"fastScrollTrackDrawable", 11 },
- { u"fastScrollOverlayPosition", 11 },
- { u"customTokens", 11 },
- { u"nextFocusForward", 11 },
- { u"firstDayOfWeek", 11 },
- { u"showWeekNumber", 11 },
- { u"minDate", 11 },
- { u"maxDate", 11 },
- { u"shownWeekCount", 11 },
- { u"selectedWeekBackgroundColor", 11 },
- { u"focusedMonthDateColor", 11 },
- { u"unfocusedMonthDateColor", 11 },
- { u"weekNumberColor", 11 },
- { u"weekSeparatorLineColor", 11 },
- { u"selectedDateVerticalBar", 11 },
- { u"weekDayTextAppearance", 11 },
- { u"dateTextAppearance", 11 },
- { u"solidColor", 11 },
- { u"spinnersShown", 11 },
- { u"calendarViewShown", 11 },
- { u"state_multiline", 11 },
- { u"detailsElementBackground", 11 },
- { u"textColorHighlightInverse", 11 },
- { u"textColorLinkInverse", 11 },
- { u"editTextColor", 11 },
- { u"editTextBackground", 11 },
- { u"horizontalScrollViewStyle", 11 },
- { u"layerType", 11 },
- { u"alertDialogIcon", 11 },
- { u"windowMinWidthMajor", 11 },
- { u"windowMinWidthMinor", 11 },
- { u"queryHint", 11 },
- { u"fastScrollTextColor", 11 },
- { u"largeHeap", 11 },
- { u"windowCloseOnTouchOutside", 11 },
- { u"datePickerStyle", 11 },
- { u"calendarViewStyle", 11 },
- { u"textEditSidePasteWindowLayout", 11 },
- { u"textEditSideNoPasteWindowLayout", 11 },
- { u"actionMenuTextAppearance", 11 },
- { u"actionMenuTextColor", 11 },
- { u"textCursorDrawable", 12 },
- { u"resizeMode", 12 },
- { u"requiresSmallestWidthDp", 12 },
- { u"compatibleWidthLimitDp", 12 },
- { u"largestWidthLimitDp", 12 },
- { u"state_hovered", 13 },
- { u"state_drag_can_accept", 13 },
- { u"state_drag_hovered", 13 },
- { u"stopWithTask", 13 },
- { u"switchTextOn", 13 },
- { u"switchTextOff", 13 },
- { u"switchPreferenceStyle", 13 },
- { u"switchTextAppearance", 13 },
- { u"track", 13 },
- { u"switchMinWidth", 13 },
- { u"switchPadding", 13 },
- { u"thumbTextPadding", 13 },
- { u"textSuggestionsWindowStyle", 13 },
- { u"textEditSuggestionItemLayout", 13 },
- { u"rowCount", 13 },
- { u"rowOrderPreserved", 13 },
- { u"columnCount", 13 },
- { u"columnOrderPreserved", 13 },
- { u"useDefaultMargins", 13 },
- { u"alignmentMode", 13 },
- { u"layout_row", 13 },
- { u"layout_rowSpan", 13 },
- { u"layout_columnSpan", 13 },
- { u"actionModeSelectAllDrawable", 13 },
- { u"isAuxiliary", 13 },
- { u"accessibilityEventTypes", 13 },
- { u"packageNames", 13 },
- { u"accessibilityFeedbackType", 13 },
- { u"notificationTimeout", 13 },
- { u"accessibilityFlags", 13 },
- { u"canRetrieveWindowContent", 13 },
- { u"listPreferredItemHeightLarge", 13 },
- { u"listPreferredItemHeightSmall", 13 },
- { u"actionBarSplitStyle", 13 },
- { u"actionProviderClass", 13 },
- { u"backgroundStacked", 13 },
- { u"backgroundSplit", 13 },
- { u"textAllCaps", 13 },
- { u"colorPressedHighlight", 13 },
- { u"colorLongPressedHighlight", 13 },
- { u"colorFocusedHighlight", 13 },
- { u"colorActivatedHighlight", 13 },
- { u"colorMultiSelectHighlight", 13 },
- { u"drawableStart", 13 },
- { u"drawableEnd", 13 },
- { u"actionModeStyle", 13 },
- { u"minResizeWidth", 13 },
- { u"minResizeHeight", 13 },
- { u"actionBarWidgetTheme", 13 },
- { u"uiOptions", 13 },
- { u"subtypeLocale", 13 },
- { u"subtypeExtraValue", 13 },
- { u"actionBarDivider", 13 },
- { u"actionBarItemBackground", 13 },
- { u"actionModeSplitBackground", 13 },
- { u"textAppearanceListItem", 13 },
- { u"textAppearanceListItemSmall", 13 },
- { u"targetDescriptions", 13 },
- { u"directionDescriptions", 13 },
- { u"overridesImplicitlyEnabledSubtype", 13 },
- { u"listPreferredItemPaddingLeft", 13 },
- { u"listPreferredItemPaddingRight", 13 },
- { u"requiresFadingEdge", 13 },
- { u"publicKey", 13 },
- { u"parentActivityName", 16 },
- { u"isolatedProcess", 16 },
- { u"importantForAccessibility", 16 },
- { u"keyboardLayout", 16 },
- { u"fontFamily", 16 },
- { u"mediaRouteButtonStyle", 16 },
- { u"mediaRouteTypes", 16 },
- { u"supportsRtl", 17 },
- { u"textDirection", 17 },
- { u"textAlignment", 17 },
- { u"layoutDirection", 17 },
- { u"paddingStart", 17 },
- { u"paddingEnd", 17 },
- { u"layout_marginStart", 17 },
- { u"layout_marginEnd", 17 },
- { u"layout_toStartOf", 17 },
- { u"layout_toEndOf", 17 },
- { u"layout_alignStart", 17 },
- { u"layout_alignEnd", 17 },
- { u"layout_alignParentStart", 17 },
- { u"layout_alignParentEnd", 17 },
- { u"listPreferredItemPaddingStart", 17 },
- { u"listPreferredItemPaddingEnd", 17 },
- { u"singleUser", 17 },
- { u"presentationTheme", 17 },
- { u"subtypeId", 17 },
- { u"initialKeyguardLayout", 17 },
- { u"widgetCategory", 17 },
- { u"permissionGroupFlags", 17 },
- { u"labelFor", 17 },
- { u"permissionFlags", 17 },
- { u"checkedTextViewStyle", 17 },
- { u"showOnLockScreen", 17 },
- { u"format12Hour", 17 },
- { u"format24Hour", 17 },
- { u"timeZone", 17 },
- { u"mipMap", 18 },
- { u"mirrorForRtl", 18 },
- { u"windowOverscan", 18 },
- { u"requiredForAllUsers", 18 },
- { u"indicatorStart", 18 },
- { u"indicatorEnd", 18 },
- { u"childIndicatorStart", 18 },
- { u"childIndicatorEnd", 18 },
- { u"restrictedAccountType", 18 },
- { u"requiredAccountType", 18 },
- { u"canRequestTouchExplorationMode", 18 },
- { u"canRequestEnhancedWebAccessibility", 18 },
- { u"canRequestFilterKeyEvents", 18 },
- { u"layoutMode", 18 },
- { u"keySet", 19 },
- { u"targetId", 19 },
- { u"fromScene", 19 },
- { u"toScene", 19 },
- { u"transition", 19 },
- { u"transitionOrdering", 19 },
- { u"fadingMode", 19 },
- { u"startDelay", 19 },
- { u"ssp", 19 },
- { u"sspPrefix", 19 },
- { u"sspPattern", 19 },
- { u"addPrintersActivity", 19 },
- { u"vendor", 19 },
- { u"category", 19 },
- { u"isAsciiCapable", 19 },
- { u"autoMirrored", 19 },
- { u"supportsSwitchingToNextInputMethod", 19 },
- { u"requireDeviceUnlock", 19 },
- { u"apduServiceBanner", 19 },
- { u"accessibilityLiveRegion", 19 },
- { u"windowTranslucentStatus", 19 },
- { u"windowTranslucentNavigation", 19 },
- { u"advancedPrintOptionsActivity", 19 },
- { u"banner", 20 },
- { u"windowSwipeToDismiss", 20 },
- { u"isGame", 20 },
- { u"allowEmbedded", 20 },
- { u"setupActivity", 20 },
- { u"fastScrollStyle", 21 },
- { u"windowContentTransitions", 21 },
- { u"windowContentTransitionManager", 21 },
- { u"translationZ", 21 },
- { u"tintMode", 21 },
- { u"controlX1", 21 },
- { u"controlY1", 21 },
- { u"controlX2", 21 },
- { u"controlY2", 21 },
- { u"transitionName", 21 },
- { u"transitionGroup", 21 },
- { u"viewportWidth", 21 },
- { u"viewportHeight", 21 },
- { u"fillColor", 21 },
- { u"pathData", 21 },
- { u"strokeColor", 21 },
- { u"strokeWidth", 21 },
- { u"trimPathStart", 21 },
- { u"trimPathEnd", 21 },
- { u"trimPathOffset", 21 },
- { u"strokeLineCap", 21 },
- { u"strokeLineJoin", 21 },
- { u"strokeMiterLimit", 21 },
- { u"colorControlNormal", 21 },
- { u"colorControlActivated", 21 },
- { u"colorButtonNormal", 21 },
- { u"colorControlHighlight", 21 },
- { u"persistableMode", 21 },
- { u"titleTextAppearance", 21 },
- { u"subtitleTextAppearance", 21 },
- { u"slideEdge", 21 },
- { u"actionBarTheme", 21 },
- { u"textAppearanceListItemSecondary", 21 },
- { u"colorPrimary", 21 },
- { u"colorPrimaryDark", 21 },
- { u"colorAccent", 21 },
- { u"nestedScrollingEnabled", 21 },
- { u"windowEnterTransition", 21 },
- { u"windowExitTransition", 21 },
- { u"windowSharedElementEnterTransition", 21 },
- { u"windowSharedElementExitTransition", 21 },
- { u"windowAllowReturnTransitionOverlap", 21 },
- { u"windowAllowEnterTransitionOverlap", 21 },
- { u"sessionService", 21 },
- { u"stackViewStyle", 21 },
- { u"switchStyle", 21 },
- { u"elevation", 21 },
- { u"excludeId", 21 },
- { u"excludeClass", 21 },
- { u"hideOnContentScroll", 21 },
- { u"actionOverflowMenuStyle", 21 },
- { u"documentLaunchMode", 21 },
- { u"maxRecents", 21 },
- { u"autoRemoveFromRecents", 21 },
- { u"stateListAnimator", 21 },
- { u"toId", 21 },
- { u"fromId", 21 },
- { u"reversible", 21 },
- { u"splitTrack", 21 },
- { u"targetName", 21 },
- { u"excludeName", 21 },
- { u"matchOrder", 21 },
- { u"windowDrawsSystemBarBackgrounds", 21 },
- { u"statusBarColor", 21 },
- { u"navigationBarColor", 21 },
- { u"contentInsetStart", 21 },
- { u"contentInsetEnd", 21 },
- { u"contentInsetLeft", 21 },
- { u"contentInsetRight", 21 },
- { u"paddingMode", 21 },
- { u"layout_rowWeight", 21 },
- { u"layout_columnWeight", 21 },
- { u"translateX", 21 },
- { u"translateY", 21 },
- { u"selectableItemBackgroundBorderless", 21 },
- { u"elegantTextHeight", 21 },
- { u"searchKeyphraseId", 21 },
- { u"searchKeyphrase", 21 },
- { u"searchKeyphraseSupportedLocales", 21 },
- { u"windowTransitionBackgroundFadeDuration", 21 },
- { u"overlapAnchor", 21 },
- { u"progressTint", 21 },
- { u"progressTintMode", 21 },
- { u"progressBackgroundTint", 21 },
- { u"progressBackgroundTintMode", 21 },
- { u"secondaryProgressTint", 21 },
- { u"secondaryProgressTintMode", 21 },
- { u"indeterminateTint", 21 },
- { u"indeterminateTintMode", 21 },
- { u"backgroundTint", 21 },
- { u"backgroundTintMode", 21 },
- { u"foregroundTint", 21 },
- { u"foregroundTintMode", 21 },
- { u"buttonTint", 21 },
- { u"buttonTintMode", 21 },
- { u"thumbTint", 21 },
- { u"thumbTintMode", 21 },
- { u"fullBackupOnly", 21 },
- { u"propertyXName", 21 },
- { u"propertyYName", 21 },
- { u"relinquishTaskIdentity", 21 },
- { u"tileModeX", 21 },
- { u"tileModeY", 21 },
- { u"actionModeShareDrawable", 21 },
- { u"actionModeFindDrawable", 21 },
- { u"actionModeWebSearchDrawable", 21 },
- { u"transitionVisibilityMode", 21 },
- { u"minimumHorizontalAngle", 21 },
- { u"minimumVerticalAngle", 21 },
- { u"maximumAngle", 21 },
- { u"searchViewStyle", 21 },
- { u"closeIcon", 21 },
- { u"goIcon", 21 },
- { u"searchIcon", 21 },
- { u"voiceIcon", 21 },
- { u"commitIcon", 21 },
- { u"suggestionRowLayout", 21 },
- { u"queryBackground", 21 },
- { u"submitBackground", 21 },
- { u"buttonBarPositiveButtonStyle", 21 },
- { u"buttonBarNeutralButtonStyle", 21 },
- { u"buttonBarNegativeButtonStyle", 21 },
- { u"popupElevation", 21 },
- { u"actionBarPopupTheme", 21 },
- { u"multiArch", 21 },
- { u"touchscreenBlocksFocus", 21 },
- { u"windowElevation", 21 },
- { u"launchTaskBehindTargetAnimation", 21 },
- { u"launchTaskBehindSourceAnimation", 21 },
- { u"restrictionType", 21 },
- { u"dayOfWeekBackground", 21 },
- { u"dayOfWeekTextAppearance", 21 },
- { u"headerMonthTextAppearance", 21 },
- { u"headerDayOfMonthTextAppearance", 21 },
- { u"headerYearTextAppearance", 21 },
- { u"yearListItemTextAppearance", 21 },
- { u"yearListSelectorColor", 21 },
- { u"calendarTextColor", 21 },
- { u"recognitionService", 21 },
- { u"timePickerStyle", 21 },
- { u"timePickerDialogTheme", 21 },
- { u"headerTimeTextAppearance", 21 },
- { u"headerAmPmTextAppearance", 21 },
- { u"numbersTextColor", 21 },
- { u"numbersBackgroundColor", 21 },
- { u"numbersSelectorColor", 21 },
- { u"amPmTextColor", 21 },
- { u"amPmBackgroundColor", 21 },
- { u"searchKeyphraseRecognitionFlags", 21 },
- { u"checkMarkTint", 21 },
- { u"checkMarkTintMode", 21 },
- { u"popupTheme", 21 },
- { u"toolbarStyle", 21 },
- { u"windowClipToOutline", 21 },
- { u"datePickerDialogTheme", 21 },
- { u"showText", 21 },
- { u"windowReturnTransition", 21 },
- { u"windowReenterTransition", 21 },
- { u"windowSharedElementReturnTransition", 21 },
- { u"windowSharedElementReenterTransition", 21 },
- { u"resumeWhilePausing", 21 },
- { u"datePickerMode", 21 },
- { u"timePickerMode", 21 },
- { u"inset", 21 },
- { u"letterSpacing", 21 },
- { u"fontFeatureSettings", 21 },
- { u"outlineProvider", 21 },
- { u"contentAgeHint", 21 },
- { u"country", 21 },
- { u"windowSharedElementsUseOverlay", 21 },
- { u"reparent", 21 },
- { u"reparentWithOverlay", 21 },
- { u"ambientShadowAlpha", 21 },
- { u"spotShadowAlpha", 21 },
- { u"navigationIcon", 21 },
- { u"navigationContentDescription", 21 },
- { u"fragmentExitTransition", 21 },
- { u"fragmentEnterTransition", 21 },
- { u"fragmentSharedElementEnterTransition", 21 },
- { u"fragmentReturnTransition", 21 },
- { u"fragmentSharedElementReturnTransition", 21 },
- { u"fragmentReenterTransition", 21 },
- { u"fragmentAllowEnterTransitionOverlap", 21 },
- { u"fragmentAllowReturnTransitionOverlap", 21 },
- { u"patternPathData", 21 },
- { u"strokeAlpha", 21 },
- { u"fillAlpha", 21 },
- { u"windowActivityTransitions", 21 },
- { u"colorEdgeEffect", 21 }
+static const std::unordered_map<std::string, size_t> sAttrMap = {
+ { "marqueeRepeatLimit", 2 },
+ { "windowNoDisplay", 3 },
+ { "backgroundDimEnabled", 3 },
+ { "inputType", 3 },
+ { "isDefault", 3 },
+ { "windowDisablePreview", 3 },
+ { "privateImeOptions", 3 },
+ { "editorExtras", 3 },
+ { "settingsActivity", 3 },
+ { "fastScrollEnabled", 3 },
+ { "reqTouchScreen", 3 },
+ { "reqKeyboardType", 3 },
+ { "reqHardKeyboard", 3 },
+ { "reqNavigation", 3 },
+ { "windowSoftInputMode", 3 },
+ { "imeFullscreenBackground", 3 },
+ { "noHistory", 3 },
+ { "headerDividersEnabled", 3 },
+ { "footerDividersEnabled", 3 },
+ { "candidatesTextStyleSpans", 3 },
+ { "smoothScrollbar", 3 },
+ { "reqFiveWayNav", 3 },
+ { "keyBackground", 3 },
+ { "keyTextSize", 3 },
+ { "labelTextSize", 3 },
+ { "keyTextColor", 3 },
+ { "keyPreviewLayout", 3 },
+ { "keyPreviewOffset", 3 },
+ { "keyPreviewHeight", 3 },
+ { "verticalCorrection", 3 },
+ { "popupLayout", 3 },
+ { "state_long_pressable", 3 },
+ { "keyWidth", 3 },
+ { "keyHeight", 3 },
+ { "horizontalGap", 3 },
+ { "verticalGap", 3 },
+ { "rowEdgeFlags", 3 },
+ { "codes", 3 },
+ { "popupKeyboard", 3 },
+ { "popupCharacters", 3 },
+ { "keyEdgeFlags", 3 },
+ { "isModifier", 3 },
+ { "isSticky", 3 },
+ { "isRepeatable", 3 },
+ { "iconPreview", 3 },
+ { "keyOutputText", 3 },
+ { "keyLabel", 3 },
+ { "keyIcon", 3 },
+ { "keyboardMode", 3 },
+ { "isScrollContainer", 3 },
+ { "fillEnabled", 3 },
+ { "updatePeriodMillis", 3 },
+ { "initialLayout", 3 },
+ { "voiceSearchMode", 3 },
+ { "voiceLanguageModel", 3 },
+ { "voicePromptText", 3 },
+ { "voiceLanguage", 3 },
+ { "voiceMaxResults", 3 },
+ { "bottomOffset", 3 },
+ { "topOffset", 3 },
+ { "allowSingleTap", 3 },
+ { "handle", 3 },
+ { "content", 3 },
+ { "animateOnClick", 3 },
+ { "configure", 3 },
+ { "hapticFeedbackEnabled", 3 },
+ { "innerRadius", 3 },
+ { "thickness", 3 },
+ { "sharedUserLabel", 3 },
+ { "dropDownWidth", 3 },
+ { "dropDownAnchor", 3 },
+ { "imeOptions", 3 },
+ { "imeActionLabel", 3 },
+ { "imeActionId", 3 },
+ { "imeExtractEnterAnimation", 3 },
+ { "imeExtractExitAnimation", 3 },
+ { "tension", 4 },
+ { "extraTension", 4 },
+ { "anyDensity", 4 },
+ { "searchSuggestThreshold", 4 },
+ { "includeInGlobalSearch", 4 },
+ { "onClick", 4 },
+ { "targetSdkVersion", 4 },
+ { "maxSdkVersion", 4 },
+ { "testOnly", 4 },
+ { "contentDescription", 4 },
+ { "gestureStrokeWidth", 4 },
+ { "gestureColor", 4 },
+ { "uncertainGestureColor", 4 },
+ { "fadeOffset", 4 },
+ { "fadeDuration", 4 },
+ { "gestureStrokeType", 4 },
+ { "gestureStrokeLengthThreshold", 4 },
+ { "gestureStrokeSquarenessThreshold", 4 },
+ { "gestureStrokeAngleThreshold", 4 },
+ { "eventsInterceptionEnabled", 4 },
+ { "fadeEnabled", 4 },
+ { "backupAgent", 4 },
+ { "allowBackup", 4 },
+ { "glEsVersion", 4 },
+ { "queryAfterZeroResults", 4 },
+ { "dropDownHeight", 4 },
+ { "smallScreens", 4 },
+ { "normalScreens", 4 },
+ { "largeScreens", 4 },
+ { "progressBarStyleInverse", 4 },
+ { "progressBarStyleSmallInverse", 4 },
+ { "progressBarStyleLargeInverse", 4 },
+ { "searchSettingsDescription", 4 },
+ { "textColorPrimaryInverseDisableOnly", 4 },
+ { "autoUrlDetect", 4 },
+ { "resizeable", 4 },
+ { "required", 5 },
+ { "accountType", 5 },
+ { "contentAuthority", 5 },
+ { "userVisible", 5 },
+ { "windowShowWallpaper", 5 },
+ { "wallpaperOpenEnterAnimation", 5 },
+ { "wallpaperOpenExitAnimation", 5 },
+ { "wallpaperCloseEnterAnimation", 5 },
+ { "wallpaperCloseExitAnimation", 5 },
+ { "wallpaperIntraOpenEnterAnimation", 5 },
+ { "wallpaperIntraOpenExitAnimation", 5 },
+ { "wallpaperIntraCloseEnterAnimation", 5 },
+ { "wallpaperIntraCloseExitAnimation", 5 },
+ { "supportsUploading", 5 },
+ { "killAfterRestore", 5 },
+ { "restoreNeedsApplication", 5 },
+ { "smallIcon", 5 },
+ { "accountPreferences", 5 },
+ { "textAppearanceSearchResultSubtitle", 5 },
+ { "textAppearanceSearchResultTitle", 5 },
+ { "summaryColumn", 5 },
+ { "detailColumn", 5 },
+ { "detailSocialSummary", 5 },
+ { "thumbnail", 5 },
+ { "detachWallpaper", 5 },
+ { "finishOnCloseSystemDialogs", 5 },
+ { "scrollbarFadeDuration", 5 },
+ { "scrollbarDefaultDelayBeforeFade", 5 },
+ { "fadeScrollbars", 5 },
+ { "colorBackgroundCacheHint", 5 },
+ { "dropDownHorizontalOffset", 5 },
+ { "dropDownVerticalOffset", 5 },
+ { "quickContactBadgeStyleWindowSmall", 6 },
+ { "quickContactBadgeStyleWindowMedium", 6 },
+ { "quickContactBadgeStyleWindowLarge", 6 },
+ { "quickContactBadgeStyleSmallWindowSmall", 6 },
+ { "quickContactBadgeStyleSmallWindowMedium", 6 },
+ { "quickContactBadgeStyleSmallWindowLarge", 6 },
+ { "author", 7 },
+ { "autoStart", 7 },
+ { "expandableListViewWhiteStyle", 8 },
+ { "installLocation", 8 },
+ { "vmSafeMode", 8 },
+ { "webTextViewStyle", 8 },
+ { "restoreAnyVersion", 8 },
+ { "tabStripLeft", 8 },
+ { "tabStripRight", 8 },
+ { "tabStripEnabled", 8 },
+ { "logo", 9 },
+ { "xlargeScreens", 9 },
+ { "immersive", 9 },
+ { "overScrollMode", 9 },
+ { "overScrollHeader", 9 },
+ { "overScrollFooter", 9 },
+ { "filterTouchesWhenObscured", 9 },
+ { "textSelectHandleLeft", 9 },
+ { "textSelectHandleRight", 9 },
+ { "textSelectHandle", 9 },
+ { "textSelectHandleWindowStyle", 9 },
+ { "popupAnimationStyle", 9 },
+ { "screenSize", 9 },
+ { "screenDensity", 9 },
+ { "allContactsName", 11 },
+ { "windowActionBar", 11 },
+ { "actionBarStyle", 11 },
+ { "navigationMode", 11 },
+ { "displayOptions", 11 },
+ { "subtitle", 11 },
+ { "customNavigationLayout", 11 },
+ { "hardwareAccelerated", 11 },
+ { "measureWithLargestChild", 11 },
+ { "animateFirstView", 11 },
+ { "dropDownSpinnerStyle", 11 },
+ { "actionDropDownStyle", 11 },
+ { "actionButtonStyle", 11 },
+ { "showAsAction", 11 },
+ { "previewImage", 11 },
+ { "actionModeBackground", 11 },
+ { "actionModeCloseDrawable", 11 },
+ { "windowActionModeOverlay", 11 },
+ { "valueFrom", 11 },
+ { "valueTo", 11 },
+ { "valueType", 11 },
+ { "propertyName", 11 },
+ { "ordering", 11 },
+ { "fragment", 11 },
+ { "windowActionBarOverlay", 11 },
+ { "fragmentOpenEnterAnimation", 11 },
+ { "fragmentOpenExitAnimation", 11 },
+ { "fragmentCloseEnterAnimation", 11 },
+ { "fragmentCloseExitAnimation", 11 },
+ { "fragmentFadeEnterAnimation", 11 },
+ { "fragmentFadeExitAnimation", 11 },
+ { "actionBarSize", 11 },
+ { "imeSubtypeLocale", 11 },
+ { "imeSubtypeMode", 11 },
+ { "imeSubtypeExtraValue", 11 },
+ { "splitMotionEvents", 11 },
+ { "listChoiceBackgroundIndicator", 11 },
+ { "spinnerMode", 11 },
+ { "animateLayoutChanges", 11 },
+ { "actionBarTabStyle", 11 },
+ { "actionBarTabBarStyle", 11 },
+ { "actionBarTabTextStyle", 11 },
+ { "actionOverflowButtonStyle", 11 },
+ { "actionModeCloseButtonStyle", 11 },
+ { "titleTextStyle", 11 },
+ { "subtitleTextStyle", 11 },
+ { "iconifiedByDefault", 11 },
+ { "actionLayout", 11 },
+ { "actionViewClass", 11 },
+ { "activatedBackgroundIndicator", 11 },
+ { "state_activated", 11 },
+ { "listPopupWindowStyle", 11 },
+ { "popupMenuStyle", 11 },
+ { "textAppearanceLargePopupMen", 11 },
+ { "textAppearanceSmallPopupMen", 11 },
+ { "breadCrumbTitle", 11 },
+ { "breadCrumbShortTitle", 11 },
+ { "listDividerAlertDialog", 11 },
+ { "textColorAlertDialogListItem", 11 },
+ { "loopViews", 11 },
+ { "dialogTheme", 11 },
+ { "alertDialogTheme", 11 },
+ { "dividerVertical", 11 },
+ { "homeAsUpIndicator", 11 },
+ { "enterFadeDuration", 11 },
+ { "exitFadeDuration", 11 },
+ { "selectableItemBackground", 11 },
+ { "autoAdvanceViewId", 11 },
+ { "useIntrinsicSizeAsMinimum", 11 },
+ { "actionModeCutDrawable", 11 },
+ { "actionModeCopyDrawable", 11 },
+ { "actionModePasteDrawable", 11 },
+ { "textEditPasteWindowLayout", 11 },
+ { "textEditNoPasteWindowLayout", 11 },
+ { "textIsSelectable", 11 },
+ { "windowEnableSplitTouch", 11 },
+ { "indeterminateProgressStyle", 11 },
+ { "progressBarPadding", 11 },
+ { "animationResolution", 11 },
+ { "state_accelerated", 11 },
+ { "baseline", 11 },
+ { "homeLayout", 11 },
+ { "opacity", 11 },
+ { "alpha", 11 },
+ { "transformPivotX", 11 },
+ { "transformPivotY", 11 },
+ { "translationX", 11 },
+ { "translationY", 11 },
+ { "scaleX", 11 },
+ { "scaleY", 11 },
+ { "rotation", 11 },
+ { "rotationX", 11 },
+ { "rotationY", 11 },
+ { "showDividers", 11 },
+ { "dividerPadding", 11 },
+ { "borderlessButtonStyle", 11 },
+ { "dividerHorizontal", 11 },
+ { "itemPadding", 11 },
+ { "buttonBarStyle", 11 },
+ { "buttonBarButtonStyle", 11 },
+ { "segmentedButtonStyle", 11 },
+ { "staticWallpaperPreview", 11 },
+ { "allowParallelSyncs", 11 },
+ { "isAlwaysSyncable", 11 },
+ { "verticalScrollbarPosition", 11 },
+ { "fastScrollAlwaysVisible", 11 },
+ { "fastScrollThumbDrawable", 11 },
+ { "fastScrollPreviewBackgroundLeft", 11 },
+ { "fastScrollPreviewBackgroundRight", 11 },
+ { "fastScrollTrackDrawable", 11 },
+ { "fastScrollOverlayPosition", 11 },
+ { "customTokens", 11 },
+ { "nextFocusForward", 11 },
+ { "firstDayOfWeek", 11 },
+ { "showWeekNumber", 11 },
+ { "minDate", 11 },
+ { "maxDate", 11 },
+ { "shownWeekCount", 11 },
+ { "selectedWeekBackgroundColor", 11 },
+ { "focusedMonthDateColor", 11 },
+ { "unfocusedMonthDateColor", 11 },
+ { "weekNumberColor", 11 },
+ { "weekSeparatorLineColor", 11 },
+ { "selectedDateVerticalBar", 11 },
+ { "weekDayTextAppearance", 11 },
+ { "dateTextAppearance", 11 },
+ { "solidColor", 11 },
+ { "spinnersShown", 11 },
+ { "calendarViewShown", 11 },
+ { "state_multiline", 11 },
+ { "detailsElementBackground", 11 },
+ { "textColorHighlightInverse", 11 },
+ { "textColorLinkInverse", 11 },
+ { "editTextColor", 11 },
+ { "editTextBackground", 11 },
+ { "horizontalScrollViewStyle", 11 },
+ { "layerType", 11 },
+ { "alertDialogIcon", 11 },
+ { "windowMinWidthMajor", 11 },
+ { "windowMinWidthMinor", 11 },
+ { "queryHint", 11 },
+ { "fastScrollTextColor", 11 },
+ { "largeHeap", 11 },
+ { "windowCloseOnTouchOutside", 11 },
+ { "datePickerStyle", 11 },
+ { "calendarViewStyle", 11 },
+ { "textEditSidePasteWindowLayout", 11 },
+ { "textEditSideNoPasteWindowLayout", 11 },
+ { "actionMenuTextAppearance", 11 },
+ { "actionMenuTextColor", 11 },
+ { "textCursorDrawable", 12 },
+ { "resizeMode", 12 },
+ { "requiresSmallestWidthDp", 12 },
+ { "compatibleWidthLimitDp", 12 },
+ { "largestWidthLimitDp", 12 },
+ { "state_hovered", 13 },
+ { "state_drag_can_accept", 13 },
+ { "state_drag_hovered", 13 },
+ { "stopWithTask", 13 },
+ { "switchTextOn", 13 },
+ { "switchTextOff", 13 },
+ { "switchPreferenceStyle", 13 },
+ { "switchTextAppearance", 13 },
+ { "track", 13 },
+ { "switchMinWidth", 13 },
+ { "switchPadding", 13 },
+ { "thumbTextPadding", 13 },
+ { "textSuggestionsWindowStyle", 13 },
+ { "textEditSuggestionItemLayout", 13 },
+ { "rowCount", 13 },
+ { "rowOrderPreserved", 13 },
+ { "columnCount", 13 },
+ { "columnOrderPreserved", 13 },
+ { "useDefaultMargins", 13 },
+ { "alignmentMode", 13 },
+ { "layout_row", 13 },
+ { "layout_rowSpan", 13 },
+ { "layout_columnSpan", 13 },
+ { "actionModeSelectAllDrawable", 13 },
+ { "isAuxiliary", 13 },
+ { "accessibilityEventTypes", 13 },
+ { "packageNames", 13 },
+ { "accessibilityFeedbackType", 13 },
+ { "notificationTimeout", 13 },
+ { "accessibilityFlags", 13 },
+ { "canRetrieveWindowContent", 13 },
+ { "listPreferredItemHeightLarge", 13 },
+ { "listPreferredItemHeightSmall", 13 },
+ { "actionBarSplitStyle", 13 },
+ { "actionProviderClass", 13 },
+ { "backgroundStacked", 13 },
+ { "backgroundSplit", 13 },
+ { "textAllCaps", 13 },
+ { "colorPressedHighlight", 13 },
+ { "colorLongPressedHighlight", 13 },
+ { "colorFocusedHighlight", 13 },
+ { "colorActivatedHighlight", 13 },
+ { "colorMultiSelectHighlight", 13 },
+ { "drawableStart", 13 },
+ { "drawableEnd", 13 },
+ { "actionModeStyle", 13 },
+ { "minResizeWidth", 13 },
+ { "minResizeHeight", 13 },
+ { "actionBarWidgetTheme", 13 },
+ { "uiOptions", 13 },
+ { "subtypeLocale", 13 },
+ { "subtypeExtraValue", 13 },
+ { "actionBarDivider", 13 },
+ { "actionBarItemBackground", 13 },
+ { "actionModeSplitBackground", 13 },
+ { "textAppearanceListItem", 13 },
+ { "textAppearanceListItemSmall", 13 },
+ { "targetDescriptions", 13 },
+ { "directionDescriptions", 13 },
+ { "overridesImplicitlyEnabledSubtype", 13 },
+ { "listPreferredItemPaddingLeft", 13 },
+ { "listPreferredItemPaddingRight", 13 },
+ { "requiresFadingEdge", 13 },
+ { "publicKey", 13 },
+ { "parentActivityName", 16 },
+ { "isolatedProcess", 16 },
+ { "importantForAccessibility", 16 },
+ { "keyboardLayout", 16 },
+ { "fontFamily", 16 },
+ { "mediaRouteButtonStyle", 16 },
+ { "mediaRouteTypes", 16 },
+ { "supportsRtl", 17 },
+ { "textDirection", 17 },
+ { "textAlignment", 17 },
+ { "layoutDirection", 17 },
+ { "paddingStart", 17 },
+ { "paddingEnd", 17 },
+ { "layout_marginStart", 17 },
+ { "layout_marginEnd", 17 },
+ { "layout_toStartOf", 17 },
+ { "layout_toEndOf", 17 },
+ { "layout_alignStart", 17 },
+ { "layout_alignEnd", 17 },
+ { "layout_alignParentStart", 17 },
+ { "layout_alignParentEnd", 17 },
+ { "listPreferredItemPaddingStart", 17 },
+ { "listPreferredItemPaddingEnd", 17 },
+ { "singleUser", 17 },
+ { "presentationTheme", 17 },
+ { "subtypeId", 17 },
+ { "initialKeyguardLayout", 17 },
+ { "widgetCategory", 17 },
+ { "permissionGroupFlags", 17 },
+ { "labelFor", 17 },
+ { "permissionFlags", 17 },
+ { "checkedTextViewStyle", 17 },
+ { "showOnLockScreen", 17 },
+ { "format12Hour", 17 },
+ { "format24Hour", 17 },
+ { "timeZone", 17 },
+ { "mipMap", 18 },
+ { "mirrorForRtl", 18 },
+ { "windowOverscan", 18 },
+ { "requiredForAllUsers", 18 },
+ { "indicatorStart", 18 },
+ { "indicatorEnd", 18 },
+ { "childIndicatorStart", 18 },
+ { "childIndicatorEnd", 18 },
+ { "restrictedAccountType", 18 },
+ { "requiredAccountType", 18 },
+ { "canRequestTouchExplorationMode", 18 },
+ { "canRequestEnhancedWebAccessibility", 18 },
+ { "canRequestFilterKeyEvents", 18 },
+ { "layoutMode", 18 },
+ { "keySet", 19 },
+ { "targetId", 19 },
+ { "fromScene", 19 },
+ { "toScene", 19 },
+ { "transition", 19 },
+ { "transitionOrdering", 19 },
+ { "fadingMode", 19 },
+ { "startDelay", 19 },
+ { "ssp", 19 },
+ { "sspPrefix", 19 },
+ { "sspPattern", 19 },
+ { "addPrintersActivity", 19 },
+ { "vendor", 19 },
+ { "category", 19 },
+ { "isAsciiCapable", 19 },
+ { "autoMirrored", 19 },
+ { "supportsSwitchingToNextInputMethod", 19 },
+ { "requireDeviceUnlock", 19 },
+ { "apduServiceBanner", 19 },
+ { "accessibilityLiveRegion", 19 },
+ { "windowTranslucentStatus", 19 },
+ { "windowTranslucentNavigation", 19 },
+ { "advancedPrintOptionsActivity", 19 },
+ { "banner", 20 },
+ { "windowSwipeToDismiss", 20 },
+ { "isGame", 20 },
+ { "allowEmbedded", 20 },
+ { "setupActivity", 20 },
+ { "fastScrollStyle", 21 },
+ { "windowContentTransitions", 21 },
+ { "windowContentTransitionManager", 21 },
+ { "translationZ", 21 },
+ { "tintMode", 21 },
+ { "controlX1", 21 },
+ { "controlY1", 21 },
+ { "controlX2", 21 },
+ { "controlY2", 21 },
+ { "transitionName", 21 },
+ { "transitionGroup", 21 },
+ { "viewportWidth", 21 },
+ { "viewportHeight", 21 },
+ { "fillColor", 21 },
+ { "pathData", 21 },
+ { "strokeColor", 21 },
+ { "strokeWidth", 21 },
+ { "trimPathStart", 21 },
+ { "trimPathEnd", 21 },
+ { "trimPathOffset", 21 },
+ { "strokeLineCap", 21 },
+ { "strokeLineJoin", 21 },
+ { "strokeMiterLimit", 21 },
+ { "colorControlNormal", 21 },
+ { "colorControlActivated", 21 },
+ { "colorButtonNormal", 21 },
+ { "colorControlHighlight", 21 },
+ { "persistableMode", 21 },
+ { "titleTextAppearance", 21 },
+ { "subtitleTextAppearance", 21 },
+ { "slideEdge", 21 },
+ { "actionBarTheme", 21 },
+ { "textAppearanceListItemSecondary", 21 },
+ { "colorPrimary", 21 },
+ { "colorPrimaryDark", 21 },
+ { "colorAccent", 21 },
+ { "nestedScrollingEnabled", 21 },
+ { "windowEnterTransition", 21 },
+ { "windowExitTransition", 21 },
+ { "windowSharedElementEnterTransition", 21 },
+ { "windowSharedElementExitTransition", 21 },
+ { "windowAllowReturnTransitionOverlap", 21 },
+ { "windowAllowEnterTransitionOverlap", 21 },
+ { "sessionService", 21 },
+ { "stackViewStyle", 21 },
+ { "switchStyle", 21 },
+ { "elevation", 21 },
+ { "excludeId", 21 },
+ { "excludeClass", 21 },
+ { "hideOnContentScroll", 21 },
+ { "actionOverflowMenuStyle", 21 },
+ { "documentLaunchMode", 21 },
+ { "maxRecents", 21 },
+ { "autoRemoveFromRecents", 21 },
+ { "stateListAnimator", 21 },
+ { "toId", 21 },
+ { "fromId", 21 },
+ { "reversible", 21 },
+ { "splitTrack", 21 },
+ { "targetName", 21 },
+ { "excludeName", 21 },
+ { "matchOrder", 21 },
+ { "windowDrawsSystemBarBackgrounds", 21 },
+ { "statusBarColor", 21 },
+ { "navigationBarColor", 21 },
+ { "contentInsetStart", 21 },
+ { "contentInsetEnd", 21 },
+ { "contentInsetLeft", 21 },
+ { "contentInsetRight", 21 },
+ { "paddingMode", 21 },
+ { "layout_rowWeight", 21 },
+ { "layout_columnWeight", 21 },
+ { "translateX", 21 },
+ { "translateY", 21 },
+ { "selectableItemBackgroundBorderless", 21 },
+ { "elegantTextHeight", 21 },
+ { "searchKeyphraseId", 21 },
+ { "searchKeyphrase", 21 },
+ { "searchKeyphraseSupportedLocales", 21 },
+ { "windowTransitionBackgroundFadeDuration", 21 },
+ { "overlapAnchor", 21 },
+ { "progressTint", 21 },
+ { "progressTintMode", 21 },
+ { "progressBackgroundTint", 21 },
+ { "progressBackgroundTintMode", 21 },
+ { "secondaryProgressTint", 21 },
+ { "secondaryProgressTintMode", 21 },
+ { "indeterminateTint", 21 },
+ { "indeterminateTintMode", 21 },
+ { "backgroundTint", 21 },
+ { "backgroundTintMode", 21 },
+ { "foregroundTint", 21 },
+ { "foregroundTintMode", 21 },
+ { "buttonTint", 21 },
+ { "buttonTintMode", 21 },
+ { "thumbTint", 21 },
+ { "thumbTintMode", 21 },
+ { "fullBackupOnly", 21 },
+ { "propertyXName", 21 },
+ { "propertyYName", 21 },
+ { "relinquishTaskIdentity", 21 },
+ { "tileModeX", 21 },
+ { "tileModeY", 21 },
+ { "actionModeShareDrawable", 21 },
+ { "actionModeFindDrawable", 21 },
+ { "actionModeWebSearchDrawable", 21 },
+ { "transitionVisibilityMode", 21 },
+ { "minimumHorizontalAngle", 21 },
+ { "minimumVerticalAngle", 21 },
+ { "maximumAngle", 21 },
+ { "searchViewStyle", 21 },
+ { "closeIcon", 21 },
+ { "goIcon", 21 },
+ { "searchIcon", 21 },
+ { "voiceIcon", 21 },
+ { "commitIcon", 21 },
+ { "suggestionRowLayout", 21 },
+ { "queryBackground", 21 },
+ { "submitBackground", 21 },
+ { "buttonBarPositiveButtonStyle", 21 },
+ { "buttonBarNeutralButtonStyle", 21 },
+ { "buttonBarNegativeButtonStyle", 21 },
+ { "popupElevation", 21 },
+ { "actionBarPopupTheme", 21 },
+ { "multiArch", 21 },
+ { "touchscreenBlocksFocus", 21 },
+ { "windowElevation", 21 },
+ { "launchTaskBehindTargetAnimation", 21 },
+ { "launchTaskBehindSourceAnimation", 21 },
+ { "restrictionType", 21 },
+ { "dayOfWeekBackground", 21 },
+ { "dayOfWeekTextAppearance", 21 },
+ { "headerMonthTextAppearance", 21 },
+ { "headerDayOfMonthTextAppearance", 21 },
+ { "headerYearTextAppearance", 21 },
+ { "yearListItemTextAppearance", 21 },
+ { "yearListSelectorColor", 21 },
+ { "calendarTextColor", 21 },
+ { "recognitionService", 21 },
+ { "timePickerStyle", 21 },
+ { "timePickerDialogTheme", 21 },
+ { "headerTimeTextAppearance", 21 },
+ { "headerAmPmTextAppearance", 21 },
+ { "numbersTextColor", 21 },
+ { "numbersBackgroundColor", 21 },
+ { "numbersSelectorColor", 21 },
+ { "amPmTextColor", 21 },
+ { "amPmBackgroundColor", 21 },
+ { "searchKeyphraseRecognitionFlags", 21 },
+ { "checkMarkTint", 21 },
+ { "checkMarkTintMode", 21 },
+ { "popupTheme", 21 },
+ { "toolbarStyle", 21 },
+ { "windowClipToOutline", 21 },
+ { "datePickerDialogTheme", 21 },
+ { "showText", 21 },
+ { "windowReturnTransition", 21 },
+ { "windowReenterTransition", 21 },
+ { "windowSharedElementReturnTransition", 21 },
+ { "windowSharedElementReenterTransition", 21 },
+ { "resumeWhilePausing", 21 },
+ { "datePickerMode", 21 },
+ { "timePickerMode", 21 },
+ { "inset", 21 },
+ { "letterSpacing", 21 },
+ { "fontFeatureSettings", 21 },
+ { "outlineProvider", 21 },
+ { "contentAgeHint", 21 },
+ { "country", 21 },
+ { "windowSharedElementsUseOverlay", 21 },
+ { "reparent", 21 },
+ { "reparentWithOverlay", 21 },
+ { "ambientShadowAlpha", 21 },
+ { "spotShadowAlpha", 21 },
+ { "navigationIcon", 21 },
+ { "navigationContentDescription", 21 },
+ { "fragmentExitTransition", 21 },
+ { "fragmentEnterTransition", 21 },
+ { "fragmentSharedElementEnterTransition", 21 },
+ { "fragmentReturnTransition", 21 },
+ { "fragmentSharedElementReturnTransition", 21 },
+ { "fragmentReenterTransition", 21 },
+ { "fragmentAllowEnterTransitionOverlap", 21 },
+ { "fragmentAllowReturnTransitionOverlap", 21 },
+ { "patternPathData", 21 },
+ { "strokeAlpha", 21 },
+ { "fillAlpha", 21 },
+ { "windowActivityTransitions", 21 },
+ { "colorEdgeEffect", 21 }
};
size_t findAttributeSdkLevel(const ResourceName& name) {
- if (name.package != u"android" && name.type != ResourceType::kAttr) {
+ if (name.package != "android" && name.type != ResourceType::kAttr) {
return 0;
}
@@ -738,8 +738,8 @@
return SDK_LOLLIPOP_MR1;
}
-std::pair<StringPiece16, int> getDevelopmentSdkCodeNameAndVersion() {
- return std::make_pair(StringPiece16(sDevelopmentSdkCodeName), sDevelopmentSdkLevel);
+std::pair<StringPiece, int> getDevelopmentSdkCodeNameAndVersion() {
+ return std::make_pair(StringPiece(sDevelopmentSdkCodeName), sDevelopmentSdkLevel);
}
} // namespace aapt
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index a6dba8b..f28679f 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -49,7 +49,7 @@
size_t findAttributeSdkLevel(ResourceId id);
size_t findAttributeSdkLevel(const ResourceName& name);
-std::pair<StringPiece16, int> getDevelopmentSdkCodeNameAndVersion();
+std::pair<StringPiece, int> getDevelopmentSdkCodeNameAndVersion();
} // namespace aapt
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index aadb00b..fe4b967 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -59,11 +59,11 @@
return *this;
}
-const std::u16string* StringPool::Ref::operator->() const {
+const std::string* StringPool::Ref::operator->() const {
return &mEntry->value;
}
-const std::u16string& StringPool::Ref::operator*() const {
+const std::string& StringPool::Ref::operator*() const {
return mEntry->value;
}
@@ -124,15 +124,15 @@
return mEntry->str.getContext();
}
-StringPool::Ref StringPool::makeRef(const StringPiece16& str) {
+StringPool::Ref StringPool::makeRef(const StringPiece& str) {
return makeRefImpl(str, Context{}, true);
}
-StringPool::Ref StringPool::makeRef(const StringPiece16& str, const Context& context) {
+StringPool::Ref StringPool::makeRef(const StringPiece& str, const Context& context) {
return makeRefImpl(str, context, true);
}
-StringPool::Ref StringPool::makeRefImpl(const StringPiece16& str, const Context& context,
+StringPool::Ref StringPool::makeRefImpl(const StringPiece& str, const Context& context,
bool unique) {
if (unique) {
auto iter = mIndexedStrings.find(str);
@@ -147,7 +147,7 @@
entry->index = mStrings.size();
entry->ref = 0;
mStrings.emplace_back(entry);
- mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry));
+ mIndexedStrings.insert(std::make_pair(StringPiece(entry->value), entry));
return Ref(entry);
}
@@ -162,13 +162,12 @@
entry->index = mStrings.size();
entry->ref = 0;
mStrings.emplace_back(entry);
- mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry));
+ mIndexedStrings.insert(std::make_pair(StringPiece(entry->value), entry));
StyleEntry* styleEntry = new StyleEntry();
styleEntry->str = Ref(entry);
for (const aapt::Span& span : str.spans) {
- styleEntry->spans.emplace_back(Span{makeRef(span.name),
- span.firstChar, span.lastChar});
+ styleEntry->spans.emplace_back(Span{ makeRef(span.name), span.firstChar, span.lastChar });
}
styleEntry->ref = 0;
mStyles.emplace_back(styleEntry);
@@ -182,7 +181,7 @@
entry->index = mStrings.size();
entry->ref = 0;
mStrings.emplace_back(entry);
- mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry));
+ mIndexedStrings.insert(std::make_pair(StringPiece(entry->value), entry));
StyleEntry* styleEntry = new StyleEntry();
styleEntry->str = Ref(entry);
@@ -320,33 +319,40 @@
indices++;
if (utf8) {
- std::string encoded = util::utf16ToUtf8(entry->value);
+ const std::string& encoded = entry->value;
+ const ssize_t utf16Length = utf8_to_utf16_length(
+ reinterpret_cast<const uint8_t*>(entry->value.data()), entry->value.size());
+ assert(utf16Length >= 0);
- const size_t totalSize = encodedLengthUnits<char>(entry->value.size())
+ const size_t totalSize = encodedLengthUnits<char>(utf16Length)
+ encodedLengthUnits<char>(encoded.length())
+ encoded.size() + 1;
char* data = out->nextBlock<char>(totalSize);
- // First encode the actual UTF16 string length.
- data = encodeLength(data, entry->value.size());
+ // First encode the UTF16 string length.
+ data = encodeLength(data, utf16Length);
- // Now encode the size of the converted UTF8 string.
+ // Now encode the size of the real UTF8 string.
data = encodeLength(data, encoded.length());
strncpy(data, encoded.data(), encoded.size());
+
} else {
- const size_t totalSize = encodedLengthUnits<char16_t>(entry->value.size())
- + entry->value.size() + 1;
+ const std::u16string encoded = util::utf8ToUtf16(entry->value);
+ const ssize_t utf16Length = encoded.size();
+
+ // Total number of 16-bit words to write.
+ const size_t totalSize = encodedLengthUnits<char16_t>(utf16Length) + encoded.size() + 1;
char16_t* data = out->nextBlock<char16_t>(totalSize);
// Encode the actual UTF16 string length.
- data = encodeLength(data, entry->value.size());
- const size_t byteLength = entry->value.size() * sizeof(char16_t);
+ data = encodeLength(data, utf16Length);
+ const size_t byteLength = encoded.size() * sizeof(char16_t);
// NOTE: For some reason, strncpy16(data, entry->value.data(), entry->value.size())
// truncates the string.
- memcpy(data, entry->value.data(), byteLength);
+ memcpy(data, encoded.data(), byteLength);
// The null-terminating character is already here due to the block of data being set
// to 0s on allocation.
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index 5f88543..72ae9d1 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -30,13 +30,13 @@
namespace aapt {
struct Span {
- std::u16string name;
+ std::string name;
uint32_t firstChar;
uint32_t lastChar;
};
struct StyleString {
- std::u16string str;
+ std::string str;
std::vector<Span> spans;
};
@@ -56,8 +56,8 @@
~Ref();
Ref& operator=(const Ref& rhs);
- const std::u16string* operator->() const;
- const std::u16string& operator*() const;
+ const std::string* operator->() const;
+ const std::string& operator*() const;
size_t getIndex() const;
const Context& getContext() const;
@@ -95,7 +95,7 @@
class Entry {
public:
- std::u16string value;
+ std::string value;
Context context;
size_t index;
@@ -136,14 +136,14 @@
* Adds a string to the pool, unless it already exists. Returns
* a reference to the string in the pool.
*/
- Ref makeRef(const StringPiece16& str);
+ Ref makeRef(const StringPiece& str);
/**
* Adds a string to the pool, unless it already exists, with a context
* object that can be used when sorting the string pool. Returns
* a reference to the string in the pool.
*/
- Ref makeRef(const StringPiece16& str, const Context& context);
+ Ref makeRef(const StringPiece& str, const Context& context);
/**
* Adds a style to the string pool and returns a reference to it.
@@ -195,11 +195,11 @@
static bool flatten(BigBuffer* out, const StringPool& pool, bool utf8);
- Ref makeRefImpl(const StringPiece16& str, const Context& context, bool unique);
+ Ref makeRefImpl(const StringPiece& str, const Context& context, bool unique);
std::vector<std::unique_ptr<Entry>> mStrings;
std::vector<std::unique_ptr<StyleEntry>> mStyles;
- std::unordered_multimap<StringPiece16, Entry*> mIndexedStrings;
+ std::unordered_multimap<StringPiece, Entry*> mIndexedStrings;
};
//
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 562d80e..1367af7 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -15,9 +15,9 @@
*/
#include "StringPool.h"
+#include "test/Test.h"
#include "util/Util.h"
-#include <gtest/gtest.h>
#include <string>
namespace aapt {
@@ -25,37 +25,37 @@
TEST(StringPoolTest, InsertOneString) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"wut");
- EXPECT_EQ(*ref, u"wut");
+ StringPool::Ref ref = pool.makeRef("wut");
+ EXPECT_EQ(*ref, "wut");
}
TEST(StringPoolTest, InsertTwoUniqueStrings) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"wut");
- StringPool::Ref ref2 = pool.makeRef(u"hey");
+ StringPool::Ref ref = pool.makeRef("wut");
+ StringPool::Ref ref2 = pool.makeRef("hey");
- EXPECT_EQ(*ref, u"wut");
- EXPECT_EQ(*ref2, u"hey");
+ EXPECT_EQ(*ref, "wut");
+ EXPECT_EQ(*ref2, "hey");
}
TEST(StringPoolTest, DoNotInsertNewDuplicateString) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"wut");
- StringPool::Ref ref2 = pool.makeRef(u"wut");
+ StringPool::Ref ref = pool.makeRef("wut");
+ StringPool::Ref ref2 = pool.makeRef("wut");
- EXPECT_EQ(*ref, u"wut");
- EXPECT_EQ(*ref2, u"wut");
+ EXPECT_EQ(*ref, "wut");
+ EXPECT_EQ(*ref2, "wut");
EXPECT_EQ(1u, pool.size());
}
TEST(StringPoolTest, MaintainInsertionOrderIndex) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"z");
- StringPool::Ref ref2 = pool.makeRef(u"a");
- StringPool::Ref ref3 = pool.makeRef(u"m");
+ StringPool::Ref ref = pool.makeRef("z");
+ StringPool::Ref ref2 = pool.makeRef("a");
+ StringPool::Ref ref3 = pool.makeRef("m");
EXPECT_EQ(0u, ref.getIndex());
EXPECT_EQ(1u, ref2.getIndex());
@@ -65,39 +65,39 @@
TEST(StringPoolTest, PruneStringsWithNoReferences) {
StringPool pool;
- StringPool::Ref refA = pool.makeRef(u"foo");
+ StringPool::Ref refA = pool.makeRef("foo");
{
- StringPool::Ref ref = pool.makeRef(u"wut");
- EXPECT_EQ(*ref, u"wut");
+ StringPool::Ref ref = pool.makeRef("wut");
+ EXPECT_EQ(*ref, "wut");
EXPECT_EQ(2u, pool.size());
}
- StringPool::Ref refB = pool.makeRef(u"bar");
+ StringPool::Ref refB = pool.makeRef("bar");
EXPECT_EQ(3u, pool.size());
pool.prune();
EXPECT_EQ(2u, pool.size());
StringPool::const_iterator iter = begin(pool);
- EXPECT_EQ((*iter)->value, u"foo");
+ EXPECT_EQ((*iter)->value, "foo");
EXPECT_LT((*iter)->index, 2u);
++iter;
- EXPECT_EQ((*iter)->value, u"bar");
+ EXPECT_EQ((*iter)->value, "bar");
EXPECT_LT((*iter)->index, 2u);
}
TEST(StringPoolTest, SortAndMaintainIndexesInReferences) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"z");
- StringPool::StyleRef ref2 = pool.makeRef(StyleString{ {u"a"} });
- StringPool::Ref ref3 = pool.makeRef(u"m");
+ StringPool::Ref ref = pool.makeRef("z");
+ StringPool::StyleRef ref2 = pool.makeRef(StyleString{ {"a"} });
+ StringPool::Ref ref3 = pool.makeRef("m");
- EXPECT_EQ(*ref, u"z");
+ EXPECT_EQ(*ref, "z");
EXPECT_EQ(0u, ref.getIndex());
- EXPECT_EQ(*(ref2->str), u"a");
+ EXPECT_EQ(*(ref2->str), "a");
EXPECT_EQ(1u, ref2.getIndex());
- EXPECT_EQ(*ref3, u"m");
+ EXPECT_EQ(*ref3, "m");
EXPECT_EQ(2u, ref3.getIndex());
pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
@@ -105,30 +105,30 @@
});
- EXPECT_EQ(*ref, u"z");
+ EXPECT_EQ(*ref, "z");
EXPECT_EQ(2u, ref.getIndex());
- EXPECT_EQ(*(ref2->str), u"a");
+ EXPECT_EQ(*(ref2->str), "a");
EXPECT_EQ(0u, ref2.getIndex());
- EXPECT_EQ(*ref3, u"m");
+ EXPECT_EQ(*ref3, "m");
EXPECT_EQ(1u, ref3.getIndex());
}
TEST(StringPoolTest, SortAndStillDedupe) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"z");
- StringPool::Ref ref2 = pool.makeRef(u"a");
- StringPool::Ref ref3 = pool.makeRef(u"m");
+ StringPool::Ref ref = pool.makeRef("z");
+ StringPool::Ref ref2 = pool.makeRef("a");
+ StringPool::Ref ref3 = pool.makeRef("m");
pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
return a.value < b.value;
});
- StringPool::Ref ref4 = pool.makeRef(u"z");
- StringPool::Ref ref5 = pool.makeRef(u"a");
- StringPool::Ref ref6 = pool.makeRef(u"m");
+ StringPool::Ref ref4 = pool.makeRef("z");
+ StringPool::Ref ref5 = pool.makeRef("a");
+ StringPool::Ref ref6 = pool.makeRef("m");
EXPECT_EQ(ref4.getIndex(), ref.getIndex());
EXPECT_EQ(ref5.getIndex(), ref2.getIndex());
@@ -139,20 +139,20 @@
StringPool pool;
StyleString str {
- { u"android" },
+ { "android" },
{
- Span{ { u"b" }, 2, 6 }
+ Span{ { "b" }, 2, 6 }
}
};
StringPool::StyleRef ref = pool.makeRef(str);
EXPECT_EQ(0u, ref.getIndex());
- EXPECT_EQ(std::u16string(u"android"), *(ref->str));
+ EXPECT_EQ(std::string("android"), *(ref->str));
ASSERT_EQ(1u, ref->spans.size());
const StringPool::Span& span = ref->spans.front();
- EXPECT_EQ(*(span.name), u"b");
+ EXPECT_EQ(*(span.name), "b");
EXPECT_EQ(2u, span.firstChar);
EXPECT_EQ(6u, span.lastChar);
}
@@ -160,9 +160,9 @@
TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
StringPool pool;
- StringPool::Ref ref = pool.makeRef(u"android");
+ StringPool::Ref ref = pool.makeRef("android");
- StyleString str { { u"android" } };
+ StyleString str { { "android" } };
StringPool::StyleRef styleRef = pool.makeRef(str);
EXPECT_NE(ref.getIndex(), styleRef.getIndex());
@@ -184,7 +184,7 @@
using namespace android; // For NO_ERROR on Windows.
StringPool pool;
- pool.makeRef(u"\u093f");
+ pool.makeRef("\u093f");
BigBuffer buffer(1024);
StringPool::flattenUtf16(&buffer, pool);
@@ -198,20 +198,20 @@
EXPECT_EQ(0u, str[1]);
}
-constexpr const char16_t* sLongString = u"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使 用するその他のアプリは、起動しても更新されないことがあります。バッテリーセーバーは端末の充電中は自動的にOFFになります。";
+constexpr const char* sLongString = "バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使 用するその他のアプリは、起動しても更新されないことがあります。バッテリーセーバーは端末の充電中は自動的にOFFになります。";
-TEST(StringPoolTest, FlattenUtf8) {
+TEST(StringPoolTest, Flatten) {
using namespace android; // For NO_ERROR on Windows.
StringPool pool;
- StringPool::Ref ref1 = pool.makeRef(u"hello");
- StringPool::Ref ref2 = pool.makeRef(u"goodbye");
+ StringPool::Ref ref1 = pool.makeRef("hello");
+ StringPool::Ref ref2 = pool.makeRef("goodbye");
StringPool::Ref ref3 = pool.makeRef(sLongString);
- StringPool::Ref ref4 = pool.makeRef(u"");
+ StringPool::Ref ref4 = pool.makeRef("");
StringPool::StyleRef ref5 = pool.makeRef(StyleString{
- { u"style" },
- { Span{ { u"b" }, 0, 1 }, Span{ { u"i" }, 2, 3 } }
+ { "style" },
+ { Span{ { "b" }, 0, 1 }, Span{ { "i" }, 2, 3 } }
});
EXPECT_EQ(0u, ref1.getIndex());
@@ -220,30 +220,43 @@
EXPECT_EQ(3u, ref4.getIndex());
EXPECT_EQ(4u, ref5.getIndex());
- BigBuffer buffer(1024);
- StringPool::flattenUtf8(&buffer, pool);
+ BigBuffer buffers[2] = { BigBuffer(1024), BigBuffer(1024) };
+ StringPool::flattenUtf8(&buffers[0], pool);
+ StringPool::flattenUtf16(&buffers[1], pool);
- std::unique_ptr<uint8_t[]> data = util::copy(buffer);
- {
+ // Test both UTF-8 and UTF-16 buffers.
+ for (const BigBuffer& buffer : buffers) {
+ std::unique_ptr<uint8_t[]> data = util::copy(buffer);
+
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- EXPECT_EQ(util::getString(test, 0), u"hello");
- EXPECT_EQ(util::getString(test, 1), u"goodbye");
- EXPECT_EQ(util::getString(test, 2), sLongString);
+ EXPECT_EQ(std::string("hello"), util::getString(test, 0));
+ EXPECT_EQ(StringPiece16(u"hello"), util::getString16(test, 0));
+
+ EXPECT_EQ(std::string("goodbye"), util::getString(test, 1));
+ EXPECT_EQ(StringPiece16(u"goodbye"), util::getString16(test, 1));
+
+ EXPECT_EQ(StringPiece(sLongString), util::getString(test, 2));
+ EXPECT_EQ(util::utf8ToUtf16(sLongString), util::getString16(test, 2).toString());
+
size_t len;
- EXPECT_NE(nullptr, test.stringAt(3, &len));
- EXPECT_EQ(util::getString(test, 4), u"style");
+ EXPECT_TRUE(test.stringAt(3, &len) != nullptr || test.string8At(3, &len) != nullptr);
+
+ EXPECT_EQ(std::string("style"), util::getString(test, 4));
+ EXPECT_EQ(StringPiece16(u"style"), util::getString16(test, 4));
const ResStringPool_span* span = test.styleAt(4);
ASSERT_NE(nullptr, span);
- EXPECT_EQ(util::getString(test, span->name.index), u"b");
+ EXPECT_EQ(std::string("b"), util::getString(test, span->name.index));
+ EXPECT_EQ(StringPiece16(u"b"), util::getString16(test, span->name.index));
EXPECT_EQ(0u, span->firstChar);
EXPECT_EQ(1u, span->lastChar);
span++;
ASSERT_NE(ResStringPool_span::END, span->name.index);
- EXPECT_EQ(util::getString(test, span->name.index), u"i");
+ EXPECT_EQ(std::string("i"), util::getString(test, span->name.index));
+ EXPECT_EQ(StringPiece16(u"i"), util::getString16(test, span->name.index));
EXPECT_EQ(2u, span->firstChar);
EXPECT_EQ(3u, span->lastChar);
span++;
diff --git a/tools/aapt2/ValueVisitor_test.cpp b/tools/aapt2/ValueVisitor_test.cpp
index 1624079..11eab33 100644
--- a/tools/aapt2/ValueVisitor_test.cpp
+++ b/tools/aapt2/ValueVisitor_test.cpp
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-#include <string>
-
#include "ResourceValues.h"
-#include "util/Util.h"
#include "ValueVisitor.h"
-#include "test/Builders.h"
+#include "test/Test.h"
+#include "util/Util.h"
+
+#include <string>
namespace aapt {
@@ -51,7 +50,7 @@
};
TEST(ValueVisitorTest, VisitsReference) {
- Reference ref(ResourceName{u"android", ResourceType::kAttr, u"foo"});
+ Reference ref(ResourceName{"android", ResourceType::kAttr, "foo"});
SingleReferenceVisitor visitor;
ref.accept(&visitor);
@@ -60,8 +59,8 @@
TEST(ValueVisitorTest, VisitsReferencesInStyle) {
std::unique_ptr<Style> style = test::StyleBuilder()
- .setParent(u"@android:style/foo")
- .addItem(u"@android:attr/one", test::buildReference(u"@android:id/foo"))
+ .setParent("@android:style/foo")
+ .addItem("@android:attr/one", test::buildReference("@android:id/foo"))
.build();
StyleVisitor visitor;
@@ -74,11 +73,11 @@
}
TEST(ValueVisitorTest, ValueCast) {
- std::unique_ptr<Reference> ref = test::buildReference(u"@android:color/white");
+ std::unique_ptr<Reference> ref = test::buildReference("@android:color/white");
EXPECT_NE(valueCast<Reference>(ref.get()), nullptr);
std::unique_ptr<Style> style = test::StyleBuilder()
- .addItem(u"@android:attr/foo", test::buildReference(u"@android:color/black"))
+ .addItem("@android:attr/foo", test::buildReference("@android:color/black"))
.build();
EXPECT_NE(valueCast<Style>(style.get()), nullptr);
EXPECT_EQ(valueCast<Reference>(style.get()), nullptr);
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 5d11c40..39e4489 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -43,8 +43,8 @@
struct ResourcePathData {
Source source;
- std::u16string resourceDir;
- std::u16string name;
+ std::string resourceDir;
+ std::string name;
std::string extension;
// Original config str. We keep this because when we parse the config, we may add on
@@ -96,8 +96,8 @@
return ResourcePathData{
Source(path),
- util::utf8ToUtf16(dirStr),
- util::utf8ToUtf16(name),
+ dirStr.toString(),
+ name.toString(),
extension.toString(),
configStr.toString(),
config
@@ -127,7 +127,7 @@
}
static bool isHidden(const StringPiece& filename) {
- return util::stringStartsWith<char>(filename, ".");
+ return util::stringStartsWith(filename, ".");
}
/**
@@ -200,7 +200,7 @@
parserOptions.errorOnPositionalArguments = !options.legacyMode;
// If the filename includes donottranslate, then the default translatable is false.
- parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos;
+ parserOptions.translatable = pathData.name.find("donottranslate") == std::string::npos;
ResourceParser resParser(context->getDiagnostics(), &table, pathData.source,
pathData.config, parserOptions);
@@ -440,8 +440,8 @@
return nullptr;
}
- const std::u16string& getCompilationPackage() override {
- static std::u16string empty;
+ const std::string& getCompilationPackage() override {
+ static std::string empty;
return empty;
}
@@ -530,7 +530,7 @@
context.getDiagnostics()->note(DiagMessage(pathData.source) << "processing");
}
- if (pathData.resourceDir == u"values") {
+ if (pathData.resourceDir == "values") {
// Overwrite the extension.
pathData.extension = "arsc";
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index aa4a580..341c9b3 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -15,7 +15,6 @@
*/
#include "ResourceTable.h"
-
#include "compile/IdAssigner.h"
#include "process/IResourceTableConsumer.h"
#include "util/Util.h"
diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp
index e25a17a..802e99a 100644
--- a/tools/aapt2/compile/IdAssigner_test.cpp
+++ b/tools/aapt2/compile/IdAssigner_test.cpp
@@ -27,10 +27,10 @@
TEST(IdAssignerTest, AssignIds) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addSimple(u"@android:attr/foo")
- .addSimple(u"@android:attr/bar")
- .addSimple(u"@android:id/foo")
- .setPackageId(u"android", 0x01)
+ .addSimple("@android:attr/foo")
+ .addSimple("@android:attr/bar")
+ .addSimple("@android:id/foo")
+ .setPackageId("android", 0x01)
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
@@ -42,12 +42,12 @@
TEST(IdAssignerTest, AssignIdsWithReservedIds) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addSimple(u"@android:attr/foo", ResourceId(0x01040006))
- .addSimple(u"@android:attr/bar")
- .addSimple(u"@android:id/foo")
- .addSimple(u"@app:id/biz")
- .setPackageId(u"android", 0x01)
- .setPackageId(u"app", 0x7f)
+ .addSimple("@android:attr/foo", ResourceId(0x01040006))
+ .addSimple("@android:attr/bar")
+ .addSimple("@android:id/foo")
+ .addSimple("@app:id/biz")
+ .setPackageId("android", 0x01)
+ .setPackageId("app", 0x7f)
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
@@ -59,10 +59,10 @@
TEST(IdAssignerTest, FailWhenNonUniqueIdsAssigned) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addSimple(u"@android:attr/foo", ResourceId(0x01040006))
- .addSimple(u"@android:attr/bar", ResourceId(0x01040006))
- .setPackageId(u"android", 0x01)
- .setPackageId(u"app", 0x7f)
+ .addSimple("@android:attr/foo", ResourceId(0x01040006))
+ .addSimple("@android:attr/bar", ResourceId(0x01040006))
+ .setPackageId("android", 0x01)
+ .setPackageId("app", 0x7f)
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index bbf7f41..055d8b5 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -1234,7 +1234,7 @@
goto bail;
}
- if (util::stringEndsWith<char>(source.path, ".9.png")) {
+ if (util::stringEndsWith(source.path, ".9.png")) {
std::string errorMsg;
if (!do9Patch(&pngInfo, &errorMsg)) {
mDiag->error(DiagMessage() << errorMsg);
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index d080e16..732101f 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -29,7 +29,7 @@
StringPool* pool) {
Pseudolocalizer localizer(method);
- const StringPiece16 originalText = *string->value->str;
+ const StringPiece originalText = *string->value->str;
StyleString localized;
@@ -147,7 +147,7 @@
}
void visit(String* string) override {
- std::u16string result = mLocalizer.start() + mLocalizer.text(*string->value) +
+ std::string result = mLocalizer.start() + mLocalizer.text(*string->value) +
mLocalizer.end();
std::unique_ptr<String> localized = util::make_unique<String>(mPool->makeRef(result));
localized->setSource(string->getSource());
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
index 4cb6ea2..1816abc 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -15,21 +15,18 @@
*/
#include "compile/PseudolocaleGenerator.h"
-#include "test/Builders.h"
-#include "test/Common.h"
-#include "test/Context.h"
+#include "test/Test.h"
#include "util/Util.h"
#include <androidfw/ResourceTypes.h>
-#include <gtest/gtest.h>
namespace aapt {
TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
StringPool pool;
StyleString originalStyle;
- originalStyle.str = u"Hello world!";
- originalStyle.spans = { Span{ u"b", 2, 3 }, Span{ u"b", 6, 7 }, Span{ u"i", 1, 10 } };
+ originalStyle.str = "Hello world!";
+ originalStyle.spans = { Span{ "b", 2, 3 }, Span{ "b", 6, 7 }, Span{ "i", 1, 10 } };
std::unique_ptr<StyledString> newString = pseudolocalizeStyledString(
util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
@@ -38,51 +35,51 @@
EXPECT_EQ(originalStyle.str, *newString->value->str);
ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
- EXPECT_EQ(2u, newString->value->spans[0].firstChar);
- EXPECT_EQ(3u, newString->value->spans[0].lastChar);
- EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[0].name);
+ EXPECT_EQ(std::string("He").size(), newString->value->spans[0].firstChar);
+ EXPECT_EQ(std::string("Hel").size(), newString->value->spans[0].lastChar);
+ EXPECT_EQ(std::string("b"), *newString->value->spans[0].name);
- EXPECT_EQ(6u, newString->value->spans[1].firstChar);
- EXPECT_EQ(7u, newString->value->spans[1].lastChar);
- EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[1].name);
+ EXPECT_EQ(std::string("Hello ").size(), newString->value->spans[1].firstChar);
+ EXPECT_EQ(std::string("Hello w").size(), newString->value->spans[1].lastChar);
+ EXPECT_EQ(std::string("b"), *newString->value->spans[1].name);
- EXPECT_EQ(1u, newString->value->spans[2].firstChar);
- EXPECT_EQ(10u, newString->value->spans[2].lastChar);
- EXPECT_EQ(std::u16string(u"i"), *newString->value->spans[2].name);
+ EXPECT_EQ(std::string("H").size(), newString->value->spans[2].firstChar);
+ EXPECT_EQ(std::string("Hello worl").size(), newString->value->spans[2].lastChar);
+ EXPECT_EQ(std::string("i"), *newString->value->spans[2].name);
- originalStyle.spans.push_back(Span{ u"em", 0, 11u });
+ originalStyle.spans.push_back(Span{ "em", 0, 11u });
newString = pseudolocalizeStyledString(
util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
Pseudolocalizer::Method::kAccent, &pool);
- EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļð¡ one two]"), *newString->value->str);
+ EXPECT_EQ(std::string("[Ĥéļļö ŵöŕļð¡ one two]"), *newString->value->str);
ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
- EXPECT_EQ(3u, newString->value->spans[0].firstChar);
- EXPECT_EQ(4u, newString->value->spans[0].lastChar);
+ EXPECT_EQ(std::string("[Ĥé").size(), newString->value->spans[0].firstChar);
+ EXPECT_EQ(std::string("[Ĥéļ").size(), newString->value->spans[0].lastChar);
- EXPECT_EQ(7u, newString->value->spans[1].firstChar);
- EXPECT_EQ(8u, newString->value->spans[1].lastChar);
+ EXPECT_EQ(std::string("[Ĥéļļö ").size(), newString->value->spans[1].firstChar);
+ EXPECT_EQ(std::string("[Ĥéļļö ŵ").size(), newString->value->spans[1].lastChar);
- EXPECT_EQ(2u, newString->value->spans[2].firstChar);
- EXPECT_EQ(11u, newString->value->spans[2].lastChar);
+ EXPECT_EQ(std::string("[Ĥ").size(), newString->value->spans[2].firstChar);
+ EXPECT_EQ(std::string("[Ĥéļļö ŵöŕļ").size(), newString->value->spans[2].lastChar);
- EXPECT_EQ(1u, newString->value->spans[3].firstChar);
- EXPECT_EQ(12u, newString->value->spans[3].lastChar);
+ EXPECT_EQ(std::string("[").size(), newString->value->spans[3].firstChar);
+ EXPECT_EQ(std::string("[Ĥéļļö ŵöŕļð").size(), newString->value->spans[3].lastChar);
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addString(u"@android:string/one", u"one")
- .addString(u"@android:string/two", ResourceId{}, test::parseConfigOrDie("en"), u"two")
- .addString(u"@android:string/three", u"three")
- .addString(u"@android:string/three", ResourceId{}, test::parseConfigOrDie("en-rXA"),
- u"three")
- .addString(u"@android:string/four", u"four")
+ .addString("@android:string/one", "one")
+ .addString("@android:string/two", ResourceId{}, test::parseConfigOrDie("en"), "two")
+ .addString("@android:string/three", "three")
+ .addString("@android:string/three", ResourceId{}, test::parseConfigOrDie("en-rXA"),
+ "three")
+ .addString("@android:string/four", "four")
.build();
- String* val = test::getValue<String>(table.get(), u"@android:string/four");
+ String* val = test::getValue<String>(table.get(), "@android:string/four");
val->setTranslateable(false);
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
@@ -90,31 +87,31 @@
ASSERT_TRUE(generator.consume(context.get(), table.get()));
// Normal pseudolocalization should take place.
- ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/one",
test::parseConfigOrDie("en-rXA")));
- ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/one",
test::parseConfigOrDie("ar-rXB")));
// No default config for android:string/two, so no pseudlocales should exist.
- ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/two",
test::parseConfigOrDie("en-rXA")));
- ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/two",
test::parseConfigOrDie("ar-rXB")));
// Check that we didn't override manual pseudolocalization.
- val = test::getValueForConfig<String>(table.get(), u"@android:string/three",
+ val = test::getValueForConfig<String>(table.get(), "@android:string/three",
test::parseConfigOrDie("en-rXA"));
ASSERT_NE(nullptr, val);
- EXPECT_EQ(std::u16string(u"three"), *val->value);
+ EXPECT_EQ(std::string("three"), *val->value);
- ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/three",
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/three",
test::parseConfigOrDie("ar-rXB")));
// Check that four's translateable marker was honored.
- ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/four",
test::parseConfigOrDie("en-rXA")));
- ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), "@android:string/four",
test::parseConfigOrDie("ar-rXB")));
}
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
index 767d746..90d0d85 100644
--- a/tools/aapt2/compile/Pseudolocalizer.cpp
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -20,41 +20,41 @@
namespace aapt {
// String basis to generate expansion
-static const std::u16string k_expansion_string = u"one two three "
+static const std::string k_expansion_string = "one two three "
"four five six seven eight nine ten eleven twelve thirteen "
"fourteen fiveteen sixteen seventeen nineteen twenty";
// Special unicode characters to override directionality of the words
-static const std::u16string k_rlm = u"\u200f";
-static const std::u16string k_rlo = u"\u202e";
-static const std::u16string k_pdf = u"\u202c";
+static const std::string k_rlm = "\u200f";
+static const std::string k_rlo = "\u202e";
+static const std::string k_pdf = "\u202c";
// Placeholder marks
-static const std::u16string k_placeholder_open = u"\u00bb";
-static const std::u16string k_placeholder_close = u"\u00ab";
+static const std::string k_placeholder_open = "\u00bb";
+static const std::string k_placeholder_close = "\u00ab";
-static const char16_t k_arg_start = u'{';
-static const char16_t k_arg_end = u'}';
+static const char k_arg_start = '{';
+static const char k_arg_end = '}';
class PseudoMethodNone : public PseudoMethodImpl {
public:
- std::u16string text(const StringPiece16& text) override { return text.toString(); }
- std::u16string placeholder(const StringPiece16& text) override { return text.toString(); }
+ std::string text(const StringPiece& text) override { return text.toString(); }
+ std::string placeholder(const StringPiece& text) override { return text.toString(); }
};
class PseudoMethodBidi : public PseudoMethodImpl {
public:
- std::u16string text(const StringPiece16& text) override;
- std::u16string placeholder(const StringPiece16& text) override;
+ std::string text(const StringPiece& text) override;
+ std::string placeholder(const StringPiece& text) override;
};
class PseudoMethodAccent : public PseudoMethodImpl {
public:
PseudoMethodAccent() : mDepth(0), mWordCount(0), mLength(0) {}
- std::u16string start() override;
- std::u16string end() override;
- std::u16string text(const StringPiece16& text) override;
- std::u16string placeholder(const StringPiece16& text) override;
+ std::string start() override;
+ std::string end() override;
+ std::string text(const StringPiece& text) override;
+ std::string placeholder(const StringPiece& text) override;
private:
size_t mDepth;
size_t mWordCount;
@@ -79,12 +79,12 @@
}
}
-std::u16string Pseudolocalizer::text(const StringPiece16& text) {
- std::u16string out;
+std::string Pseudolocalizer::text(const StringPiece& text) {
+ std::string out;
size_t depth = mLastDepth;
size_t lastpos, pos;
const size_t length = text.size();
- const char16_t* str = text.data();
+ const char* str = text.data();
bool escaped = false;
for (lastpos = pos = 0; pos < length; pos++) {
char16_t c = str[pos];
@@ -111,7 +111,7 @@
}
size_t size = nextpos - lastpos;
if (size) {
- std::u16string chunk = text.substr(lastpos, size).toString();
+ std::string chunk = text.substr(lastpos, size).toString();
if (pseudo) {
chunk = mImpl->text(chunk);
} else if (str[lastpos] == k_arg_start && str[nextpos - 1] == k_arg_end) {
@@ -131,67 +131,67 @@
return out;
}
-static const char16_t* pseudolocalizeChar(const char16_t c) {
+static const char* pseudolocalizeChar(const char c) {
switch (c) {
- case 'a': return u"\u00e5";
- case 'b': return u"\u0253";
- case 'c': return u"\u00e7";
- case 'd': return u"\u00f0";
- case 'e': return u"\u00e9";
- case 'f': return u"\u0192";
- case 'g': return u"\u011d";
- case 'h': return u"\u0125";
- case 'i': return u"\u00ee";
- case 'j': return u"\u0135";
- case 'k': return u"\u0137";
- case 'l': return u"\u013c";
- case 'm': return u"\u1e3f";
- case 'n': return u"\u00f1";
- case 'o': return u"\u00f6";
- case 'p': return u"\u00fe";
- case 'q': return u"\u0051";
- case 'r': return u"\u0155";
- case 's': return u"\u0161";
- case 't': return u"\u0163";
- case 'u': return u"\u00fb";
- case 'v': return u"\u0056";
- case 'w': return u"\u0175";
- case 'x': return u"\u0445";
- case 'y': return u"\u00fd";
- case 'z': return u"\u017e";
- case 'A': return u"\u00c5";
- case 'B': return u"\u03b2";
- case 'C': return u"\u00c7";
- case 'D': return u"\u00d0";
- case 'E': return u"\u00c9";
- case 'G': return u"\u011c";
- case 'H': return u"\u0124";
- case 'I': return u"\u00ce";
- case 'J': return u"\u0134";
- case 'K': return u"\u0136";
- case 'L': return u"\u013b";
- case 'M': return u"\u1e3e";
- case 'N': return u"\u00d1";
- case 'O': return u"\u00d6";
- case 'P': return u"\u00de";
- case 'Q': return u"\u0071";
- case 'R': return u"\u0154";
- case 'S': return u"\u0160";
- case 'T': return u"\u0162";
- case 'U': return u"\u00db";
- case 'V': return u"\u03bd";
- case 'W': return u"\u0174";
- case 'X': return u"\u00d7";
- case 'Y': return u"\u00dd";
- case 'Z': return u"\u017d";
- case '!': return u"\u00a1";
- case '?': return u"\u00bf";
- case '$': return u"\u20ac";
- default: return NULL;
+ case 'a': return "\u00e5";
+ case 'b': return "\u0253";
+ case 'c': return "\u00e7";
+ case 'd': return "\u00f0";
+ case 'e': return "\u00e9";
+ case 'f': return "\u0192";
+ case 'g': return "\u011d";
+ case 'h': return "\u0125";
+ case 'i': return "\u00ee";
+ case 'j': return "\u0135";
+ case 'k': return "\u0137";
+ case 'l': return "\u013c";
+ case 'm': return "\u1e3f";
+ case 'n': return "\u00f1";
+ case 'o': return "\u00f6";
+ case 'p': return "\u00fe";
+ case 'q': return "\u0051";
+ case 'r': return "\u0155";
+ case 's': return "\u0161";
+ case 't': return "\u0163";
+ case 'u': return "\u00fb";
+ case 'v': return "\u0056";
+ case 'w': return "\u0175";
+ case 'x': return "\u0445";
+ case 'y': return "\u00fd";
+ case 'z': return "\u017e";
+ case 'A': return "\u00c5";
+ case 'B': return "\u03b2";
+ case 'C': return "\u00c7";
+ case 'D': return "\u00d0";
+ case 'E': return "\u00c9";
+ case 'G': return "\u011c";
+ case 'H': return "\u0124";
+ case 'I': return "\u00ce";
+ case 'J': return "\u0134";
+ case 'K': return "\u0136";
+ case 'L': return "\u013b";
+ case 'M': return "\u1e3e";
+ case 'N': return "\u00d1";
+ case 'O': return "\u00d6";
+ case 'P': return "\u00de";
+ case 'Q': return "\u0071";
+ case 'R': return "\u0154";
+ case 'S': return "\u0160";
+ case 'T': return "\u0162";
+ case 'U': return "\u00db";
+ case 'V': return "\u03bd";
+ case 'W': return "\u0174";
+ case 'X': return "\u00d7";
+ case 'Y': return "\u00dd";
+ case 'Z': return "\u017d";
+ case '!': return "\u00a1";
+ case '?': return "\u00bf";
+ case '$': return "\u20ac";
+ default: return nullptr;
}
}
-static bool isPossibleNormalPlaceholderEnd(const char16_t c) {
+static bool isPossibleNormalPlaceholderEnd(const char c) {
switch (c) {
case 's': return true;
case 'S': return true;
@@ -218,11 +218,11 @@
}
}
-static std::u16string pseudoGenerateExpansion(const unsigned int length) {
- std::u16string result = k_expansion_string;
- const char16_t* s = result.data();
+static std::string pseudoGenerateExpansion(const unsigned int length) {
+ std::string result = k_expansion_string;
+ const char* s = result.data();
if (result.size() < length) {
- result += u" ";
+ result += " ";
result += pseudoGenerateExpansion(length - result.size());
} else {
int ext = 0;
@@ -238,26 +238,26 @@
return result;
}
-std::u16string PseudoMethodAccent::start() {
- std::u16string result;
+std::string PseudoMethodAccent::start() {
+ std::string result;
if (mDepth == 0) {
- result = u"[";
+ result = "[";
}
mWordCount = mLength = 0;
mDepth++;
return result;
}
-std::u16string PseudoMethodAccent::end() {
- std::u16string result;
+std::string PseudoMethodAccent::end() {
+ std::string result;
if (mLength) {
- result += u" ";
+ result += " ";
result += pseudoGenerateExpansion(mWordCount > 3 ? mLength : mLength / 2);
}
mWordCount = mLength = 0;
mDepth--;
if (mDepth == 0) {
- result += u"]";
+ result += "]";
}
return result;
}
@@ -267,17 +267,17 @@
*
* Note: This leaves placeholder syntax untouched.
*/
-std::u16string PseudoMethodAccent::text(const StringPiece16& source)
+std::string PseudoMethodAccent::text(const StringPiece& source)
{
- const char16_t* s = source.data();
- std::u16string result;
+ const char* s = source.data();
+ std::string result;
const size_t I = source.size();
bool lastspace = true;
for (size_t i = 0; i < I; i++) {
- char16_t c = s[i];
+ char c = s[i];
if (c == '%') {
// Placeholder syntax, no need to pseudolocalize
- std::u16string chunk;
+ std::string chunk;
bool end = false;
chunk.append(&c, 1);
while (!end && i + 1 < I) {
@@ -300,7 +300,7 @@
bool tag_closed = false;
while (!tag_closed && i < I) {
if (c == '&') {
- std::u16string escapeText;
+ std::string escapeText;
escapeText.append(&c, 1);
bool end = false;
size_t htmlCodePos = i;
@@ -322,7 +322,7 @@
}
}
result += escapeText;
- if (escapeText != u"<") {
+ if (escapeText != "<") {
tag_closed = true;
}
continue;
@@ -338,11 +338,11 @@
}
} else {
// This is a pure text that should be pseudolocalized
- const char16_t* p = pseudolocalizeChar(c);
+ const char* p = pseudolocalizeChar(c);
if (p != nullptr) {
result += p;
} else {
- bool space = util::isspace16(c);
+ bool space = isspace(c);
if (lastspace && !space) {
mWordCount++;
}
@@ -356,19 +356,19 @@
return result;
}
-std::u16string PseudoMethodAccent::placeholder(const StringPiece16& source) {
+std::string PseudoMethodAccent::placeholder(const StringPiece& source) {
// Surround a placeholder with brackets
return k_placeholder_open + source.toString() + k_placeholder_close;
}
-std::u16string PseudoMethodBidi::text(const StringPiece16& source) {
- const char16_t* s = source.data();
- std::u16string result;
+std::string PseudoMethodBidi::text(const StringPiece& source) {
+ const char* s = source.data();
+ std::string result;
bool lastspace = true;
bool space = true;
for (size_t i = 0; i < source.size(); i++) {
- char16_t c = s[i];
- space = util::isspace16(c);
+ char c = s[i];
+ space = isspace(c);
if (lastspace && !space) {
// Word start
result += k_rlm + k_rlo;
@@ -386,7 +386,7 @@
return result;
}
-std::u16string PseudoMethodBidi::placeholder(const StringPiece16& source) {
+std::string PseudoMethodBidi::placeholder(const StringPiece& source) {
// Surround a placeholder with directionality change sequence
return k_rlm + k_rlo + source.toString() + k_pdf + k_rlm;
}
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
index 8818c17..7db88de 100644
--- a/tools/aapt2/compile/Pseudolocalizer.h
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -29,10 +29,10 @@
class PseudoMethodImpl {
public:
virtual ~PseudoMethodImpl() {}
- virtual std::u16string start() { return {}; }
- virtual std::u16string end() { return {}; }
- virtual std::u16string text(const StringPiece16& text) = 0;
- virtual std::u16string placeholder(const StringPiece16& text) = 0;
+ virtual std::string start() { return {}; }
+ virtual std::string end() { return {}; }
+ virtual std::string text(const StringPiece& text) = 0;
+ virtual std::string placeholder(const StringPiece& text) = 0;
};
class Pseudolocalizer {
@@ -45,9 +45,9 @@
Pseudolocalizer(Method method);
void setMethod(Method method);
- std::u16string start() { return mImpl->start(); }
- std::u16string end() { return mImpl->end(); }
- std::u16string text(const StringPiece16& text);
+ std::string start() { return mImpl->start(); }
+ std::string end() { return mImpl->end(); }
+ std::string text(const StringPiece& text);
private:
std::unique_ptr<PseudoMethodImpl> mImpl;
size_t mLastDepth;
diff --git a/tools/aapt2/compile/Pseudolocalizer_test.cpp b/tools/aapt2/compile/Pseudolocalizer_test.cpp
index 36c8896..c33e152 100644
--- a/tools/aapt2/compile/Pseudolocalizer_test.cpp
+++ b/tools/aapt2/compile/Pseudolocalizer_test.cpp
@@ -28,9 +28,8 @@
static ::testing::AssertionResult simpleHelper(const char* input, const char* expected,
Pseudolocalizer::Method method) {
Pseudolocalizer pseudo(method);
- std::string result = util::utf16ToUtf8(
- pseudo.start() + pseudo.text(util::utf8ToUtf16(input)) + pseudo.end());
- if (StringPiece(expected) != result) {
+ std::string result = pseudo.start() + pseudo.text(input) + pseudo.end();
+ if (result != expected) {
return ::testing::AssertionFailure() << expected << " != " << result;
}
return ::testing::AssertionSuccess();
@@ -40,12 +39,9 @@
const char* expected,
Pseudolocalizer::Method method) {
Pseudolocalizer pseudo(method);
- std::string result = util::utf16ToUtf8(pseudo.start() +
- pseudo.text(util::utf8ToUtf16(in1)) +
- pseudo.text(util::utf8ToUtf16(in2)) +
- pseudo.text(util::utf8ToUtf16(in3)) +
- pseudo.end());
- if (StringPiece(expected) != result) {
+ std::string result = pseudo.start() + pseudo.text(in1) + pseudo.text(in2) + pseudo.text(in3) +
+ pseudo.end();
+ if (result != expected) {
return ::testing::AssertionFailure() << expected << " != " << result;
}
return ::testing::AssertionSuccess();
@@ -218,10 +214,10 @@
TEST(PseudolocalizerTest, RedefineMethod) {
Pseudolocalizer pseudo(Pseudolocalizer::Method::kAccent);
- std::u16string result = pseudo.text(u"Hello, ");
+ std::string result = pseudo.text("Hello, ");
pseudo.setMethod(Pseudolocalizer::Method::kNone);
- result += pseudo.text(u"world!");
- ASSERT_EQ(StringPiece("Ĥéļļö, world!"), util::utf16ToUtf8(result));
+ result += pseudo.text("world!");
+ ASSERT_EQ(StringPiece("Ĥéļļö, world!"), result);
}
} // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index a37ea86..ea1ced3 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -38,13 +38,13 @@
ASSERT_TRUE(collector.consume(context.get(), doc.get()));
EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
- SourcedResourceName{ test::parseNameOrDie(u"@id/foo"), 3u }));
+ SourcedResourceName{ test::parseNameOrDie("@id/foo"), 3u }));
EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
- SourcedResourceName{ test::parseNameOrDie(u"@id/bar"), 3u }));
+ SourcedResourceName{ test::parseNameOrDie("@id/bar"), 3u }));
EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
- SourcedResourceName{ test::parseNameOrDie(u"@id/car"), 6u }));
+ SourcedResourceName{ test::parseNameOrDie("@id/car"), 6u }));
}
TEST(XmlIdCollectorTest, DontCollectNonIds) {
diff --git a/tools/aapt2/diff/Diff.cpp b/tools/aapt2/diff/Diff.cpp
index 1ff6ef6..9b1f057 100644
--- a/tools/aapt2/diff/Diff.cpp
+++ b/tools/aapt2/diff/Diff.cpp
@@ -28,7 +28,7 @@
class DiffContext : public IAaptContext {
public:
- const std::u16string& getCompilationPackage() override {
+ const std::string& getCompilationPackage() override {
return mEmpty;
}
@@ -57,7 +57,7 @@
}
private:
- std::u16string mEmpty;
+ std::string mEmpty;
StdErrDiagnostics mDiagnostics;
NameMangler mNameMangler = NameMangler(NameManglerPolicy{});
SymbolTable mSymbolTable;
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
index 8f0dd3a..88c6f64 100644
--- a/tools/aapt2/dump/Dump.cpp
+++ b/tools/aapt2/dump/Dump.cpp
@@ -137,8 +137,8 @@
return nullptr;
}
- const std::u16string& getCompilationPackage() override {
- static std::u16string empty;
+ const std::string& getCompilationPackage() override {
+ static std::string empty;
return empty;
}
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 28a7928..5fbb0fe 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -25,6 +25,7 @@
#include <android-base/macros.h>
#include <algorithm>
+#include <sstream>
#include <type_traits>
#include <numeric>
@@ -231,7 +232,8 @@
}
// Copy the package name in device endianness.
- strcpy16_htod(pkgHeader->name, arraysize(pkgHeader->name), mPackage->name);
+ strcpy16_htod(pkgHeader->name, arraysize(pkgHeader->name),
+ util::utf8ToUtf16(mPackage->name));
// Serialize the types. We do this now so that our type and key strings
// are populated. We write those first.
@@ -423,9 +425,9 @@
// If there is a gap in the type IDs, fill in the StringPool
// with empty values until we reach the ID we expect.
while (type->id.value() > expectedTypeId) {
- std::u16string typeName(u"?");
- typeName += expectedTypeId;
- mTypePool.makeRef(typeName);
+ std::stringstream typeName;
+ typeName << "?" << expectedTypeId;
+ mTypePool.makeRef(typeName.str());
expectedTypeId++;
}
expectedTypeId++;
diff --git a/tools/aapt2/flatten/TableFlattener_test.cpp b/tools/aapt2/flatten/TableFlattener_test.cpp
index d0f831e..e720e7e 100644
--- a/tools/aapt2/flatten/TableFlattener_test.cpp
+++ b/tools/aapt2/flatten/TableFlattener_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "ResourceUtils.h"
#include "flatten/TableFlattener.h"
#include "test/Test.h"
#include "unflatten/BinaryResourceParser.h"
@@ -27,7 +28,7 @@
public:
void SetUp() override {
mContext = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
.build();
}
@@ -62,7 +63,7 @@
}
::testing::AssertionResult exists(ResTable* table,
- const StringPiece16& expectedName,
+ const StringPiece& expectedName,
const ResourceId expectedId,
const ConfigDescription& expectedConfig,
const uint8_t expectedDataType, const uint32_t expectedData,
@@ -104,25 +105,16 @@
return ::testing::AssertionFailure() << "failed to find resource name";
}
- StringPiece16 package16(actualName.package, actualName.packageLen);
- if (package16 != expectedResName.package) {
+ Maybe<ResourceName> resName = ResourceUtils::toResourceName(actualName);
+ if (!resName) {
return ::testing::AssertionFailure()
- << "expected package '" << expectedResName.package << "' but got '"
- << package16 << "'";
- }
-
- StringPiece16 type16(actualName.type, actualName.typeLen);
- if (type16 != toString(expectedResName.type)) {
- return ::testing::AssertionFailure()
- << "expected type '" << expectedResName.type
- << "' but got '" << type16 << "'";
- }
-
- StringPiece16 name16(actualName.name, actualName.nameLen);
- if (name16 != expectedResName.entry) {
- return ::testing::AssertionFailure()
- << "expected name '" << expectedResName.entry
- << "' but got '" << name16 << "'";
+ << "expected name '" << expectedResName << "' but got '"
+ << StringPiece16(actualName.package, actualName.packageLen)
+ << ":"
+ << StringPiece16(actualName.type, actualName.typeLen)
+ << "/"
+ << StringPiece16(actualName.name, actualName.nameLen)
+ << "'";
}
if (expectedConfig != config) {
@@ -139,67 +131,67 @@
TEST_F(TableFlattenerTest, FlattenFullyLinkedTable) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addSimple(u"@com.app.test:id/one", ResourceId(0x7f020000))
- .addSimple(u"@com.app.test:id/two", ResourceId(0x7f020001))
- .addValue(u"@com.app.test:id/three", ResourceId(0x7f020002),
- test::buildReference(u"@com.app.test:id/one", ResourceId(0x7f020000)))
- .addValue(u"@com.app.test:integer/one", ResourceId(0x7f030000),
+ .setPackageId("com.app.test", 0x7f)
+ .addSimple("@com.app.test:id/one", ResourceId(0x7f020000))
+ .addSimple("@com.app.test:id/two", ResourceId(0x7f020001))
+ .addValue("@com.app.test:id/three", ResourceId(0x7f020002),
+ test::buildReference("@com.app.test:id/one", ResourceId(0x7f020000)))
+ .addValue("@com.app.test:integer/one", ResourceId(0x7f030000),
util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
- .addValue(u"@com.app.test:integer/one", test::parseConfigOrDie("v1"),
+ .addValue("@com.app.test:integer/one", test::parseConfigOrDie("v1"),
ResourceId(0x7f030000),
util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
- .addString(u"@com.app.test:string/test", ResourceId(0x7f040000), u"foo")
- .addString(u"@com.app.test:layout/bar", ResourceId(0x7f050000), u"res/layout/bar.xml")
+ .addString("@com.app.test:string/test", ResourceId(0x7f040000), "foo")
+ .addString("@com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml")
.build();
ResTable resTable;
ASSERT_TRUE(flatten(table.get(), &resTable));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:id/one", ResourceId(0x7f020000), {},
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:id/one", ResourceId(0x7f020000), {},
Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:id/two", ResourceId(0x7f020001), {},
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:id/two", ResourceId(0x7f020001), {},
Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:id/three", ResourceId(0x7f020002), {},
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:id/three", ResourceId(0x7f020002), {},
Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:integer/one", ResourceId(0x7f030000),
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:integer/one", ResourceId(0x7f030000),
{}, Res_value::TYPE_INT_DEC, 1u,
ResTable_config::CONFIG_VERSION));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:integer/one", ResourceId(0x7f030000),
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:integer/one", ResourceId(0x7f030000),
test::parseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u,
ResTable_config::CONFIG_VERSION));
- StringPiece16 fooStr = u"foo";
+ std::u16string fooStr = u"foo";
ssize_t idx = resTable.getTableStringBlock(0)->indexOfString(fooStr.data(), fooStr.size());
ASSERT_GE(idx, 0);
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:string/test", ResourceId(0x7f040000),
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:string/test", ResourceId(0x7f040000),
{}, Res_value::TYPE_STRING, (uint32_t) idx, 0u));
- StringPiece16 barPath = u"res/layout/bar.xml";
+ std::u16string barPath = u"res/layout/bar.xml";
idx = resTable.getTableStringBlock(0)->indexOfString(barPath.data(), barPath.size());
ASSERT_GE(idx, 0);
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:layout/bar", ResourceId(0x7f050000), {},
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:layout/bar", ResourceId(0x7f050000), {},
Res_value::TYPE_STRING, (uint32_t) idx, 0u));
}
TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addSimple(u"@com.app.test:id/one", ResourceId(0x7f020001))
- .addSimple(u"@com.app.test:id/three", ResourceId(0x7f020003))
+ .setPackageId("com.app.test", 0x7f)
+ .addSimple("@com.app.test:id/one", ResourceId(0x7f020001))
+ .addSimple("@com.app.test:id/three", ResourceId(0x7f020003))
.build();
ResTable resTable;
ASSERT_TRUE(flatten(table.get(), &resTable));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:id/one", ResourceId(0x7f020001), {},
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:id/one", ResourceId(0x7f020001), {},
Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
- EXPECT_TRUE(exists(&resTable, u"@com.app.test:id/three", ResourceId(0x7f020003), {},
- Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+ EXPECT_TRUE(exists(&resTable, "@com.app.test:id/three", ResourceId(0x7f020003), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
}
TEST_F(TableFlattenerTest, FlattenMinMaxAttributes) {
@@ -208,15 +200,15 @@
attr.minInt = 10;
attr.maxInt = 23;
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addValue(u"@android:attr/foo", ResourceId(0x01010000),
+ .setPackageId("android", 0x01)
+ .addValue("@android:attr/foo", ResourceId(0x01010000),
util::make_unique<Attribute>(attr))
.build();
ResourceTable result;
ASSERT_TRUE(flatten(table.get(), &result));
- Attribute* actualAttr = test::getValue<Attribute>(&result, u"@android:attr/foo");
+ Attribute* actualAttr = test::getValue<Attribute>(&result, "@android:attr/foo");
ASSERT_NE(nullptr, actualAttr);
EXPECT_EQ(attr.isWeak(), actualAttr->isWeak());
EXPECT_EQ(attr.typeMask, actualAttr->typeMask);
diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp
index 2cf7dda..a743177 100644
--- a/tools/aapt2/flatten/XmlFlattener.cpp
+++ b/tools/aapt2/flatten/XmlFlattener.cpp
@@ -57,7 +57,7 @@
mBuffer(buffer), mOptions(options) {
}
- void addString(const StringPiece16& str, uint32_t priority, android::ResStringPool_ref* dest,
+ void addString(const StringPiece& str, uint32_t priority, android::ResStringPool_ref* dest,
bool treatEmptyStringAsNull = false) {
if (str.empty() && treatEmptyStringAsNull) {
// Some parts of the runtime treat null differently than empty string.
@@ -205,9 +205,9 @@
xmlAttr->compiledAttribute.value().id.value() == kIdAttr) {
flatElem->idIndex = util::hostToDevice16(attributeIndex);
} else if (xmlAttr->namespaceUri.empty()) {
- if (xmlAttr->name == u"class") {
+ if (xmlAttr->name == "class") {
flatElem->classIndex = util::hostToDevice16(attributeIndex);
- } else if (xmlAttr->name == u"style") {
+ } else if (xmlAttr->name == "style") {
flatElem->styleIndex = util::hostToDevice16(attributeIndex);
}
}
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index ef06528..9efee1e 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -16,13 +16,11 @@
#include "flatten/XmlFlattener.h"
#include "link/Linkers.h"
-#include "test/Builders.h"
-#include "test/Context.h"
+#include "test/Test.h"
#include "util/BigBuffer.h"
#include "util/Util.h"
#include <androidfw/ResourceTypes.h>
-#include <gtest/gtest.h>
namespace aapt {
@@ -30,15 +28,15 @@
public:
void SetUp() override {
mContext = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
+ .setCompilationPackage("com.app.test")
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test" })
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addSymbol(u"@android:attr/id", ResourceId(0x010100d0),
+ .addSymbol("@android:attr/id", ResourceId(0x010100d0),
test::AttributeBuilder().build())
- .addSymbol(u"@com.app.test:id/id", ResourceId(0x7f020000))
- .addSymbol(u"@android:attr/paddingStart", ResourceId(0x010103b3),
+ .addSymbol("@com.app.test:id/id", ResourceId(0x7f020000))
+ .addSymbol("@android:attr/paddingStart", ResourceId(0x010103b3),
test::AttributeBuilder().build())
- .addSymbol(u"@android:attr/colorAccent", ResourceId(0x01010435),
+ .addSymbol("@android:attr/colorAccent", ResourceId(0x01010435),
test::AttributeBuilder().build())
.build())
.build();
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index b7e7f90..23ff8ab 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -47,23 +47,13 @@
mComment << "\n * " << std::move(comment);
}
-void AnnotationProcessor::appendComment(const StringPiece16& comment) {
- // We need to process line by line to clean-up whitespace and append prefixes.
- for (StringPiece16 line : util::tokenize(comment, u'\n')) {
- line = util::trimWhitespace(line);
- if (!line.empty()) {
- std::string utf8Line = util::utf16ToUtf8(line);
- appendCommentLine(utf8Line);
- }
- }
-}
-
void AnnotationProcessor::appendComment(const StringPiece& comment) {
+ // We need to process line by line to clean-up whitespace and append prefixes.
for (StringPiece line : util::tokenize(comment, '\n')) {
line = util::trimWhitespace(line);
if (!line.empty()) {
- std::string utf8Line = line.toString();
- appendCommentLine(utf8Line);
+ std::string lineCopy = line.toString();
+ appendCommentLine(lineCopy);
}
}
}
@@ -75,7 +65,7 @@
void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) const {
if (mHasComments) {
std::string result = mComment.str();
- for (StringPiece line : util::tokenize<char>(result, '\n')) {
+ for (StringPiece line : util::tokenize(result, '\n')) {
*out << prefix << line << "\n";
}
*out << prefix << " */" << "\n";
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index 8309dd9..cfc32f3 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -57,7 +57,6 @@
* Adds more comments. Since resources can have various values with different configurations,
* we need to collect all the comments.
*/
- void appendComment(const StringPiece16& comment);
void appendComment(const StringPiece& comment);
void appendNewLine();
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 84df0b4..fbaefb1 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -19,7 +19,6 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
-
#include "java/AnnotationProcessor.h"
#include "java/ClassDefinition.h"
#include "java/JavaClassGenerator.h"
@@ -39,20 +38,20 @@
mContext(context), mTable(table), mOptions(options) {
}
-static const std::set<StringPiece16> sJavaIdentifiers = {
- u"abstract", u"assert", u"boolean", u"break", u"byte",
- u"case", u"catch", u"char", u"class", u"const", u"continue",
- u"default", u"do", u"double", u"else", u"enum", u"extends",
- u"final", u"finally", u"float", u"for", u"goto", u"if",
- u"implements", u"import", u"instanceof", u"int", u"interface",
- u"long", u"native", u"new", u"package", u"private", u"protected",
- u"public", u"return", u"short", u"static", u"strictfp", u"super",
- u"switch", u"synchronized", u"this", u"throw", u"throws",
- u"transient", u"try", u"void", u"volatile", u"while", u"true",
- u"false", u"null"
+static const std::set<StringPiece> sJavaIdentifiers = {
+ "abstract", "assert", "boolean", "break", "byte",
+ "case", "catch", "char", "class", "const", "continue",
+ "default", "do", "double", "else", "enum", "extends",
+ "final", "finally", "float", "for", "goto", "if",
+ "implements", "import", "instanceof", "int", "interface",
+ "long", "native", "new", "package", "private", "protected",
+ "public", "return", "short", "static", "strictfp", "super",
+ "switch", "synchronized", "this", "throw", "throws",
+ "transient", "try", "void", "volatile", "while", "true",
+ "false", "null"
};
-static bool isValidSymbol(const StringPiece16& symbol) {
+static bool isValidSymbol(const StringPiece& symbol) {
return sJavaIdentifiers.find(symbol) == sJavaIdentifiers.end();
}
@@ -60,8 +59,8 @@
* Java symbols can not contain . or -, but those are valid in a resource name.
* Replace those with '_'.
*/
-static std::string transform(const StringPiece16& symbol) {
- std::string output = util::utf16ToUtf8(symbol);
+static std::string transform(const StringPiece& symbol) {
+ std::string output = symbol.toString();
for (char& c : output) {
if (c == '.' || c == '-') {
c = '_';
@@ -83,7 +82,7 @@
*/
static std::string transformNestedAttr(const ResourceNameRef& attrName,
const std::string& styleableClassName,
- const StringPiece16& packageNameToGenerate) {
+ const StringPiece& packageNameToGenerate) {
std::string output = styleableClassName;
// We may reference IDs from other packages, so prefix the entry name with
@@ -204,8 +203,8 @@
}
}
-void JavaClassGenerator::addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
+void JavaClassGenerator::addMembersToStyleableClass(const StringPiece& packageNameToGenerate,
+ const std::string& entryName,
const Styleable* styleable,
ClassDefinition* outStyleableClassDef) {
const std::string className = transform(entryName);
@@ -284,8 +283,8 @@
continue;
}
- StringPiece16 attrCommentLine = entry.symbol->attribute->getComment();
- if (attrCommentLine.contains(StringPiece16(u"@removed"))) {
+ StringPiece attrCommentLine = entry.symbol->attribute->getComment();
+ if (attrCommentLine.contains("@removed")) {
// Removed attributes are public but hidden from the documentation, so don't emit
// them as part of the class documentation.
continue;
@@ -354,12 +353,12 @@
continue;
}
- StringPiece16 comment = styleableAttr.attrRef->getComment();
+ StringPiece comment = styleableAttr.attrRef->getComment();
if (styleableAttr.symbol->attribute && comment.empty()) {
comment = styleableAttr.symbol->attribute->getComment();
}
- if (comment.contains(StringPiece16(u"@removed"))) {
+ if (comment.contains("@removed")) {
// Removed attributes are public but hidden from the documentation, so don't emit them
// as part of the class documentation.
continue;
@@ -367,7 +366,7 @@
const ResourceName& attrName = styleableAttr.attrRef->name.value();
- StringPiece16 packageName = attrName.package;
+ StringPiece packageName = attrName.package;
if (packageName.empty()) {
packageName = mContext->getCompilationPackage();
}
@@ -403,7 +402,7 @@
}
}
-bool JavaClassGenerator::addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+bool JavaClassGenerator::addMembersToTypeClass(const StringPiece& packageNameToGenerate,
const ResourceTablePackage* package,
const ResourceTableType* type,
ClassDefinition* outTypeClassDef) {
@@ -418,8 +417,8 @@
id = ResourceId(package->id.value(), type->id.value(), entry->id.value());
}
- std::u16string unmangledPackage;
- std::u16string unmangledName = entry->name;
+ std::string unmangledPackage;
+ std::string unmangledName = entry->name;
if (NameMangler::unmangle(&unmangledName, &unmangledPackage)) {
// The entry name was mangled, and we successfully unmangled it.
// Check that we want to emit this symbol.
@@ -481,7 +480,7 @@
return true;
}
-bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, std::ostream* out) {
+bool JavaClassGenerator::generate(const StringPiece& packageNameToGenerate, std::ostream* out) {
return generate(packageNameToGenerate, packageNameToGenerate, out);
}
@@ -494,8 +493,8 @@
}
}
-bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
- const StringPiece16& outPackageName, std::ostream* out) {
+bool JavaClassGenerator::generate(const StringPiece& packageNameToGenerate,
+ const StringPiece& outPackageName, std::ostream* out) {
ClassDefinition rClass("R", ClassQualifier::None, true);
@@ -509,8 +508,7 @@
(mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
std::unique_ptr<ClassDefinition> classDef = util::make_unique<ClassDefinition>(
- util::utf16ToUtf8(toString(type->type)), ClassQualifier::Static,
- forceCreationIfEmpty);
+ toString(type->type), ClassQualifier::Static, forceCreationIfEmpty);
bool result = addMembersToTypeClass(packageNameToGenerate, package.get(), type.get(),
classDef.get());
@@ -545,8 +543,7 @@
appendJavaDocAnnotations(mOptions.javadocAnnotations, rClass.getCommentBuilder());
- if (!ClassDefinition::writeJavaFile(&rClass, util::utf16ToUtf8(outPackageName),
- mOptions.useFinal, out)) {
+ if (!ClassDefinition::writeJavaFile(&rClass, outPackageName, mOptions.useFinal, out)) {
return false;
}
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 77e0ed7..901a86e 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -66,22 +66,22 @@
* We need to generate these symbols in a separate file.
* Returns true on success.
*/
- bool generate(const StringPiece16& packageNameToGenerate, std::ostream* out);
+ bool generate(const StringPiece& packageNameToGenerate, std::ostream* out);
- bool generate(const StringPiece16& packageNameToGenerate,
- const StringPiece16& outputPackageName,
+ bool generate(const StringPiece& packageNameToGenerate,
+ const StringPiece& outputPackageName,
std::ostream* out);
const std::string& getError() const;
private:
- bool addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+ bool addMembersToTypeClass(const StringPiece& packageNameToGenerate,
const ResourceTablePackage* package,
const ResourceTableType* type,
ClassDefinition* outTypeClassDef);
- void addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
+ void addMembersToStyleableClass(const StringPiece& packageNameToGenerate,
+ const std::string& entryName,
const Styleable* styleable,
ClassDefinition* outStyleableClassDef);
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 46266b3..57a8047 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -25,40 +25,40 @@
TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addSimple(u"@android:id/class", ResourceId(0x01020000))
+ .setPackageId("android", 0x01)
+ .addSimple("@android:id/class", ResourceId(0x01020000))
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
- EXPECT_FALSE(generator.generate(u"android", &out));
+ EXPECT_FALSE(generator.generate("android", &out));
}
TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addSimple(u"@android:id/hey-man", ResourceId(0x01020000))
- .addValue(u"@android:attr/cool.attr", ResourceId(0x01010000),
+ .setPackageId("android", 0x01)
+ .addSimple("@android:id/hey-man", ResourceId(0x01020000))
+ .addValue("@android:attr/cool.attr", ResourceId(0x01010000),
test::AttributeBuilder(false).build())
- .addValue(u"@android:styleable/hey.dude", ResourceId(0x01030000),
+ .addValue("@android:styleable/hey.dude", ResourceId(0x01030000),
test::StyleableBuilder()
- .addItem(u"@android:attr/cool.attr", ResourceId(0x01010000))
+ .addItem("@android:attr/cool.attr", ResourceId(0x01010000))
.build())
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
- EXPECT_TRUE(generator.generate(u"android", &out));
+ EXPECT_TRUE(generator.generate("android", &out));
std::string output = out.str();
@@ -74,18 +74,18 @@
TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addSimple(u"@android:id/one", ResourceId(0x01020000))
- .addSimple(u"@android:id/com.foo$two", ResourceId(0x01020001))
+ .setPackageId("android", 0x01)
+ .addSimple("@android:id/one", ResourceId(0x01020000))
+ .addSimple("@android:id/com.foo$two", ResourceId(0x01020001))
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", u"com.android.internal", &out));
+ ASSERT_TRUE(generator.generate("android", "com.android.internal", &out));
std::string output = out.str();
EXPECT_NE(std::string::npos, output.find("package com.android.internal;"));
@@ -96,18 +96,18 @@
TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addSimple(u"@android:attr/two", ResourceId(0x01010001))
- .addSimple(u"@android:^attr-private/one", ResourceId(0x01010000))
+ .setPackageId("android", 0x01)
+ .addSimple("@android:attr/two", ResourceId(0x01010001))
+ .addSimple("@android:^attr-private/one", ResourceId(0x01010000))
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string output = out.str();
EXPECT_NE(std::string::npos, output.find("public static final class attr"));
@@ -117,17 +117,17 @@
TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
StdErrDiagnostics diag;
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addSimple(u"@android:id/one", ResourceId(0x01020000))
- .addSimple(u"@android:id/two", ResourceId(0x01020001))
- .addSimple(u"@android:id/three", ResourceId(0x01020002))
- .setSymbolState(u"@android:id/one", ResourceId(0x01020000), SymbolState::kPublic)
- .setSymbolState(u"@android:id/two", ResourceId(0x01020001), SymbolState::kPrivate)
+ .setPackageId("android", 0x01)
+ .addSimple("@android:id/one", ResourceId(0x01020000))
+ .addSimple("@android:id/two", ResourceId(0x01020001))
+ .addSimple("@android:id/three", ResourceId(0x01020002))
+ .setSymbolState("@android:id/one", ResourceId(0x01020000), SymbolState::kPublic)
+ .setSymbolState("@android:id/two", ResourceId(0x01020001), SymbolState::kPrivate)
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGeneratorOptions options;
@@ -135,7 +135,7 @@
{
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string output = out.str();
EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
EXPECT_EQ(std::string::npos, output.find("two"));
@@ -146,7 +146,7 @@
{
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string output = out.str();
EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;"));
@@ -157,7 +157,7 @@
{
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string output = out.str();
EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;"));
@@ -198,27 +198,27 @@
TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .setPackageId(u"com.lib", 0x02)
- .addValue(u"@android:attr/bar", ResourceId(0x01010000),
+ .setPackageId("android", 0x01)
+ .setPackageId("com.lib", 0x02)
+ .addValue("@android:attr/bar", ResourceId(0x01010000),
test::AttributeBuilder(false).build())
- .addValue(u"@com.lib:attr/bar", ResourceId(0x02010000),
+ .addValue("@com.lib:attr/bar", ResourceId(0x02010000),
test::AttributeBuilder(false).build())
- .addValue(u"@android:styleable/foo", ResourceId(0x01030000),
+ .addValue("@android:styleable/foo", ResourceId(0x01030000),
test::StyleableBuilder()
- .addItem(u"@android:attr/bar", ResourceId(0x01010000))
- .addItem(u"@com.lib:attr/bar", ResourceId(0x02010000))
+ .addItem("@android:attr/bar", ResourceId(0x01010000))
+ .addItem("@com.lib:attr/bar", ResourceId(0x02010000))
.build())
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
- EXPECT_TRUE(generator.generate(u"android", &out));
+ EXPECT_TRUE(generator.generate("android", &out));
std::string output = out.str();
EXPECT_NE(std::string::npos, output.find("int foo_bar="));
@@ -227,19 +227,19 @@
TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addSimple(u"@android:id/foo", ResourceId(0x01010000))
+ .setPackageId("android", 0x01)
+ .addSimple("@android:id/foo", ResourceId(0x01010000))
.build();
- test::getValue<Id>(table.get(), u"@android:id/foo")
- ->setComment(std::u16string(u"This is a comment\n@deprecated"));
+ test::getValue<Id>(table.get(), "@android:id/foo")
+ ->setComment(std::string("This is a comment\n@deprecated"));
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string actual = out.str();
const char* expectedText =
@@ -259,59 +259,56 @@
TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
Attribute attr(false);
- attr.setComment(StringPiece16(u"This is an attribute"));
+ attr.setComment(StringPiece("This is an attribute"));
Styleable styleable;
- styleable.entries.push_back(Reference(test::parseNameOrDie(u"@android:attr/one")));
- styleable.setComment(StringPiece16(u"This is a styleable"));
+ styleable.entries.push_back(Reference(test::parseNameOrDie("@android:attr/one")));
+ styleable.setComment(StringPiece("This is a styleable"));
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addValue(u"@android:attr/one", util::make_unique<Attribute>(attr))
- .addValue(u"@android:styleable/Container",
+ .setPackageId("android", 0x01)
+ .addValue("@android:attr/one", util::make_unique<Attribute>(attr))
+ .addValue("@android:styleable/Container",
std::unique_ptr<Styleable>(styleable.clone(nullptr)))
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGeneratorOptions options;
options.useFinal = false;
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string actual = out.str();
EXPECT_NE(std::string::npos, actual.find("@attr name android:one"));
EXPECT_NE(std::string::npos, actual.find("@attr description"));
- EXPECT_NE(std::string::npos, actual.find(util::utf16ToUtf8(attr.getComment())));
- EXPECT_NE(std::string::npos, actual.find(util::utf16ToUtf8(styleable.getComment())));
+ EXPECT_NE(std::string::npos, actual.find(attr.getComment().data()));
+ EXPECT_NE(std::string::npos, actual.find(styleable.getComment().data()));
}
TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
Attribute attr(false);
- attr.setComment(StringPiece16(u"@removed"));
-
+ attr.setComment(StringPiece("@removed"));
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"android", 0x01)
- .addValue(u"@android:attr/one", util::make_unique<Attribute>(attr))
+ .setPackageId("android", 0x01)
+ .addValue("@android:attr/one", util::make_unique<Attribute>(attr))
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.build();
JavaClassGeneratorOptions options;
options.useFinal = false;
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
- ASSERT_TRUE(generator.generate(u"android", &out));
+ ASSERT_TRUE(generator.generate("android", &out));
std::string actual = out.str();
- std::cout << actual << std::endl;
-
EXPECT_EQ(std::string::npos, actual.find("@attr name android:one"));
EXPECT_EQ(std::string::npos, actual.find("@attr description"));
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index be8955e..5ff11b1 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -25,12 +25,12 @@
namespace aapt {
-static Maybe<StringPiece16> extractJavaIdentifier(IDiagnostics* diag, const Source& source,
- const StringPiece16& value) {
- const StringPiece16 sep = u".";
+static Maybe<StringPiece> extractJavaIdentifier(IDiagnostics* diag, const Source& source,
+ const StringPiece& value) {
+ const StringPiece sep = ".";
auto iter = std::find_end(value.begin(), value.end(), sep.begin(), sep.end());
- StringPiece16 result;
+ StringPiece result;
if (iter != value.end()) {
result.assign(iter + sep.size(), value.end() - (iter + sep.size()));
} else {
@@ -42,15 +42,15 @@
return {};
}
- iter = util::findNonAlphaNumericAndNotInSet(result, u"_");
+ iter = util::findNonAlphaNumericAndNotInSet(result, "_");
if (iter != result.end()) {
diag->error(DiagMessage(source)
- << "invalid character '" << StringPiece16(iter, 1)
+ << "invalid character '" << StringPiece(iter, 1)
<< "' in '" << result << "'");
return {};
}
- if (*result.begin() >= u'0' && *result.begin() <= u'9') {
+ if (*result.begin() >= '0' && *result.begin() <= '9') {
diag->error(DiagMessage(source) << "symbol can not start with a digit");
return {};
}
@@ -60,20 +60,20 @@
static bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
ClassDefinition* classDef) {
- xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
+ xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "name");
if (!attr) {
diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
return false;
}
- Maybe<StringPiece16> result = extractJavaIdentifier(diag, source.withLine(el->lineNumber),
- attr->value);
+ Maybe<StringPiece> result = extractJavaIdentifier(diag, source.withLine(el->lineNumber),
+ attr->value);
if (!result) {
return false;
}
std::unique_ptr<StringMember> stringMember = util::make_unique<StringMember>(
- util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
+ result.value(), attr->value);
stringMember->getCommentBuilder()->appendComment(el->comment);
classDef->addMember(std::move(stringMember));
@@ -87,7 +87,7 @@
return {};
}
- if (el->name != u"manifest" && !el->namespaceUri.empty()) {
+ if (el->name != "manifest" && !el->namespaceUri.empty()) {
diag->error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
return {};
}
@@ -102,9 +102,9 @@
std::vector<xml::Element*> children = el->getChildElements();
for (xml::Element* childEl : children) {
if (childEl->namespaceUri.empty()) {
- if (childEl->name == u"permission") {
+ if (childEl->name == "permission") {
error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
- } else if (childEl->name == u"permission-group") {
+ } else if (childEl->name == "permission-group") {
error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
}
}
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index d3bca70..eecb544 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -15,10 +15,7 @@
*/
#include "java/ManifestClassGenerator.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index 53ff961..9061660 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -43,7 +43,7 @@
node->namespaceUri);
if (maybePackage) {
// This is a custom view, let's figure out the class name from this.
- std::u16string package = maybePackage.value().package + u"." + node->name;
+ std::string package = maybePackage.value().package + "." + node->name;
if (util::isJavaClassName(package)) {
addClass(node->lineNumber, package);
}
@@ -58,11 +58,11 @@
}
protected:
- void addClass(size_t lineNumber, const std::u16string& className) {
+ void addClass(size_t lineNumber, const std::string& className) {
mKeepSet->addClass(Source(mSource.path, lineNumber), className);
}
- void addMethod(size_t lineNumber, const std::u16string& methodName) {
+ void addMethod(size_t lineNumber, const std::string& methodName) {
mKeepSet->addMethod(Source(mSource.path, lineNumber), methodName);
}
@@ -79,19 +79,19 @@
bool checkClass = false;
bool checkName = false;
if (node->namespaceUri.empty()) {
- checkClass = node->name == u"view" || node->name == u"fragment";
+ checkClass = node->name == "view" || node->name == "fragment";
} else if (node->namespaceUri == xml::kSchemaAndroid) {
- checkName = node->name == u"fragment";
+ checkName = node->name == "fragment";
}
for (const auto& attr : node->attributes) {
- if (checkClass && attr.namespaceUri.empty() && attr.name == u"class" &&
+ if (checkClass && attr.namespaceUri.empty() && attr.name == "class" &&
util::isJavaClassName(attr.value)) {
addClass(node->lineNumber, attr.value);
} else if (checkName && attr.namespaceUri == xml::kSchemaAndroid &&
- attr.name == u"name" && util::isJavaClassName(attr.value)) {
+ attr.name == "name" && util::isJavaClassName(attr.value)) {
addClass(node->lineNumber, attr.value);
- } else if (attr.namespaceUri == xml::kSchemaAndroid && attr.name == u"onClick") {
+ } else if (attr.namespaceUri == xml::kSchemaAndroid && attr.name == "onClick") {
addMethod(node->lineNumber, attr.value);
}
}
@@ -107,11 +107,11 @@
virtual void visit(xml::Element* node) override {
bool checkFragment = false;
if (node->namespaceUri.empty()) {
- checkFragment = node->name == u"PreferenceScreen" || node->name == u"header";
+ checkFragment = node->name == "PreferenceScreen" || node->name == "header";
}
if (checkFragment) {
- xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, u"fragment");
+ xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, "fragment");
if (attr && util::isJavaClassName(attr->value)) {
addClass(node->lineNumber, attr->value);
}
@@ -127,9 +127,9 @@
virtual void visit(xml::Element* node) override {
bool checkClass = node->namespaceUri.empty() &&
- (node->name == u"transition" || node->name == u"pathMotion");
+ (node->name == "transition" || node->name == "pathMotion");
if (checkClass) {
- xml::Attribute* attr = node->findAttribute({}, u"class");
+ xml::Attribute* attr = node->findAttribute({}, "class");
if (attr && util::isJavaClassName(attr->value)) {
addClass(node->lineNumber, attr->value);
}
@@ -147,50 +147,50 @@
virtual void visit(xml::Element* node) override {
if (node->namespaceUri.empty()) {
bool getName = false;
- if (node->name == u"manifest") {
- xml::Attribute* attr = node->findAttribute({}, u"package");
+ if (node->name == "manifest") {
+ xml::Attribute* attr = node->findAttribute({}, "package");
if (attr) {
mPackage = attr->value;
}
- } else if (node->name == u"application") {
+ } else if (node->name == "application") {
getName = true;
- xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, u"backupAgent");
+ xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, "backupAgent");
if (attr) {
- Maybe<std::u16string> result = util::getFullyQualifiedClassName(mPackage,
- attr->value);
+ Maybe<std::string> result = util::getFullyQualifiedClassName(mPackage,
+ attr->value);
if (result) {
addClass(node->lineNumber, result.value());
}
}
if (mMainDexOnly) {
xml::Attribute* defaultProcess = node->findAttribute(xml::kSchemaAndroid,
- u"process");
+ "process");
if (defaultProcess) {
mDefaultProcess = defaultProcess->value;
}
}
- } else if (node->name == u"activity" || node->name == u"service" ||
- node->name == u"receiver" || node->name == u"provider" ||
- node->name == u"instrumentation") {
+ } else if (node->name == "activity" || node->name == "service" ||
+ node->name == "receiver" || node->name == "provider" ||
+ node->name == "instrumentation") {
getName = true;
}
if (getName) {
- xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, u"name");
+ xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, "name");
getName = attr != nullptr;
if (getName && mMainDexOnly) {
xml::Attribute* componentProcess = node->findAttribute(xml::kSchemaAndroid,
- u"process");
+ "process");
- const std::u16string& process = componentProcess ? componentProcess->value
- : mDefaultProcess;
- getName = !process.empty() && process[0] != u':';
+ const std::string& process = componentProcess ? componentProcess->value
+ : mDefaultProcess;
+ getName = !process.empty() && process[0] != ':';
}
if (getName) {
- Maybe<std::u16string> result = util::getFullyQualifiedClassName(mPackage,
- attr->value);
+ Maybe<std::string> result = util::getFullyQualifiedClassName(mPackage,
+ attr->value);
if (result) {
addClass(node->lineNumber, result.value());
}
@@ -201,9 +201,9 @@
}
private:
- std::u16string mPackage;
+ std::string mPackage;
const bool mMainDexOnly;
- std::u16string mDefaultProcess;
+ std::string mDefaultProcess;
};
bool collectProguardRulesForManifest(const Source& source, xml::XmlResource* res,
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index 744ae5b..c2d2bd9 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -31,19 +31,19 @@
class KeepSet {
public:
- inline void addClass(const Source& source, const std::u16string& className) {
+ inline void addClass(const Source& source, const std::string& className) {
mKeepSet[className].insert(source);
}
- inline void addMethod(const Source& source, const std::u16string& methodName) {
+ inline void addMethod(const Source& source, const std::string& methodName) {
mKeepMethodSet[methodName].insert(source);
}
private:
friend bool writeKeepSet(std::ostream* out, const KeepSet& keepSet);
- std::map<std::u16string, std::set<Source>> mKeepSet;
- std::map<std::u16string, std::set<Source>> mKeepMethodSet;
+ std::map<std::string, std::set<Source>> mKeepSet;
+ std::map<std::string, std::set<Source>> mKeepMethodSet;
};
bool collectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keepSet,
diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp
index 99a7c02..7764176 100644
--- a/tools/aapt2/link/AutoVersioner_test.cpp
+++ b/tools/aapt2/link/AutoVersioner_test.cpp
@@ -25,7 +25,7 @@
const ConfigDescription landConfig = test::parseConfigOrDie("land");
const ConfigDescription sw600dpLandConfig = test::parseConfigOrDie("sw600dp-land");
- ResourceEntry entry(u"foo");
+ ResourceEntry entry("foo");
entry.values.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
entry.values.push_back(util::make_unique<ResourceConfigValue>(landConfig, ""));
entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dpLandConfig, ""));
@@ -39,7 +39,7 @@
const ConfigDescription sw600dpV13Config = test::parseConfigOrDie("sw600dp-v13");
const ConfigDescription v21Config = test::parseConfigOrDie("v21");
- ResourceEntry entry(u"foo");
+ ResourceEntry entry("foo");
entry.values.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dpV13Config, ""));
entry.values.push_back(util::make_unique<ResourceConfigValue>(v21Config, ""));
@@ -50,73 +50,73 @@
TEST(AutoVersionerTest, VersionStylesForTable) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"app", 0x7f)
- .addValue(u"@app:style/Foo", test::parseConfigOrDie("v4"), ResourceId(0x7f020000),
+ .setPackageId("app", 0x7f)
+ .addValue("@app:style/Foo", test::parseConfigOrDie("v4"), ResourceId(0x7f020000),
test::StyleBuilder()
- .addItem(u"@android:attr/onClick", ResourceId(0x0101026f),
+ .addItem("@android:attr/onClick", ResourceId(0x0101026f),
util::make_unique<Id>())
- .addItem(u"@android:attr/paddingStart", ResourceId(0x010103b3),
+ .addItem("@android:attr/paddingStart", ResourceId(0x010103b3),
util::make_unique<Id>())
- .addItem(u"@android:attr/requiresSmallestWidthDp",
+ .addItem("@android:attr/requiresSmallestWidthDp",
ResourceId(0x01010364), util::make_unique<Id>())
- .addItem(u"@android:attr/colorAccent", ResourceId(0x01010435),
+ .addItem("@android:attr/colorAccent", ResourceId(0x01010435),
util::make_unique<Id>())
.build())
- .addValue(u"@app:style/Foo", test::parseConfigOrDie("v21"), ResourceId(0x7f020000),
+ .addValue("@app:style/Foo", test::parseConfigOrDie("v21"), ResourceId(0x7f020000),
test::StyleBuilder()
- .addItem(u"@android:attr/paddingEnd", ResourceId(0x010103b4),
+ .addItem("@android:attr/paddingEnd", ResourceId(0x010103b4),
util::make_unique<Id>())
.build())
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"app")
+ .setCompilationPackage("app")
.setPackageId(0x7f)
.build();
AutoVersioner versioner;
ASSERT_TRUE(versioner.consume(context.get(), table.get()));
- Style* style = test::getValueForConfig<Style>(table.get(), u"@app:style/Foo",
+ Style* style = test::getValueForConfig<Style>(table.get(), "@app:style/Foo",
test::parseConfigOrDie("v4"));
ASSERT_NE(style, nullptr);
ASSERT_EQ(style->entries.size(), 1u);
AAPT_ASSERT_TRUE(style->entries.front().key.name);
EXPECT_EQ(style->entries.front().key.name.value(),
- test::parseNameOrDie(u"@android:attr/onClick"));
+ test::parseNameOrDie("@android:attr/onClick"));
- style = test::getValueForConfig<Style>(table.get(), u"@app:style/Foo",
+ style = test::getValueForConfig<Style>(table.get(), "@app:style/Foo",
test::parseConfigOrDie("v13"));
ASSERT_NE(style, nullptr);
ASSERT_EQ(style->entries.size(), 2u);
AAPT_ASSERT_TRUE(style->entries[0].key.name);
EXPECT_EQ(style->entries[0].key.name.value(),
- test::parseNameOrDie(u"@android:attr/onClick"));
+ test::parseNameOrDie("@android:attr/onClick"));
AAPT_ASSERT_TRUE(style->entries[1].key.name);
EXPECT_EQ(style->entries[1].key.name.value(),
- test::parseNameOrDie(u"@android:attr/requiresSmallestWidthDp"));
+ test::parseNameOrDie("@android:attr/requiresSmallestWidthDp"));
- style = test::getValueForConfig<Style>(table.get(), u"@app:style/Foo",
+ style = test::getValueForConfig<Style>(table.get(), "@app:style/Foo",
test::parseConfigOrDie("v17"));
ASSERT_NE(style, nullptr);
ASSERT_EQ(style->entries.size(), 3u);
AAPT_ASSERT_TRUE(style->entries[0].key.name);
EXPECT_EQ(style->entries[0].key.name.value(),
- test::parseNameOrDie(u"@android:attr/onClick"));
+ test::parseNameOrDie("@android:attr/onClick"));
AAPT_ASSERT_TRUE(style->entries[1].key.name);
EXPECT_EQ(style->entries[1].key.name.value(),
- test::parseNameOrDie(u"@android:attr/requiresSmallestWidthDp"));
+ test::parseNameOrDie("@android:attr/requiresSmallestWidthDp"));
AAPT_ASSERT_TRUE(style->entries[2].key.name);
EXPECT_EQ(style->entries[2].key.name.value(),
- test::parseNameOrDie(u"@android:attr/paddingStart"));
+ test::parseNameOrDie("@android:attr/paddingStart"));
- style = test::getValueForConfig<Style>(table.get(), u"@app:style/Foo",
+ style = test::getValueForConfig<Style>(table.get(), "@app:style/Foo",
test::parseConfigOrDie("v21"));
ASSERT_NE(style, nullptr);
ASSERT_EQ(style->entries.size(), 1u);
AAPT_ASSERT_TRUE(style->entries.front().key.name);
EXPECT_EQ(style->entries.front().key.name.value(),
- test::parseNameOrDie(u"@android:attr/paddingEnd"));
+ test::parseNameOrDie("@android:attr/paddingEnd"));
}
} // namespace aapt
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 9411053..8093e6a 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -58,8 +58,8 @@
std::vector<std::string> includePaths;
std::vector<std::string> overlayFiles;
Maybe<std::string> generateJavaClassPath;
- Maybe<std::u16string> customJavaPackage;
- std::set<std::u16string> extraJavaPackages;
+ Maybe<std::string> customJavaPackage;
+ std::set<std::string> extraJavaPackages;
Maybe<std::string> generateProguardRulesPath;
Maybe<std::string> generateMainDexProguardRulesPath;
bool noAutoVersion = false;
@@ -72,7 +72,7 @@
bool autoAddOverlay = false;
bool doNotCompressAnything = false;
std::vector<std::string> extensionsToNotCompress;
- Maybe<std::u16string> privateSymbols;
+ Maybe<std::string> privateSymbols;
ManifestFixerOptions manifestFixerOptions;
std::unordered_set<std::string> products;
TableSplitterOptions tableSplitterOptions;
@@ -95,11 +95,11 @@
mNameMangler = NameMangler(policy);
}
- const std::u16string& getCompilationPackage() override {
+ const std::string& getCompilationPackage() override {
return mCompilationPackage;
}
- void setCompilationPackage(const StringPiece16& packageName) {
+ void setCompilationPackage(const StringPiece& packageName) {
mCompilationPackage = packageName.toString();
}
@@ -134,7 +134,7 @@
private:
StdErrDiagnostics mDiagnostics;
NameMangler mNameMangler;
- std::u16string mCompilationPackage;
+ std::string mCompilationPackage;
uint8_t mPackageId = 0x0;
SymbolTable mSymbols;
bool mVerbose = false;
@@ -155,7 +155,7 @@
size_t bufferSize = data->size();
// If the file ends with .flat, we must strip off the CompiledFileHeader from it.
- if (util::stringEndsWith<char>(file->getSource().path, ".flat")) {
+ if (util::stringEndsWith(file->getSource().path, ".flat")) {
CompiledFileInputStream inputStream(data->data(), data->size());
if (!inputStream.CompiledFile()) {
context->getDiagnostics()->error(DiagMessage(file->getSource())
@@ -213,16 +213,6 @@
return false;
}
-/*static std::unique_ptr<ResourceTable> loadTable(const Source& source, const void* data, size_t len,
- IDiagnostics* diag) {
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(diag, table.get(), source, data, len);
- if (!parser.parse()) {
- return {};
- }
- return table;
-}*/
-
static std::unique_ptr<ResourceTable> loadTableFromPb(const Source& source,
const void* data, size_t len,
IDiagnostics* diag) {
@@ -329,7 +319,7 @@
}
for (const std::string& extension : mOptions.extensionsToNotCompress) {
- if (util::stringEndsWith<char>(str, extension)) {
+ if (util::stringEndsWith(str, extension)) {
return 0;
}
}
@@ -352,7 +342,7 @@
return false;
}
- if (util::stringEndsWith<char>(srcPath, ".flat")) {
+ if (util::stringEndsWith(srcPath, ".flat")) {
outFileOp->xmlToFlatten = loadBinaryXmlSkipFileExport(file->getSource(),
data->data(), data->size(),
mContext->getDiagnostics());
@@ -384,7 +374,7 @@
// Skip this if it is a vector or animated-vector.
xml::Element* el = xml::findRootElement(outFileOp->xmlToFlatten.get());
if (el && el->namespaceUri.empty()) {
- if (el->name == u"vector" || el->name == u"animated-vector") {
+ if (el->name == "vector" || el->name == "animated-vector") {
// We are NOT going to version this file.
outFileOp->skipVersion = true;
return true;
@@ -413,8 +403,8 @@
<< versionedFileDesc.config << "'");
}
- std::u16string genPath = util::utf8ToUtf16(ResourceUtils::buildResourceFileName(
- versionedFileDesc, mContext->getNameMangler()));
+ std::string genPath = ResourceUtils::buildResourceFileName(
+ versionedFileDesc, mContext->getNameMangler());
bool added = table->addFileReferenceAllowMangled(versionedFileDesc.name,
versionedFileDesc.config,
@@ -438,7 +428,7 @@
*/
bool ResourceFileFlattener::flatten(ResourceTable* table, IArchiveWriter* archiveWriter) {
bool error = false;
- std::map<std::pair<ConfigDescription, StringPiece16>, FileOperation> configSortedFiles;
+ std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> configSortedFiles;
for (auto& pkg : table->packages) {
for (auto& type : pkg->types) {
@@ -463,12 +453,12 @@
}
FileOperation fileOp;
- fileOp.dstPath = util::utf16ToUtf8(*fileRef->path);
+ fileOp.dstPath = *fileRef->path;
const StringPiece srcPath = file->getSource().path;
if (type->type != ResourceType::kRaw &&
- (util::stringEndsWith<char>(srcPath, ".xml.flat") ||
- util::stringEndsWith<char>(srcPath, ".xml"))) {
+ (util::stringEndsWith(srcPath, ".xml.flat") ||
+ util::stringEndsWith(srcPath, ".xml"))) {
ResourceFile fileDesc;
fileDesc.config = configValue->config;
fileDesc.name = ResourceName(pkg->name, type->type, entry->name);
@@ -486,7 +476,7 @@
// we end up copying the string in the std::make_pair() method, then creating
// a StringPiece16 from the copy, which would cause us to end up referencing
// garbage in the map.
- const StringPiece16 entryName(entry->name);
+ const StringPiece entryName(entry->name);
configSortedFiles[std::make_pair(configValue->config, entryName)] =
std::move(fileOp);
}
@@ -592,12 +582,12 @@
if (xml::Element* manifestEl = xml::findRootElement(xmlRes->root.get())) {
AppInfo appInfo;
- if (!manifestEl->namespaceUri.empty() || manifestEl->name != u"manifest") {
+ if (!manifestEl->namespaceUri.empty() || manifestEl->name != "manifest") {
diag->error(DiagMessage(xmlRes->file.source) << "root tag must be <manifest>");
return {};
}
- xml::Attribute* packageAttr = manifestEl->findAttribute({}, u"package");
+ xml::Attribute* packageAttr = manifestEl->findAttribute({}, "package");
if (!packageAttr) {
diag->error(DiagMessage(xmlRes->file.source)
<< "<manifest> must have a 'package' attribute");
@@ -606,9 +596,9 @@
appInfo.package = packageAttr->value;
- if (xml::Element* usesSdkEl = manifestEl->findChild({}, u"uses-sdk")) {
+ if (xml::Element* usesSdkEl = manifestEl->findChild({}, "uses-sdk")) {
if (xml::Attribute* minSdk =
- usesSdkEl->findAttribute(xml::kSchemaAndroid, u"minSdkVersion")) {
+ usesSdkEl->findAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
appInfo.minSdkVersion = minSdk->value;
}
}
@@ -642,7 +632,7 @@
// Special case the occurrence of an ID that is being generated for the
// 'android' package. This is due to legacy reasons.
if (valueCast<Id>(configValue->value.get()) &&
- package->name == u"android") {
+ package->name == "android") {
mContext->getDiagnostics()->warn(
DiagMessage(configValue->value->getSource())
<< "generated id '" << resName
@@ -752,14 +742,14 @@
return true;
}
- bool writeJavaFile(ResourceTable* table, const StringPiece16& packageNameToGenerate,
- const StringPiece16& outPackage, JavaClassGeneratorOptions javaOptions) {
+ bool writeJavaFile(ResourceTable* table, const StringPiece& packageNameToGenerate,
+ const StringPiece& outPackage, JavaClassGeneratorOptions javaOptions) {
if (!mOptions.generateJavaClassPath) {
return true;
}
std::string outPath = mOptions.generateJavaClassPath.value();
- file::appendPath(&outPath, file::packageToPath(util::utf16ToUtf8(outPackage)));
+ file::appendPath(&outPath, file::packageToPath(outPackage));
if (!file::mkdirs(outPath)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed to create directory '" << outPath << "'");
@@ -813,7 +803,7 @@
manifestClass->getCommentBuilder()->appendComment(properAnnotation);
}
- const std::string packageUtf8 = util::utf16ToUtf8(mContext->getCompilationPackage());
+ const std::string& packageUtf8 = mContext->getCompilationPackage();
std::string outPath = mOptions.generateJavaClassPath.value();
file::appendPath(&outPath, file::packageToPath(packageUtf8));
@@ -921,7 +911,7 @@
mOptions.extraJavaPackages.insert(pkg->name);
}
- pkg->name = u"";
+ pkg->name = "";
if (override) {
result = mTableMerger->mergeOverlay(Source(input), table.get(), collection.get());
} else {
@@ -1059,12 +1049,12 @@
* Otherwise the files is processed on its own.
*/
bool mergePath(const std::string& path, bool override) {
- if (util::stringEndsWith<char>(path, ".flata") ||
- util::stringEndsWith<char>(path, ".jar") ||
- util::stringEndsWith<char>(path, ".jack") ||
- util::stringEndsWith<char>(path, ".zip")) {
+ if (util::stringEndsWith(path, ".flata") ||
+ util::stringEndsWith(path, ".jar") ||
+ util::stringEndsWith(path, ".jack") ||
+ util::stringEndsWith(path, ".zip")) {
return mergeArchive(path, override);
- } else if (util::stringEndsWith<char>(path, ".apk")) {
+ } else if (util::stringEndsWith(path, ".apk")) {
return mergeStaticLibrary(path, override);
}
@@ -1085,10 +1075,10 @@
*/
bool mergeFile(io::IFile* file, bool override) {
const Source& src = file->getSource();
- if (util::stringEndsWith<char>(src.path, ".arsc.flat")) {
+ if (util::stringEndsWith(src.path, ".arsc.flat")) {
return mergeResourceTable(file, override);
- } else if (util::stringEndsWith<char>(src.path, ".flat")){
+ } else if (util::stringEndsWith(src.path, ".flat")){
// Try opening the file and looking for an Export header.
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
@@ -1135,7 +1125,7 @@
mContext->setNameManglerPolicy(NameManglerPolicy{ mContext->getCompilationPackage() });
- if (mContext->getCompilationPackage() == u"android") {
+ if (mContext->getCompilationPackage() == "android") {
mContext->setPackageId(0x01);
} else {
mContext->setPackageId(0x7f);
@@ -1370,8 +1360,8 @@
options.useFinal = false;
}
- const StringPiece16 actualPackage = mContext->getCompilationPackage();
- StringPiece16 outputPackage = mContext->getCompilationPackage();
+ const StringPiece actualPackage = mContext->getCompilationPackage();
+ StringPiece outputPackage = mContext->getCompilationPackage();
if (mOptions.customJavaPackage) {
// Override the output java package to the custom one.
outputPackage = mOptions.customJavaPackage.value();
@@ -1395,7 +1385,7 @@
return 1;
}
- for (const std::u16string& extraPackage : mOptions.extraJavaPackages) {
+ for (const std::string& extraPackage : mOptions.extraJavaPackages) {
if (!writeJavaFile(&mFinalTable, actualPackage, extraPackage, options)) {
return 1;
}
@@ -1440,11 +1430,6 @@
LinkContext context;
LinkOptions options;
std::vector<std::string> overlayArgList;
- Maybe<std::string> privateSymbolsPackage;
- Maybe<std::string> minSdkVersion, targetSdkVersion;
- Maybe<std::string> renameManifestPackage, renameInstrumentationTargetPackage;
- Maybe<std::string> versionCode, versionName;
- Maybe<std::string> customJavaPackage;
std::vector<std::string> extraJavaPackages;
Maybe<std::string> configs;
Maybe<std::string> preferredDensity;
@@ -1489,14 +1474,19 @@
"by -o",
&options.outputToDirectory)
.optionalFlag("--min-sdk-version", "Default minimum SDK version to use for "
- "AndroidManifest.xml", &minSdkVersion)
+ "AndroidManifest.xml",
+ &options.manifestFixerOptions.minSdkVersionDefault)
.optionalFlag("--target-sdk-version", "Default target SDK version to use for "
- "AndroidManifest.xml", &targetSdkVersion)
+ "AndroidManifest.xml",
+ &options.manifestFixerOptions.targetSdkVersionDefault)
.optionalFlag("--version-code", "Version code (integer) to inject into the "
- "AndroidManifest.xml if none is present", &versionCode)
+ "AndroidManifest.xml if none is present",
+ &options.manifestFixerOptions.versionCodeDefault)
.optionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml "
- "if none is present", &versionName)
- .optionalSwitch("--static-lib", "Generate a static Android library", &options.staticLib)
+ "if none is present",
+ &options.manifestFixerOptions.versionNameDefault)
+ .optionalSwitch("--static-lib", "Generate a static Android library",
+ &options.staticLib)
.optionalSwitch("--no-static-lib-packages",
"Merge all library resources under the app's package",
&options.noStaticLibPackages)
@@ -1506,24 +1496,29 @@
.optionalFlag("--private-symbols", "Package name to use when generating R.java for "
"private symbols.\n"
"If not specified, public and private symbols will use the application's "
- "package name", &privateSymbolsPackage)
+ "package name",
+ &options.privateSymbols)
.optionalFlag("--custom-package", "Custom Java package under which to generate R.java",
- &customJavaPackage)
+ &options.customJavaPackage)
.optionalFlagList("--extra-packages", "Generate the same R.java but with different "
- "package names", &extraJavaPackages)
+ "package names",
+ &extraJavaPackages)
.optionalFlagList("--add-javadoc-annotation", "Adds a JavaDoc annotation to all "
- "generated Java classes", &options.javadocAnnotations)
+ "generated Java classes",
+ &options.javadocAnnotations)
.optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
- "overlays without <add-resource> tags", &options.autoAddOverlay)
+ "overlays without <add-resource> tags",
+ &options.autoAddOverlay)
.optionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml",
- &renameManifestPackage)
+ &options.manifestFixerOptions.renameManifestPackage)
.optionalFlag("--rename-instrumentation-target-package",
"Changes the name of the target package for instrumentation. Most useful "
"when used\nin conjunction with --rename-manifest-package",
- &renameInstrumentationTargetPackage)
+ &options.manifestFixerOptions.renameInstrumentationTargetPackage)
.optionalFlagList("-0", "File extensions not to compress",
&options.extensionsToNotCompress)
- .optionalSwitch("-v", "Enables verbose logging", &verbose);
+ .optionalSwitch("-v", "Enables verbose logging",
+ &verbose);
if (!flags.parse("aapt2 link", args, &std::cerr)) {
return 1;
@@ -1532,7 +1527,7 @@
// Expand all argument-files passed into the command line. These start with '@'.
std::vector<std::string> argList;
for (const std::string& arg : flags.getArgs()) {
- if (util::stringStartsWith<char>(arg, "@")) {
+ if (util::stringStartsWith(arg, "@")) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
if (!file::appendArgsFromFile(path, &argList, &error)) {
@@ -1546,7 +1541,7 @@
// Expand all argument-files passed to -R.
for (const std::string& arg : overlayArgList) {
- if (util::stringStartsWith<char>(arg, "@")) {
+ if (util::stringStartsWith(arg, "@")) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
if (!file::appendArgsFromFile(path, &options.overlayFiles, &error)) {
@@ -1562,52 +1557,16 @@
context.setVerbose(verbose);
}
- if (privateSymbolsPackage) {
- options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
- }
-
- if (minSdkVersion) {
- options.manifestFixerOptions.minSdkVersionDefault =
- util::utf8ToUtf16(minSdkVersion.value());
- }
-
- if (targetSdkVersion) {
- options.manifestFixerOptions.targetSdkVersionDefault =
- util::utf8ToUtf16(targetSdkVersion.value());
- }
-
- if (renameManifestPackage) {
- options.manifestFixerOptions.renameManifestPackage =
- util::utf8ToUtf16(renameManifestPackage.value());
- }
-
- if (renameInstrumentationTargetPackage) {
- options.manifestFixerOptions.renameInstrumentationTargetPackage =
- util::utf8ToUtf16(renameInstrumentationTargetPackage.value());
- }
-
- if (versionCode) {
- options.manifestFixerOptions.versionCodeDefault = util::utf8ToUtf16(versionCode.value());
- }
-
- if (versionName) {
- options.manifestFixerOptions.versionNameDefault = util::utf8ToUtf16(versionName.value());
- }
-
- if (customJavaPackage) {
- options.customJavaPackage = util::utf8ToUtf16(customJavaPackage.value());
- }
-
// Populate the set of extra packages for which to generate R.java.
for (std::string& extraPackage : extraJavaPackages) {
// A given package can actually be a colon separated list of packages.
for (StringPiece package : util::split(extraPackage, ':')) {
- options.extraJavaPackages.insert(util::utf8ToUtf16(package));
+ options.extraJavaPackages.insert(package.toString());
}
}
if (productList) {
- for (StringPiece product : util::tokenize<char>(productList.value(), ',')) {
+ for (StringPiece product : util::tokenize(productList.value(), ',')) {
if (product != "" && product != "default") {
options.products.insert(product.toString());
}
@@ -1616,7 +1575,7 @@
AxisConfigFilter filter;
if (configs) {
- for (const StringPiece& configStr : util::tokenize<char>(configs.value(), ',')) {
+ for (const StringPiece& configStr : util::tokenize(configs.value(), ',')) {
ConfigDescription config;
LocaleValue lv;
if (lv.initFromFilterString(configStr)) {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index db6e06d..ef09535 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -32,11 +32,12 @@
// We allow unqualified class names (ie: .HelloActivity)
// Since we don't know the package name, we can just make a fake one here and
// the test will be identical as long as the real package name is valid too.
- Maybe<std::u16string> fullyQualifiedClassName =
- util::getFullyQualifiedClassName(u"a", attr->value);
+ Maybe<std::string> fullyQualifiedClassName =
+ util::getFullyQualifiedClassName("a", attr->value);
- StringPiece16 qualifiedClassName = fullyQualifiedClassName
+ StringPiece qualifiedClassName = fullyQualifiedClassName
? fullyQualifiedClassName.value() : attr->value;
+
if (!util::isJavaClassName(qualifiedClassName)) {
diag->error(DiagMessage(el->lineNumber)
<< "attribute 'android:name' in <"
@@ -47,14 +48,14 @@
}
static bool optionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
- if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) {
+ if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "name")) {
return nameIsJavaClassName(el, attr, diag);
}
return true;
}
static bool requiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
- if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) {
+ if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "name")) {
return nameIsJavaClassName(el, attr, diag);
}
diag->error(DiagMessage(el->lineNumber)
@@ -63,7 +64,7 @@
}
static bool verifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
- xml::Attribute* attr = el->findAttribute({}, u"package");
+ xml::Attribute* attr = el->findAttribute({}, "package");
if (!attr) {
diag->error(DiagMessage(el->lineNumber) << "<manifest> tag is missing 'package' attribute");
return false;
@@ -100,31 +101,31 @@
// Common intent-filter actions.
xml::XmlNodeAction intentFilterAction;
- intentFilterAction[u"action"];
- intentFilterAction[u"category"];
- intentFilterAction[u"data"];
+ intentFilterAction["action"];
+ intentFilterAction["category"];
+ intentFilterAction["data"];
// Common meta-data actions.
xml::XmlNodeAction metaDataAction;
// Manifest actions.
- xml::XmlNodeAction& manifestAction = (*executor)[u"manifest"];
+ xml::XmlNodeAction& manifestAction = (*executor)["manifest"];
manifestAction.action(verifyManifest);
manifestAction.action([&](xml::Element* el) -> bool {
if (mOptions.versionNameDefault) {
- if (el->findAttribute(xml::kSchemaAndroid, u"versionName") == nullptr) {
+ if (el->findAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
el->attributes.push_back(xml::Attribute{
xml::kSchemaAndroid,
- u"versionName",
+ "versionName",
mOptions.versionNameDefault.value() });
}
}
if (mOptions.versionCodeDefault) {
- if (el->findAttribute(xml::kSchemaAndroid, u"versionCode") == nullptr) {
+ if (el->findAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
el->attributes.push_back(xml::Attribute{
xml::kSchemaAndroid,
- u"versionCode",
+ "versionCode",
mOptions.versionCodeDefault.value() });
}
}
@@ -132,87 +133,87 @@
});
// Meta tags.
- manifestAction[u"eat-comment"];
+ manifestAction["eat-comment"];
// Uses-sdk actions.
- manifestAction[u"uses-sdk"].action([&](xml::Element* el) -> bool {
+ manifestAction["uses-sdk"].action([&](xml::Element* el) -> bool {
if (mOptions.minSdkVersionDefault &&
- el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion") == nullptr) {
+ el->findAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
// There was no minSdkVersion defined and we have a default to assign.
el->attributes.push_back(xml::Attribute{
- xml::kSchemaAndroid, u"minSdkVersion",
+ xml::kSchemaAndroid, "minSdkVersion",
mOptions.minSdkVersionDefault.value() });
}
if (mOptions.targetSdkVersionDefault &&
- el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion") == nullptr) {
+ el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
// There was no targetSdkVersion defined and we have a default to assign.
el->attributes.push_back(xml::Attribute{
- xml::kSchemaAndroid, u"targetSdkVersion",
+ xml::kSchemaAndroid, "targetSdkVersion",
mOptions.targetSdkVersionDefault.value() });
}
return true;
});
// Instrumentation actions.
- manifestAction[u"instrumentation"].action([&](xml::Element* el) -> bool {
+ manifestAction["instrumentation"].action([&](xml::Element* el) -> bool {
if (!mOptions.renameInstrumentationTargetPackage) {
return true;
}
- if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"targetPackage")) {
+ if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "targetPackage")) {
attr->value = mOptions.renameInstrumentationTargetPackage.value();
}
return true;
});
- manifestAction[u"original-package"];
- manifestAction[u"protected-broadcast"];
- manifestAction[u"uses-permission"];
- manifestAction[u"permission"];
- manifestAction[u"permission-tree"];
- manifestAction[u"permission-group"];
+ manifestAction["original-package"];
+ manifestAction["protected-broadcast"];
+ manifestAction["uses-permission"];
+ manifestAction["permission"];
+ manifestAction["permission-tree"];
+ manifestAction["permission-group"];
- manifestAction[u"uses-configuration"];
- manifestAction[u"uses-feature"];
- manifestAction[u"supports-screens"];
- manifestAction[u"compatible-screens"];
- manifestAction[u"supports-gl-texture"];
+ manifestAction["uses-configuration"];
+ manifestAction["uses-feature"];
+ manifestAction["supports-screens"];
+ manifestAction["compatible-screens"];
+ manifestAction["supports-gl-texture"];
// Application actions.
- xml::XmlNodeAction& applicationAction = (*executor)[u"manifest"][u"application"];
+ xml::XmlNodeAction& applicationAction = manifestAction["application"];
applicationAction.action(optionalNameIsJavaClassName);
// Uses library actions.
- applicationAction[u"uses-library"];
+ applicationAction["uses-library"];
// Meta-data.
- applicationAction[u"meta-data"] = metaDataAction;
+ applicationAction["meta-data"] = metaDataAction;
// Activity actions.
- applicationAction[u"activity"].action(requiredNameIsJavaClassName);
- applicationAction[u"activity"][u"intent-filter"] = intentFilterAction;
- applicationAction[u"activity"][u"meta-data"] = metaDataAction;
+ applicationAction["activity"].action(requiredNameIsJavaClassName);
+ applicationAction["activity"]["intent-filter"] = intentFilterAction;
+ applicationAction["activity"]["meta-data"] = metaDataAction;
// Activity alias actions.
- applicationAction[u"activity-alias"][u"intent-filter"] = intentFilterAction;
- applicationAction[u"activity-alias"][u"meta-data"] = metaDataAction;
+ applicationAction["activity-alias"]["intent-filter"] = intentFilterAction;
+ applicationAction["activity-alias"]["meta-data"] = metaDataAction;
// Service actions.
- applicationAction[u"service"].action(requiredNameIsJavaClassName);
- applicationAction[u"service"][u"intent-filter"] = intentFilterAction;
- applicationAction[u"service"][u"meta-data"] = metaDataAction;
+ applicationAction["service"].action(requiredNameIsJavaClassName);
+ applicationAction["service"]["intent-filter"] = intentFilterAction;
+ applicationAction["service"]["meta-data"] = metaDataAction;
// Receiver actions.
- applicationAction[u"receiver"].action(requiredNameIsJavaClassName);
- applicationAction[u"receiver"][u"intent-filter"] = intentFilterAction;
- applicationAction[u"receiver"][u"meta-data"] = metaDataAction;
+ applicationAction["receiver"].action(requiredNameIsJavaClassName);
+ applicationAction["receiver"]["intent-filter"] = intentFilterAction;
+ applicationAction["receiver"]["meta-data"] = metaDataAction;
// Provider actions.
- applicationAction[u"provider"].action(requiredNameIsJavaClassName);
- applicationAction[u"provider"][u"grant-uri-permissions"];
- applicationAction[u"provider"][u"meta-data"] = metaDataAction;
- applicationAction[u"provider"][u"path-permissions"];
+ applicationAction["provider"].action(requiredNameIsJavaClassName);
+ applicationAction["provider"]["grant-uri-permissions"];
+ applicationAction["provider"]["meta-data"] = metaDataAction;
+ applicationAction["provider"]["path-permissions"];
return true;
}
@@ -220,14 +221,14 @@
public:
using xml::Visitor::visit;
- explicit FullyQualifiedClassNameVisitor(const StringPiece16& package) : mPackage(package) {
+ explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : mPackage(package) {
}
void visit(xml::Element* el) override {
for (xml::Attribute& attr : el->attributes) {
if (attr.namespaceUri == xml::kSchemaAndroid
&& mClassAttributes.find(attr.name) != mClassAttributes.end()) {
- if (Maybe<std::u16string> newValue =
+ if (Maybe<std::string> newValue =
util::getFullyQualifiedClassName(mPackage, attr.value)) {
attr.value = std::move(newValue.value());
}
@@ -239,17 +240,17 @@
}
private:
- StringPiece16 mPackage;
- std::unordered_set<StringPiece16> mClassAttributes = { u"name" };
+ StringPiece mPackage;
+ std::unordered_set<StringPiece> mClassAttributes = { "name" };
};
-static bool renameManifestPackage(const StringPiece16& packageOverride, xml::Element* manifestEl) {
- xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
+static bool renameManifestPackage(const StringPiece& packageOverride, xml::Element* manifestEl) {
+ xml::Attribute* attr = manifestEl->findAttribute({}, "package");
// We've already verified that the manifest element is present, with a package name specified.
assert(attr);
- std::u16string originalPackage = std::move(attr->value);
+ std::string originalPackage = std::move(attr->value);
attr->value = packageOverride.toString();
FullyQualifiedClassNameVisitor visitor(originalPackage);
@@ -259,17 +260,17 @@
bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
xml::Element* root = xml::findRootElement(doc->root.get());
- if (!root || !root->namespaceUri.empty() || root->name != u"manifest") {
+ if (!root || !root->namespaceUri.empty() || root->name != "manifest") {
context->getDiagnostics()->error(DiagMessage(doc->file.source)
<< "root tag must be <manifest>");
return false;
}
if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
- && root->findChild({}, u"uses-sdk") == nullptr) {
+ && root->findChild({}, "uses-sdk") == nullptr) {
// Auto insert a <uses-sdk> element.
std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
- usesSdk->name = u"uses-sdk";
+ usesSdk->name = "uses-sdk";
root->addChild(std::move(usesSdk));
}
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index 4d9356a..55b587e 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -27,12 +27,12 @@
namespace aapt {
struct ManifestFixerOptions {
- Maybe<std::u16string> minSdkVersionDefault;
- Maybe<std::u16string> targetSdkVersionDefault;
- Maybe<std::u16string> renameManifestPackage;
- Maybe<std::u16string> renameInstrumentationTargetPackage;
- Maybe<std::u16string> versionNameDefault;
- Maybe<std::u16string> versionCodeDefault;
+ Maybe<std::string> minSdkVersionDefault;
+ Maybe<std::string> targetSdkVersionDefault;
+ Maybe<std::string> renameManifestPackage;
+ Maybe<std::string> renameInstrumentationTargetPackage;
+ Maybe<std::string> versionNameDefault;
+ Maybe<std::string> versionCodeDefault;
};
/**
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index f993720..6d52c4c 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -27,25 +27,25 @@
void SetUp() override {
mContext = test::ContextBuilder()
- .setCompilationPackage(u"android")
+ .setCompilationPackage("android")
.setPackageId(0x01)
- .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .setNameManglerPolicy(NameManglerPolicy{ "android" })
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addSymbol(u"@android:attr/package", ResourceId(0x01010000),
+ .addSymbol("@android:attr/package", ResourceId(0x01010000),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_STRING)
.build())
- .addSymbol(u"@android:attr/minSdkVersion", ResourceId(0x01010001),
+ .addSymbol("@android:attr/minSdkVersion", ResourceId(0x01010001),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_STRING |
android::ResTable_map::TYPE_INTEGER)
.build())
- .addSymbol(u"@android:attr/targetSdkVersion", ResourceId(0x01010002),
+ .addSymbol("@android:attr/targetSdkVersion", ResourceId(0x01010002),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_STRING |
android::ResTable_map::TYPE_INTEGER)
.build())
- .addSymbol(u"@android:string/str", ResourceId(0x01060000))
+ .addSymbol("@android:string/str", ResourceId(0x01060000))
.build())
.build();
}
@@ -83,7 +83,7 @@
}
TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
- ManifestFixerOptions options = { std::u16string(u"8"), std::u16string(u"22") };
+ ManifestFixerOptions options = { std::string("8"), std::string("22") };
std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -97,14 +97,14 @@
el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
- el = el->findChild({}, u"uses-sdk");
+ el = el->findChild({}, "uses-sdk");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
+ attr = el->findAttribute(xml::kSchemaAndroid, "minSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"7", attr->value);
- attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
+ EXPECT_EQ("7", attr->value);
+ attr = el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"21", attr->value);
+ EXPECT_EQ("21", attr->value);
doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -115,14 +115,14 @@
el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
- el = el->findChild({}, u"uses-sdk");
+ el = el->findChild({}, "uses-sdk");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
+ attr = el->findAttribute(xml::kSchemaAndroid, "minSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"8", attr->value);
- attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
+ EXPECT_EQ("8", attr->value);
+ attr = el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"21", attr->value);
+ EXPECT_EQ("21", attr->value);
doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -133,14 +133,14 @@
el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
- el = el->findChild({}, u"uses-sdk");
+ el = el->findChild({}, "uses-sdk");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
+ attr = el->findAttribute(xml::kSchemaAndroid, "minSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"8", attr->value);
- attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
+ EXPECT_EQ("8", attr->value);
+ attr = el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"22", attr->value);
+ EXPECT_EQ("22", attr->value);
doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -149,19 +149,19 @@
el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
- el = el->findChild({}, u"uses-sdk");
+ el = el->findChild({}, "uses-sdk");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
+ attr = el->findAttribute(xml::kSchemaAndroid, "minSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"8", attr->value);
- attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
+ EXPECT_EQ("8", attr->value);
+ attr = el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(u"22", attr->value);
+ EXPECT_EQ("22", attr->value);
}
TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
ManifestFixerOptions options;
- options.renameManifestPackage = std::u16string(u"com.android");
+ options.renameManifestPackage = std::string("com.android");
std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -178,40 +178,40 @@
xml::Attribute* attr = nullptr;
- attr = manifestEl->findAttribute({}, u"package");
+ attr = manifestEl->findAttribute({},"package");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::u16string(u"com.android"), attr->value);
+ EXPECT_EQ(std::string("com.android"), attr->value);
- xml::Element* applicationEl = manifestEl->findChild({}, u"application");
+ xml::Element* applicationEl = manifestEl->findChild({}, "application");
ASSERT_NE(nullptr, applicationEl);
- attr = applicationEl->findAttribute(xml::kSchemaAndroid, u"name");
+ attr = applicationEl->findAttribute(xml::kSchemaAndroid, "name");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::u16string(u"android.MainApplication"), attr->value);
+ EXPECT_EQ(std::string("android.MainApplication"), attr->value);
- attr = applicationEl->findAttribute({}, u"text");
+ attr = applicationEl->findAttribute({}, "text");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::u16string(u"hello"), attr->value);
+ EXPECT_EQ(std::string("hello"), attr->value);
xml::Element* el;
- el = applicationEl->findChild({}, u"activity");
+ el = applicationEl->findChild({}, "activity");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute(xml::kSchemaAndroid, u"name");
+ attr = el->findAttribute(xml::kSchemaAndroid, "name");
ASSERT_NE(nullptr, el);
- EXPECT_EQ(std::u16string(u"android.activity.Start"), attr->value);
+ EXPECT_EQ(std::string("android.activity.Start"), attr->value);
- el = applicationEl->findChild({}, u"receiver");
+ el = applicationEl->findChild({}, "receiver");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute(xml::kSchemaAndroid, u"name");
+ attr = el->findAttribute(xml::kSchemaAndroid, "name");
ASSERT_NE(nullptr, el);
- EXPECT_EQ(std::u16string(u"com.google.android.Receiver"), attr->value);
+ EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value);
}
TEST_F(ManifestFixerTest, RenameManifestInstrumentationPackageAndFullyQualifyTarget) {
ManifestFixerOptions options;
- options.renameInstrumentationTargetPackage = std::u16string(u"com.android");
+ options.renameInstrumentationTargetPackage = std::string("com.android");
std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -223,18 +223,18 @@
xml::Element* manifestEl = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, manifestEl);
- xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
+ xml::Element* instrumentationEl = manifestEl->findChild({}, "instrumentation");
ASSERT_NE(nullptr, instrumentationEl);
- xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
+ xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, "targetPackage");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::u16string(u"com.android"), attr->value);
+ EXPECT_EQ(std::string("com.android"), attr->value);
}
TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
ManifestFixerOptions options;
- options.versionNameDefault = std::u16string(u"Beta");
- options.versionCodeDefault = std::u16string(u"0x10000000");
+ options.versionNameDefault = std::string("Beta");
+ options.versionCodeDefault = std::string("0x10000000");
std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -244,13 +244,13 @@
xml::Element* manifestEl = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, manifestEl);
- xml::Attribute* attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName");
+ xml::Attribute* attr = manifestEl->findAttribute(xml::kSchemaAndroid, "versionName");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::u16string(u"Beta"), attr->value);
+ EXPECT_EQ(std::string("Beta"), attr->value);
- attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode");
+ attr = manifestEl->findAttribute(xml::kSchemaAndroid, "versionCode");
ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::u16string(u"0x10000000"), attr->value);
+ EXPECT_EQ(std::string("0x10000000"), attr->value);
}
} // namespace aapt
diff --git a/tools/aapt2/link/PrivateAttributeMover_test.cpp b/tools/aapt2/link/PrivateAttributeMover_test.cpp
index dbe0c92..136e10b 100644
--- a/tools/aapt2/link/PrivateAttributeMover_test.cpp
+++ b/tools/aapt2/link/PrivateAttributeMover_test.cpp
@@ -15,10 +15,7 @@
*/
#include "link/Linkers.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
@@ -26,45 +23,45 @@
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addSimple(u"@android:attr/publicA")
- .addSimple(u"@android:attr/privateA")
- .addSimple(u"@android:attr/publicB")
- .addSimple(u"@android:attr/privateB")
- .setSymbolState(u"@android:attr/publicA", ResourceId(0x01010000), SymbolState::kPublic)
- .setSymbolState(u"@android:attr/publicB", ResourceId(0x01010000), SymbolState::kPublic)
+ .addSimple("@android:attr/publicA")
+ .addSimple("@android:attr/privateA")
+ .addSimple("@android:attr/publicB")
+ .addSimple("@android:attr/privateB")
+ .setSymbolState("@android:attr/publicA", ResourceId(0x01010000), SymbolState::kPublic)
+ .setSymbolState("@android:attr/publicB", ResourceId(0x01010000), SymbolState::kPublic)
.build();
PrivateAttributeMover mover;
ASSERT_TRUE(mover.consume(context.get(), table.get()));
- ResourceTablePackage* package = table->findPackage(u"android");
+ ResourceTablePackage* package = table->findPackage("android");
ASSERT_NE(package, nullptr);
ResourceTableType* type = package->findType(ResourceType::kAttr);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
- EXPECT_NE(type->findEntry(u"publicA"), nullptr);
- EXPECT_NE(type->findEntry(u"publicB"), nullptr);
+ EXPECT_NE(type->findEntry("publicA"), nullptr);
+ EXPECT_NE(type->findEntry("publicB"), nullptr);
type = package->findType(ResourceType::kAttrPrivate);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
- EXPECT_NE(type->findEntry(u"privateA"), nullptr);
- EXPECT_NE(type->findEntry(u"privateB"), nullptr);
+ EXPECT_NE(type->findEntry("privateA"), nullptr);
+ EXPECT_NE(type->findEntry("privateB"), nullptr);
}
TEST(PrivateAttributeMoverTest, LeavePrivateAttributesWhenNoPublicAttributesDefined) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addSimple(u"@android:attr/privateA")
- .addSimple(u"@android:attr/privateB")
+ .addSimple("@android:attr/privateA")
+ .addSimple("@android:attr/privateB")
.build();
PrivateAttributeMover mover;
ASSERT_TRUE(mover.consume(context.get(), table.get()));
- ResourceTablePackage* package = table->findPackage(u"android");
+ ResourceTablePackage* package = table->findPackage("android");
ASSERT_NE(package, nullptr);
ResourceTableType* type = package->findType(ResourceType::kAttr);
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
index f4f756a..811323b 100644
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -15,10 +15,7 @@
*/
#include "link/ProductFilter.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
@@ -29,23 +26,23 @@
const ConfigDescription port = test::parseConfigOrDie("port");
ResourceTable table;
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
land, "",
test::ValueBuilder<Id>()
.setSource(Source("land/default.xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
land, "tablet",
test::ValueBuilder<Id>()
.setSource(Source("land/tablet.xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
port, "",
test::ValueBuilder<Id>()
.setSource(Source("port/default.xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
port, "tablet",
test::ValueBuilder<Id>()
.setSource(Source("port/tablet.xml")).build(),
@@ -54,13 +51,13 @@
ProductFilter filter({ "tablet" });
ASSERT_TRUE(filter.consume(context.get(), &table));
- EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/one",
land, ""));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/one",
land, "tablet"));
- EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/one",
port, ""));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/one",
port, "tablet"));
}
@@ -68,12 +65,12 @@
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
ResourceTable table;
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "",
test::ValueBuilder<Id>()
.setSource(Source("default.xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "tablet",
test::ValueBuilder<Id>()
.setSource(Source("tablet.xml")).build(),
@@ -82,10 +79,10 @@
ProductFilter filter({});
ASSERT_TRUE(filter.consume(context.get(), &table));
- EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/one",
ConfigDescription::defaultConfig(),
""));
- EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, "@android:string/one",
ConfigDescription::defaultConfig(),
"tablet"));
}
@@ -94,17 +91,17 @@
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
ResourceTable table;
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "",
test::ValueBuilder<Id>()
.setSource(Source("default.xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "tablet",
test::ValueBuilder<Id>()
.setSource(Source("tablet.xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "no-sdcard",
test::ValueBuilder<Id>()
.setSource(Source("no-sdcard.xml")).build(),
@@ -118,12 +115,12 @@
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
ResourceTable table;
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "",
test::ValueBuilder<Id>()
.setSource(Source(".xml")).build(),
context->getDiagnostics()));
- ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie("@android:string/one"),
ConfigDescription::defaultConfig(), "default",
test::ValueBuilder<Id>()
.setSource(Source("default.xml")).build(),
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 66eb0df..fe886de 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -288,7 +288,7 @@
struct EmptyDeclStack : public xml::IPackageDeclStack {
Maybe<xml::ExtractedPackage> transformPackageAlias(
- const StringPiece16& alias, const StringPiece16& localPackage) const override {
+ const StringPiece& alias, const StringPiece& localPackage) const override {
if (alias.empty()) {
return xml::ExtractedPackage{ localPackage.toString(), true /* private */ };
}
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index 76b2309..17c2636 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -23,41 +23,41 @@
TEST(ReferenceLinkerTest, LinkSimpleReferences) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addReference(u"@com.app.test:string/foo", ResourceId(0x7f020000),
- u"@com.app.test:string/bar")
+ .setPackageId("com.app.test", 0x7f)
+ .addReference("@com.app.test:string/foo", ResourceId(0x7f020000),
+ "@com.app.test:string/bar")
// Test use of local reference (w/o package name).
- .addReference(u"@com.app.test:string/bar", ResourceId(0x7f020001), u"@string/baz")
+ .addReference("@com.app.test:string/bar", ResourceId(0x7f020001), "@string/baz")
- .addReference(u"@com.app.test:string/baz", ResourceId(0x7f020002),
- u"@android:string/ok")
+ .addReference("@com.app.test:string/baz", ResourceId(0x7f020002),
+ "@android:string/ok")
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test" })
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
+ .addPublicSymbol("@android:string/ok", ResourceId(0x01040034))
.build())
.build();
ReferenceLinker linker;
ASSERT_TRUE(linker.consume(context.get(), table.get()));
- Reference* ref = test::getValue<Reference>(table.get(), u"@com.app.test:string/foo");
+ Reference* ref = test::getValue<Reference>(table.get(), "@com.app.test:string/foo");
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->id);
EXPECT_EQ(ref->id.value(), ResourceId(0x7f020001));
- ref = test::getValue<Reference>(table.get(), u"@com.app.test:string/bar");
+ ref = test::getValue<Reference>(table.get(), "@com.app.test:string/bar");
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->id);
EXPECT_EQ(ref->id.value(), ResourceId(0x7f020002));
- ref = test::getValue<Reference>(table.get(), u"@com.app.test:string/baz");
+ ref = test::getValue<Reference>(table.get(), "@com.app.test:string/baz");
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->id);
EXPECT_EQ(ref->id.value(), ResourceId(0x01040034));
@@ -65,39 +65,39 @@
TEST(ReferenceLinkerTest, LinkStyleAttributes) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addValue(u"@com.app.test:style/Theme", test::StyleBuilder()
- .setParent(u"@android:style/Theme.Material")
- .addItem(u"@android:attr/foo", ResourceUtils::tryParseColor(u"#ff00ff"))
- .addItem(u"@android:attr/bar", {} /* placeholder */)
+ .setPackageId("com.app.test", 0x7f)
+ .addValue("@com.app.test:style/Theme", test::StyleBuilder()
+ .setParent("@android:style/Theme.Material")
+ .addItem("@android:attr/foo", ResourceUtils::tryParseColor("#ff00ff"))
+ .addItem("@android:attr/bar", {} /* placeholder */)
.build())
.build();
{
// We need to fill in the value for the attribute android:attr/bar after we build the
// table, because we need access to the string pool.
- Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
+ Style* style = test::getValue<Style>(table.get(), "@com.app.test:style/Theme");
ASSERT_NE(style, nullptr);
style->entries.back().value = util::make_unique<RawString>(
- table->stringPool.makeRef(u"one|two"));
+ table->stringPool.makeRef("one|two"));
}
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test" })
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addPublicSymbol(u"@android:style/Theme.Material",
+ .addPublicSymbol("@android:style/Theme.Material",
ResourceId(0x01060000))
- .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
+ .addPublicSymbol("@android:attr/foo", ResourceId(0x01010001),
test::AttributeBuilder()
.setTypeMask(ResTable_map::TYPE_COLOR)
.build())
- .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
+ .addPublicSymbol("@android:attr/bar", ResourceId(0x01010002),
test::AttributeBuilder()
.setTypeMask(ResTable_map::TYPE_FLAGS)
- .addItem(u"one", 0x01)
- .addItem(u"two", 0x02)
+ .addItem("one", 0x01)
+ .addItem("two", 0x02)
.build())
.build())
.build();
@@ -105,7 +105,7 @@
ReferenceLinker linker;
ASSERT_TRUE(linker.consume(context.get(), table.get()));
- Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
+ Style* style = test::getValue<Style>(table.get(), "@com.app.test:style/Theme");
ASSERT_NE(style, nullptr);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().id);
@@ -124,11 +124,11 @@
TEST(ReferenceLinkerTest, LinkMangledReferencesAndAttributes) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test", { "com.android.support" } })
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
+ .addPublicSymbol("@com.app.test:attr/com.android.support$foo",
ResourceId(0x7f010000),
test::AttributeBuilder()
.setTypeMask(ResTable_map::TYPE_COLOR)
@@ -137,17 +137,17 @@
.build();
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addValue(u"@com.app.test:style/Theme", ResourceId(0x7f020000),
- test::StyleBuilder().addItem(u"@com.android.support:attr/foo",
- ResourceUtils::tryParseColor(u"#ff0000"))
+ .setPackageId("com.app.test", 0x7f)
+ .addValue("@com.app.test:style/Theme", ResourceId(0x7f020000),
+ test::StyleBuilder().addItem("@com.android.support:attr/foo",
+ ResourceUtils::tryParseColor("#ff0000"))
.build())
.build();
ReferenceLinker linker;
ASSERT_TRUE(linker.consume(context.get(), table.get()));
- Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
+ Style* style = test::getValue<Style>(table.get(), "@com.app.test:style/Theme");
ASSERT_NE(style, nullptr);
ASSERT_EQ(1u, style->entries.size());
AAPT_ASSERT_TRUE(style->entries.front().key.id);
@@ -156,18 +156,18 @@
TEST(ReferenceLinkerTest, FailToLinkPrivateSymbols) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addReference(u"@com.app.test:string/foo", ResourceId(0x7f020000),
- u"@android:string/hidden")
+ .setPackageId("com.app.test", 0x7f)
+ .addReference("@com.app.test:string/foo", ResourceId(0x7f020000),
+ "@android:string/hidden")
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test" })
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
+ .addSymbol("@android:string/hidden", ResourceId(0x01040034))
.build())
.build();
@@ -177,18 +177,18 @@
TEST(ReferenceLinkerTest, FailToLinkPrivateMangledSymbols) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addReference(u"@com.app.test:string/foo", ResourceId(0x7f020000),
- u"@com.app.lib:string/hidden")
+ .setPackageId("com.app.test", 0x7f)
+ .addReference("@com.app.test:string/foo", ResourceId(0x7f020000),
+ "@com.app.lib:string/hidden")
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.app.lib" } })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test", { "com.app.lib" } })
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
+ .addSymbol("@com.app.test:string/com.app.lib$hidden",
ResourceId(0x7f040034))
.build())
@@ -200,19 +200,19 @@
TEST(ReferenceLinkerTest, FailToLinkPrivateStyleAttributes) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addValue(u"@com.app.test:style/Theme", test::StyleBuilder()
- .addItem(u"@android:attr/hidden", ResourceUtils::tryParseColor(u"#ff00ff"))
+ .setPackageId("com.app.test", 0x7f)
+ .addValue("@com.app.test:style/Theme", test::StyleBuilder()
+ .addItem("@android:attr/hidden", ResourceUtils::tryParseColor("#ff00ff"))
.build())
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setPackageId(0x7f)
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.test" })
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
+ .addSymbol("@android:attr/hidden", ResourceId(0x01010001),
test::AttributeBuilder()
.setTypeMask(
android::ResTable_map::TYPE_COLOR)
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 7471e15..2cd2639 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -67,7 +67,7 @@
callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
FileReference* newFile, FileReference* oldFile) -> bool {
// The old file's path points inside the APK, so we can use it as is.
- io::IFile* f = collection->findFile(util::utf16ToUtf8(*oldFile->path));
+ io::IFile* f = collection->findFile(*oldFile->path);
if (!f) {
mContext->getDiagnostics()->error(DiagMessage(src) << "file '"
<< *oldFile->path
@@ -95,7 +95,7 @@
/**
* This will merge and mangle resources from a static library.
*/
-bool TableMerger::mergeAndMangle(const Source& src, const StringPiece16& packageName,
+bool TableMerger::mergeAndMangle(const Source& src, const StringPiece& packageName,
ResourceTable* table, io::IFileCollection* collection) {
bool error = false;
for (auto& package : table->packages) {
@@ -112,7 +112,7 @@
auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
FileReference* newFile, FileReference* oldFile) -> bool {
// The old file's path points inside the APK, so we can use it as is.
- io::IFile* f = collection->findFile(util::utf16ToUtf8(*oldFile->path));
+ io::IFile* f = collection->findFile(*oldFile->path);
if (!f) {
mContext->getDiagnostics()->error(DiagMessage(src) << "file '" << *oldFile->path
<< "' not found");
@@ -159,8 +159,8 @@
for (auto& srcEntry : srcType->entries) {
ResourceEntry* dstEntry;
if (manglePackage) {
- std::u16string mangledName = NameMangler::mangleEntry(srcPackage->name,
- srcEntry->name);
+ std::string mangledName = NameMangler::mangleEntry(srcPackage->name,
+ srcEntry->name);
if (allowNewResources) {
dstEntry = dstType->findOrCreateEntry(mangledName);
} else {
@@ -275,13 +275,13 @@
return !error;
}
-std::unique_ptr<FileReference> TableMerger::cloneAndMangleFile(const std::u16string& package,
+std::unique_ptr<FileReference> TableMerger::cloneAndMangleFile(const std::string& package,
const FileReference& fileRef) {
- StringPiece16 prefix, entry, suffix;
+ StringPiece prefix, entry, suffix;
if (util::extractResFilePathParts(*fileRef.path, &prefix, &entry, &suffix)) {
- std::u16string mangledEntry = NameMangler::mangleEntry(package, entry.toString());
- std::u16string newPath = prefix.toString() + mangledEntry + suffix.toString();
+ std::string mangledEntry = NameMangler::mangleEntry(package, entry.toString());
+ std::string newPath = prefix.toString() + mangledEntry + suffix.toString();
std::unique_ptr<FileReference> newFileRef = util::make_unique<FileReference>(
mMasterTable->stringPool.makeRef(newPath));
newFileRef->setComment(fileRef.getComment());
@@ -293,8 +293,7 @@
bool TableMerger::mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay) {
ResourceTable table;
- std::u16string path = util::utf8ToUtf16(ResourceUtils::buildResourceFileName(fileDesc,
- nullptr));
+ std::string path = ResourceUtils::buildResourceFileName(fileDesc, nullptr);
std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
table.stringPool.makeRef(path));
fileRef->setSource(fileDesc.source);
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 80c2a5e..6997f93 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -59,7 +59,7 @@
*/
TableMerger(IAaptContext* context, ResourceTable* outTable, const TableMergerOptions& options);
- const std::set<std::u16string>& getMergedPackages() const {
+ const std::set<std::string>& getMergedPackages() const {
return mMergedPackages;
}
@@ -81,7 +81,7 @@
* Merges resources from the given package, mangling the name. This is for static libraries.
* An io::IFileCollection is needed in order to find the referenced Files and process them.
*/
- bool mergeAndMangle(const Source& src, const StringPiece16& package, ResourceTable* table,
+ bool mergeAndMangle(const Source& src, const StringPiece& package, ResourceTable* table,
io::IFileCollection* collection);
/**
@@ -104,7 +104,7 @@
TableMergerOptions mOptions;
ResourceTablePackage* mMasterPackage;
- std::set<std::u16string> mMergedPackages;
+ std::set<std::string> mMergedPackages;
bool mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay);
@@ -117,7 +117,7 @@
const bool allowNewResources,
FileMergeCallback callback);
- std::unique_ptr<FileReference> cloneAndMangleFile(const std::u16string& package,
+ std::unique_ptr<FileReference> cloneAndMangleFile(const std::string& package,
const FileReference& value);
};
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 4a80d3f..1697217 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -30,13 +30,13 @@
void SetUp() override {
mContext = test::ContextBuilder()
// We are compiling this package.
- .setCompilationPackage(u"com.app.a")
+ .setCompilationPackage("com.app.a")
// Merge all packages that have this package ID.
.setPackageId(0x7f)
// Mangle all packages that do not have this package name.
- .setNameManglerPolicy(NameManglerPolicy{ u"com.app.a", { u"com.app.b" } })
+ .setNameManglerPolicy(NameManglerPolicy{ "com.app.a", { "com.app.b" } })
.build();
}
@@ -44,17 +44,17 @@
TEST_F(TableMergerTest, SimpleMerge) {
std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
- .setPackageId(u"com.app.a", 0x7f)
- .addReference(u"@com.app.a:id/foo", u"@com.app.a:id/bar")
- .addReference(u"@com.app.a:id/bar", u"@com.app.b:id/foo")
- .addValue(u"@com.app.a:styleable/view", test::StyleableBuilder()
- .addItem(u"@com.app.b:id/foo")
+ .setPackageId("com.app.a", 0x7f)
+ .addReference("@com.app.a:id/foo", "@com.app.a:id/bar")
+ .addReference("@com.app.a:id/bar", "@com.app.b:id/foo")
+ .addValue("@com.app.a:styleable/view", test::StyleableBuilder()
+ .addItem("@com.app.b:id/foo")
.build())
.build();
std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
- .setPackageId(u"com.app.b", 0x7f)
- .addSimple(u"@com.app.b:id/foo")
+ .setPackageId("com.app.b", 0x7f)
+ .addSimple("@com.app.b:id/foo")
.build();
ResourceTable finalTable;
@@ -62,20 +62,20 @@
io::FileCollection collection;
ASSERT_TRUE(merger.merge({}, tableA.get()));
- ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
+ ASSERT_TRUE(merger.mergeAndMangle({}, "com.app.b", tableB.get(), &collection));
- EXPECT_TRUE(merger.getMergedPackages().count(u"com.app.b") != 0);
+ EXPECT_TRUE(merger.getMergedPackages().count("com.app.b") != 0);
// Entries from com.app.a should not be mangled.
- AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/foo")));
- AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/bar")));
- AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:styleable/view")));
+ AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie("@com.app.a:id/foo")));
+ AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie("@com.app.a:id/bar")));
+ AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie("@com.app.a:styleable/view")));
// The unmangled name should not be present.
- AAPT_EXPECT_FALSE(finalTable.findResource(test::parseNameOrDie(u"@com.app.b:id/foo")));
+ AAPT_EXPECT_FALSE(finalTable.findResource(test::parseNameOrDie("@com.app.b:id/foo")));
// Look for the mangled name.
- AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/com.app.b$foo")));
+ AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie("@com.app.a:id/com.app.b$foo")));
}
TEST_F(TableMergerTest, MergeFile) {
@@ -86,17 +86,17 @@
ResourceFile fileDesc;
fileDesc.config = test::parseConfigOrDie("hdpi-v4");
- fileDesc.name = test::parseNameOrDie(u"@layout/main");
+ fileDesc.name = test::parseNameOrDie("@layout/main");
fileDesc.source = Source("res/layout-hdpi/main.xml");
test::TestFile testFile("path/to/res/layout-hdpi/main.xml.flat");
ASSERT_TRUE(merger.mergeFile(fileDesc, &testFile));
FileReference* file = test::getValueForConfig<FileReference>(&finalTable,
- u"@com.app.a:layout/main",
+ "@com.app.a:layout/main",
test::parseConfigOrDie("hdpi-v4"));
ASSERT_NE(nullptr, file);
- EXPECT_EQ(std::u16string(u"res/layout-hdpi-v4/main.xml"), *file->path);
+ EXPECT_EQ(std::string("res/layout-hdpi-v4/main.xml"), *file->path);
}
TEST_F(TableMergerTest, MergeFileOverlay) {
@@ -106,7 +106,7 @@
TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
ResourceFile fileDesc;
- fileDesc.name = test::parseNameOrDie(u"@xml/foo");
+ fileDesc.name = test::parseNameOrDie("@xml/foo");
test::TestFile fileA("path/to/fileA.xml.flat");
test::TestFile fileB("path/to/fileB.xml.flat");
@@ -116,12 +116,12 @@
TEST_F(TableMergerTest, MergeFileReferences) {
std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
- .setPackageId(u"com.app.a", 0x7f)
- .addFileReference(u"@com.app.a:xml/file", u"res/xml/file.xml")
+ .setPackageId("com.app.a", 0x7f)
+ .addFileReference("@com.app.a:xml/file", "res/xml/file.xml")
.build();
std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
- .setPackageId(u"com.app.b", 0x7f)
- .addFileReference(u"@com.app.b:xml/file", u"res/xml/file.xml")
+ .setPackageId("com.app.b", 0x7f)
+ .addFileReference("@com.app.b:xml/file", "res/xml/file.xml")
.build();
ResourceTable finalTable;
@@ -130,25 +130,25 @@
collection.insertFile("res/xml/file.xml");
ASSERT_TRUE(merger.merge({}, tableA.get()));
- ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
+ ASSERT_TRUE(merger.mergeAndMangle({}, "com.app.b", tableB.get(), &collection));
- FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file");
+ FileReference* f = test::getValue<FileReference>(&finalTable, "@com.app.a:xml/file");
ASSERT_NE(f, nullptr);
- EXPECT_EQ(std::u16string(u"res/xml/file.xml"), *f->path);
+ EXPECT_EQ(std::string("res/xml/file.xml"), *f->path);
- f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/com.app.b$file");
+ f = test::getValue<FileReference>(&finalTable, "@com.app.a:xml/com.app.b$file");
ASSERT_NE(f, nullptr);
- EXPECT_EQ(std::u16string(u"res/xml/com.app.b$file.xml"), *f->path);
+ EXPECT_EQ(std::string("res/xml/com.app.b$file.xml"), *f->path);
}
TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
std::unique_ptr<ResourceTable> base = test::ResourceTableBuilder()
- .setPackageId(u"", 0x00)
- .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+ .setPackageId("", 0x00)
+ .addValue("@bool/foo", ResourceUtils::tryParseBool("true"))
.build();
std::unique_ptr<ResourceTable> overlay = test::ResourceTableBuilder()
- .setPackageId(u"", 0x00)
- .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"false"))
+ .setPackageId("", 0x00)
+ .addValue("@bool/foo", ResourceUtils::tryParseBool("false"))
.build();
ResourceTable finalTable;
@@ -159,19 +159,19 @@
ASSERT_TRUE(merger.merge({}, base.get()));
ASSERT_TRUE(merger.mergeOverlay({}, overlay.get()));
- BinaryPrimitive* foo = test::getValue<BinaryPrimitive>(&finalTable, u"@com.app.a:bool/foo");
+ BinaryPrimitive* foo = test::getValue<BinaryPrimitive>(&finalTable, "@com.app.a:bool/foo");
ASSERT_NE(nullptr, foo);
EXPECT_EQ(0x0u, foo->value.data);
}
TEST_F(TableMergerTest, MergeAddResourceFromOverlay) {
std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
- .setPackageId(u"", 0x7f)
- .setSymbolState(u"@bool/foo", {}, SymbolState::kUndefined)
+ .setPackageId("", 0x7f)
+ .setSymbolState("@bool/foo", {}, SymbolState::kUndefined)
.build();
std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
- .setPackageId(u"", 0x7f)
- .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+ .setPackageId("", 0x7f)
+ .addValue("@bool/foo", ResourceUtils::tryParseBool("true"))
.build();
ResourceTable finalTable;
@@ -183,11 +183,11 @@
TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) {
std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
- .setPackageId(u"", 0x7f)
+ .setPackageId("", 0x7f)
.build();
std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
- .setPackageId(u"", 0x7f)
- .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+ .setPackageId("", 0x7f)
+ .addValue("@bool/foo", ResourceUtils::tryParseBool("true"))
.build();
ResourceTable finalTable;
@@ -201,11 +201,11 @@
TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
- .setPackageId(u"", 0x7f)
+ .setPackageId("", 0x7f)
.build();
std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
- .setPackageId(u"", 0x7f)
- .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+ .setPackageId("", 0x7f)
+ .addValue("@bool/foo", ResourceUtils::tryParseBool("true"))
.build();
ResourceTable finalTable;
diff --git a/tools/aapt2/link/VersionCollapser_test.cpp b/tools/aapt2/link/VersionCollapser_test.cpp
index b5387fe..4113450 100644
--- a/tools/aapt2/link/VersionCollapser_test.cpp
+++ b/tools/aapt2/link/VersionCollapser_test.cpp
@@ -22,7 +22,7 @@
template <typename T>
using uptr = std::unique_ptr<T>;
-static uptr<ResourceTable> buildTableWithConfigs(const StringPiece16& name,
+static uptr<ResourceTable> buildTableWithConfigs(const StringPiece& name,
std::initializer_list<std::string> list) {
test::ResourceTableBuilder builder;
for (const std::string& item : list) {
@@ -34,7 +34,7 @@
TEST(VersionCollapserTest, CollapseVersions) {
uptr<IAaptContext> context = test::ContextBuilder().setMinSdkVersion(7).build();
- const StringPiece16 resName = u"@android:string/foo";
+ const StringPiece resName = "@android:string/foo";
uptr<ResourceTable> table =
buildTableWithConfigs(resName,
@@ -64,7 +64,7 @@
TEST(VersionCollapserTest, CollapseVersionsWhenMinSdkIsHighest) {
uptr<IAaptContext> context = test::ContextBuilder().setMinSdkVersion(26).build();
- const StringPiece16 resName = u"@android:string/foo";
+ const StringPiece resName = "@android:string/foo";
uptr<ResourceTable> table =
buildTableWithConfigs(resName,
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 568bc74..02af5e3 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -81,7 +81,7 @@
xml::extractPackageFromNamespace(attr.namespaceUri);
if (maybePackage) {
// There is a valid package name for this attribute. We will look this up.
- StringPiece16 package = maybePackage.value().package;
+ StringPiece package = maybePackage.value().package;
if (package.empty()) {
// Empty package means the 'current' or 'local' package.
package = mContext->getCompilationPackage();
diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp
index af9098b..d48de42 100644
--- a/tools/aapt2/link/XmlReferenceLinker_test.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <test/Context.h>
#include "link/Linkers.h"
#include "test/Test.h"
@@ -24,44 +23,44 @@
public:
void SetUp() override {
mContext = test::ContextBuilder()
- .setCompilationPackage(u"com.app.test")
+ .setCompilationPackage("com.app.test")
.setNameManglerPolicy(
- NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
+ NameManglerPolicy{ "com.app.test", { "com.android.support" } })
.addSymbolSource(test::StaticSymbolSourceBuilder()
- .addPublicSymbol(u"@android:attr/layout_width", ResourceId(0x01010000),
+ .addPublicSymbol("@android:attr/layout_width", ResourceId(0x01010000),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_ENUM |
android::ResTable_map::TYPE_DIMENSION)
- .addItem(u"match_parent", 0xffffffff)
+ .addItem("match_parent", 0xffffffff)
.build())
- .addPublicSymbol(u"@android:attr/background", ResourceId(0x01010001),
+ .addPublicSymbol("@android:attr/background", ResourceId(0x01010001),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_COLOR).build())
- .addPublicSymbol(u"@android:attr/attr", ResourceId(0x01010002),
+ .addPublicSymbol("@android:attr/attr", ResourceId(0x01010002),
test::AttributeBuilder().build())
- .addPublicSymbol(u"@android:attr/text", ResourceId(0x01010003),
+ .addPublicSymbol("@android:attr/text", ResourceId(0x01010003),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_STRING)
.build())
// Add one real symbol that was introduces in v21
- .addPublicSymbol(u"@android:attr/colorAccent", ResourceId(0x01010435),
+ .addPublicSymbol("@android:attr/colorAccent", ResourceId(0x01010435),
test::AttributeBuilder().build())
// Private symbol.
- .addSymbol(u"@android:color/hidden", ResourceId(0x01020001))
+ .addSymbol("@android:color/hidden", ResourceId(0x01020001))
- .addPublicSymbol(u"@android:id/id", ResourceId(0x01030000))
- .addSymbol(u"@com.app.test:id/id", ResourceId(0x7f030000))
- .addSymbol(u"@com.app.test:color/green", ResourceId(0x7f020000))
- .addSymbol(u"@com.app.test:color/red", ResourceId(0x7f020001))
- .addSymbol(u"@com.app.test:attr/colorAccent", ResourceId(0x7f010000),
+ .addPublicSymbol("@android:id/id", ResourceId(0x01030000))
+ .addSymbol("@com.app.test:id/id", ResourceId(0x7f030000))
+ .addSymbol("@com.app.test:color/green", ResourceId(0x7f020000))
+ .addSymbol("@com.app.test:color/red", ResourceId(0x7f020001))
+ .addSymbol("@com.app.test:attr/colorAccent", ResourceId(0x7f010000),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_COLOR).build())
- .addPublicSymbol(u"@com.app.test:attr/com.android.support$colorAccent",
+ .addPublicSymbol("@com.app.test:attr/com.android.support$colorAccent",
ResourceId(0x7f010001), test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_COLOR).build())
- .addPublicSymbol(u"@com.app.test:attr/attr", ResourceId(0x7f010002),
+ .addPublicSymbol("@com.app.test:attr/attr", ResourceId(0x7f010002),
test::AttributeBuilder().build())
.build())
.build();
@@ -85,8 +84,7 @@
xml::Element* viewEl = xml::findRootElement(doc.get());
ASSERT_NE(viewEl, nullptr);
- xml::Attribute* xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android",
- u"layout_width");
+ xml::Attribute* xmlAttr = viewEl->findAttribute(xml::kSchemaAndroid, "layout_width");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
@@ -94,7 +92,7 @@
ASSERT_NE(xmlAttr->compiledValue, nullptr);
ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
- xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"background");
+ xmlAttr = viewEl->findAttribute(xml::kSchemaAndroid, "background");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
@@ -103,17 +101,17 @@
Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->name);
- EXPECT_EQ(ref->name.value(), test::parseNameOrDie(u"@color/green")); // Make sure the name
- // didn't change.
+ EXPECT_EQ(ref->name.value(), test::parseNameOrDie("@color/green")); // Make sure the name
+ // didn't change.
AAPT_ASSERT_TRUE(ref->id);
EXPECT_EQ(ref->id.value(), ResourceId(0x7f020000));
- xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"text");
+ xmlAttr = viewEl->findAttribute(xml::kSchemaAndroid, "text");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
ASSERT_FALSE(xmlAttr->compiledValue); // Strings don't get compiled for memory sake.
- xmlAttr = viewEl->findAttribute(u"", u"class");
+ xmlAttr = viewEl->findAttribute("", "class");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_FALSE(xmlAttr->compiledAttribute);
ASSERT_EQ(xmlAttr->compiledValue, nullptr);
@@ -159,7 +157,7 @@
ASSERT_NE(viewEl, nullptr);
xml::Attribute* xmlAttr = viewEl->findAttribute(
- u"http://schemas.android.com/apk/res/com.android.support", u"colorAccent");
+ xml::buildPackageNamespace("com.android.support"), "colorAccent");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
@@ -178,8 +176,7 @@
xml::Element* viewEl = xml::findRootElement(doc.get());
ASSERT_NE(viewEl, nullptr);
- xml::Attribute* xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res-auto",
- u"colorAccent");
+ xml::Attribute* xmlAttr = viewEl->findAttribute(xml::kSchemaAuto, "colorAccent");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
@@ -206,8 +203,7 @@
ASSERT_NE(viewEl, nullptr);
// All attributes and references in this element should be referring to "android" (0x01).
- xml::Attribute* xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android",
- u"attr");
+ xml::Attribute* xmlAttr = viewEl->findAttribute(xml::kSchemaAndroid, "attr");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
@@ -222,7 +218,7 @@
ASSERT_NE(viewEl, nullptr);
// All attributes and references in this element should be referring to "com.app.test" (0x7f).
- xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/com.app.test", u"attr");
+ xmlAttr = viewEl->findAttribute(xml::buildPackageNamespace("com.app.test"), "attr");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
@@ -245,8 +241,8 @@
ASSERT_NE(viewEl, nullptr);
// All attributes and references in this element should be referring to "com.app.test" (0x7f).
- xml::Attribute* xmlAttr = viewEl->findAttribute(
- u"http://schemas.android.com/apk/res/com.app.test", u"attr");
+ xml::Attribute* xmlAttr = viewEl->findAttribute(xml::buildPackageNamespace("com.app.test"),
+ "attr");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 762725d..69b7d92 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -37,7 +37,7 @@
virtual SymbolTable* getExternalSymbols() = 0;
virtual IDiagnostics* getDiagnostics() = 0;
- virtual const std::u16string& getCompilationPackage() = 0;
+ virtual const std::string& getCompilationPackage() = 0;
virtual uint8_t getPackageId() = 0;
virtual NameMangler* getNameMangler() = 0;
virtual bool verbose() = 0;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index eaaf06f..6c506df 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -16,6 +16,7 @@
#include "ConfigDescription.h"
#include "Resource.h"
+#include "ResourceUtils.h"
#include "ValueVisitor.h"
#include "process/SymbolTable.h"
#include "util/Util.h"
@@ -84,7 +85,7 @@
const SymbolTable::Symbol* SymbolTable::findByReference(const Reference& ref) {
// First try the ID. This is because when we lookup by ID, we only fill in the ID cache.
// Looking up by name fills in the name and ID cache. So a cache miss will cause a failed
- // ID lookup, then a successfull name lookup. Subsequent look ups will hit immediately
+ // ID lookup, then a successful name lookup. Subsequent look ups will hit immediately
// because the ID is cached too.
//
// If we looked up by name first, a cache miss would mean we failed to lookup by name, then
@@ -184,18 +185,13 @@
return nullptr;
}
- const ResourceType* parsedType = parseResourceType(
- StringPiece16(entryName.type, entryName.typeLen));
- if (!parsedType) {
- table.unlockBag(entry);
+ Maybe<ResourceName> parsedName = ResourceUtils::toResourceName(entryName);
+ if (!parsedName) {
return nullptr;
}
Attribute::Symbol symbol;
- symbol.symbol.name = ResourceName(
- StringPiece16(entryName.package, entryName.packageLen),
- *parsedType,
- StringPiece16(entryName.name, entryName.nameLen));
+ symbol.symbol.name = parsedName.value();
symbol.symbol.id = ResourceId(mapEntry.name.ident);
symbol.value = mapEntry.value.data;
s->attribute->symbols.push_back(std::move(symbol));
@@ -208,11 +204,15 @@
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByName(
const ResourceName& name) {
const android::ResTable& table = mAssets.getResources(false);
- StringPiece16 typeStr = toString(name.type);
+
+ const std::u16string package16 = util::utf8ToUtf16(name.package);
+ const std::u16string type16 = util::utf8ToUtf16(toString(name.type));
+ const std::u16string entry16 = util::utf8ToUtf16(name.entry);
+
uint32_t typeSpecFlags = 0;
- ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
- typeStr.data(), typeStr.size(),
- name.package.data(), name.package.size(),
+ ResourceId resId = table.identifierForName(entry16.data(), entry16.size(),
+ type16.data(), type16.size(),
+ package16.data(), package16.size(),
&typeSpecFlags);
if (!resId.isValid()) {
return {};
@@ -238,37 +238,7 @@
if (!table.getResourceName(id.id, true, &resName)) {
return {};
}
-
- ResourceName name;
- if (resName.package) {
- name.package = StringPiece16(resName.package, resName.packageLen).toString();
- }
-
- const ResourceType* type;
- if (resName.type) {
- type = parseResourceType(StringPiece16(resName.type, resName.typeLen));
-
- } else if (resName.type8) {
- type = parseResourceType(util::utf8ToUtf16(StringPiece(resName.type8, resName.typeLen)));
- } else {
- return {};
- }
-
- if (!type) {
- return {};
- }
-
- name.type = *type;
-
- if (resName.name) {
- name.entry = StringPiece16(resName.name, resName.nameLen).toString();
- } else if (resName.name8) {
- name.entry = util::utf8ToUtf16(StringPiece(resName.name8, resName.nameLen));
- } else {
- return {};
- }
-
- return name;
+ return ResourceUtils::toResourceName(resName);
}
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(ResourceId id) {
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index e684bb0..43f4dd7 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -34,7 +34,7 @@
namespace aapt {
inline android::hash_t hash_type(const ResourceName& name) {
- std::hash<std::u16string> strHash;
+ std::hash<std::string> strHash;
android::hash_t hash = 0;
hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.package));
hash = android::JenkinsHashMix(hash, (uint32_t) name.type);
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index 34f31be..6866974 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -21,31 +21,31 @@
TEST(ResourceTableSymbolSourceTest, FindSymbols) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addSimple(u"@android:id/foo", ResourceId(0x01020000))
- .addSimple(u"@android:id/bar")
- .addValue(u"@android:attr/foo", ResourceId(0x01010000),
+ .addSimple("@android:id/foo", ResourceId(0x01020000))
+ .addSimple("@android:id/bar")
+ .addValue("@android:attr/foo", ResourceId(0x01010000),
test::AttributeBuilder().build())
.build();
ResourceTableSymbolSource symbolSource(table.get());
- EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/foo")));
- EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/bar")));
+ EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie("@android:id/foo")));
+ EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie("@android:id/bar")));
std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
- test::parseNameOrDie(u"@android:attr/foo"));
+ test::parseNameOrDie("@android:attr/foo"));
ASSERT_NE(nullptr, s);
EXPECT_NE(nullptr, s->attribute);
}
TEST(ResourceTableSymbolSourceTest, FindPrivateAttrSymbol) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addValue(u"@android:^attr-private/foo", ResourceId(0x01010000),
+ .addValue("@android:^attr-private/foo", ResourceId(0x01010000),
test::AttributeBuilder().build())
.build();
ResourceTableSymbolSource symbolSource(table.get());
std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
- test::parseNameOrDie(u"@android:attr/foo"));
+ test::parseNameOrDie("@android:attr/foo"));
ASSERT_NE(nullptr, s);
EXPECT_NE(nullptr, s->attribute);
}
diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp
index 99981c5..2aa8aa5 100644
--- a/tools/aapt2/proto/ProtoHelpers.cpp
+++ b/tools/aapt2/proto/ProtoHelpers.cpp
@@ -33,7 +33,7 @@
}
void serializeSourceToPb(const Source& source, StringPool* srcPool, pb::Source* outPbSource) {
- StringPool::Ref ref = srcPool->makeRef(util::utf8ToUtf16(source.path));
+ StringPool::Ref ref = srcPool->makeRef(source.path);
outPbSource->set_path_idx(static_cast<uint32_t>(ref.getIndex()));
if (source.line) {
outPbSource->set_line_no(static_cast<uint32_t>(source.line.value()));
@@ -43,7 +43,7 @@
void deserializeSourceFromPb(const pb::Source& pbSource, const android::ResStringPool& srcPool,
Source* outSource) {
if (pbSource.has_path_idx()) {
- outSource->path = util::getString8(srcPool, pbSource.path_idx()).toString();
+ outSource->path = util::getString(srcPool, pbSource.path_idx());
}
if (pbSource.has_line_no()) {
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
index a7798e7..98ff87f 100644
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ b/tools/aapt2/proto/TableProtoDeserializer.cpp
@@ -70,10 +70,9 @@
std::map<ResourceId, ResourceNameRef> idIndex;
- ResourceTablePackage* pkg = table->createPackage(
- util::utf8ToUtf16(pbPackage.package_name()), id);
+ ResourceTablePackage* pkg = table->createPackage(pbPackage.package_name(), id);
for (const pb::Type& pbType : pbPackage.types()) {
- const ResourceType* resType = parseResourceType(util::utf8ToUtf16(pbType.name()));
+ const ResourceType* resType = parseResourceType(pbType.name());
if (!resType) {
mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'");
return {};
@@ -82,7 +81,7 @@
ResourceTableType* type = pkg->findOrCreateType(*resType);
for (const pb::Entry& pbEntry : pbType.entries()) {
- ResourceEntry* entry = type->findOrCreateEntry(util::utf8ToUtf16(pbEntry.name()));
+ ResourceEntry* entry = type->findOrCreateEntry(pbEntry.name());
// Deserialize the symbol status (public/private with source and comments).
if (pbEntry.has_symbol_status()) {
@@ -93,7 +92,7 @@
}
if (pbStatus.has_comment()) {
- entry->symbolStatus.comment = util::utf8ToUtf16(pbStatus.comment());
+ entry->symbolStatus.comment = pbStatus.comment();
}
SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility());
@@ -179,14 +178,14 @@
} else if (pbItem.has_str()) {
const uint32_t idx = pbItem.str().idx();
- StringPiece16 str = util::getString(*mValuePool, idx);
+ const std::string str = util::getString(*mValuePool, idx);
const android::ResStringPool_span* spans = mValuePool->styleAt(idx);
if (spans && spans->name.index != android::ResStringPool_span::END) {
- StyleString styleStr = { str.toString() };
+ StyleString styleStr = { str };
while (spans->name.index != android::ResStringPool_span::END) {
styleStr.spans.push_back(Span{
- util::getString(*mValuePool, spans->name.index).toString(),
+ util::getString(*mValuePool, spans->name.index),
spans->firstChar,
spans->lastChar
});
@@ -200,13 +199,13 @@
} else if (pbItem.has_raw_str()) {
const uint32_t idx = pbItem.raw_str().idx();
- StringPiece16 str = util::getString(*mValuePool, idx);
+ const std::string str = util::getString(*mValuePool, idx);
return util::make_unique<RawString>(
pool->makeRef(str, StringPool::Context{ 1, config }));
} else if (pbItem.has_file()) {
const uint32_t idx = pbItem.file().path_idx();
- StringPiece16 str = util::getString(*mValuePool, idx);
+ const std::string str = util::getString(*mValuePool, idx);
return util::make_unique<FileReference>(
pool->makeRef(str, StringPool::Context{ 0, config }));
@@ -351,7 +350,7 @@
}
if (pbRef.has_symbol_idx()) {
- StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
+ const std::string strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
ResourceNameRef nameRef;
if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) {
mDiag->error(DiagMessage(mSource) << "invalid reference name '"
@@ -373,7 +372,7 @@
}
if (pbItem.has_comment()) {
- outValue->setComment(util::utf8ToUtf16(pbItem.comment()));
+ outValue->setComment(pbItem.comment());
}
}
@@ -446,8 +445,7 @@
ResourceNameRef nameRef;
// Need to create an lvalue here so that nameRef can point to something real.
- std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name());
- if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
+ if (!ResourceUtils::parseResourceName(pbFile.resource_name(), &nameRef)) {
diag->error(DiagMessage(source) << "invalid resource name in compiled file header: "
<< pbFile.resource_name());
return {};
@@ -458,8 +456,7 @@
for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) {
// Need to create an lvalue here so that nameRef can point to something real.
- utf16Name = util::utf8ToUtf16(pbSymbol.resource_name());
- if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
+ if (!ResourceUtils::parseResourceName(pbSymbol.resource_name(), &nameRef)) {
diag->error(DiagMessage(source) << "invalid resource name for exported symbol in "
"compiled file header: "
<< pbFile.resource_name());
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index 5d1b72b..425fca6 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -171,7 +171,7 @@
void serializeItemCommonToPb(const Item& item, T* pbItem) {
serializeSourceToPb(item.getSource(), mSourcePool, pbItem->mutable_source());
if (!item.getComment().empty()) {
- pbItem->set_comment(util::utf16ToUtf8(item.getComment()));
+ pbItem->set_comment(item.getComment());
}
}
@@ -220,28 +220,28 @@
if (package->id) {
pbPackage->set_package_id(package->id.value());
}
- pbPackage->set_package_name(util::utf16ToUtf8(package->name));
+ pbPackage->set_package_name(package->name);
for (auto& type : package->types) {
pb::Type* pbType = pbPackage->add_types();
if (type->id) {
pbType->set_id(type->id.value());
}
- pbType->set_name(util::utf16ToUtf8(toString(type->type)));
+ pbType->set_name(toString(type->type).toString());
for (auto& entry : type->entries) {
pb::Entry* pbEntry = pbType->add_entries();
if (entry->id) {
pbEntry->set_id(entry->id.value());
}
- pbEntry->set_name(util::utf16ToUtf8(entry->name));
+ pbEntry->set_name(entry->name);
// Write the SymbolStatus struct.
pb::SymbolStatus* pbStatus = pbEntry->mutable_symbol_status();
pbStatus->set_visibility(serializeVisibilityToPb(entry->symbolStatus.state));
serializeSourceToPb(entry->symbolStatus.source, &sourcePool,
pbStatus->mutable_source());
- pbStatus->set_comment(util::utf16ToUtf8(entry->symbolStatus.comment));
+ pbStatus->set_comment(entry->symbolStatus.comment);
for (auto& configValue : entry->values) {
pb::ConfigValue* pbConfigValue = pbEntry->add_config_values();
@@ -254,7 +254,7 @@
serializeSourceToPb(configValue->value->getSource(), &sourcePool,
pbValue->mutable_source());
if (!configValue->value->getComment().empty()) {
- pbValue->set_comment(util::utf16ToUtf8(configValue->value->getComment()));
+ pbValue->set_comment(configValue->value->getComment());
}
if (configValue->value->isWeak()) {
@@ -275,13 +275,13 @@
std::unique_ptr<pb::CompiledFile> serializeCompiledFileToPb(const ResourceFile& file) {
std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
- pbFile->set_resource_name(util::utf16ToUtf8(file.name.toString()));
+ pbFile->set_resource_name(file.name.toString());
pbFile->set_source_path(file.source.path);
serializeConfig(file.config, pbFile->mutable_config());
for (const SourcedResourceName& exported : file.exportedSymbols) {
pb::CompiledFile_Symbol* pbSymbol = pbFile->add_exported_symbols();
- pbSymbol->set_resource_name(util::utf16ToUtf8(exported.name.toString()));
+ pbSymbol->set_resource_name(exported.name.toString());
pbSymbol->set_line_no(exported.line);
}
return pbFile;
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
index dd995d8..78b32f7 100644
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp
@@ -16,49 +16,45 @@
#include "ResourceTable.h"
#include "proto/ProtoSerialize.h"
-#include "test/Builders.h"
-#include "test/Common.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
TEST(TableProtoSerializer, SerializeSinglePackage) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.a", 0x7f)
- .addFileReference(u"@com.app.a:layout/main", ResourceId(0x7f020000),
- u"res/layout/main.xml")
- .addReference(u"@com.app.a:layout/other", ResourceId(0x7f020001),
- u"@com.app.a:layout/main")
- .addString(u"@com.app.a:string/text", {}, u"hi")
- .addValue(u"@com.app.a:id/foo", {}, util::make_unique<Id>())
+ .setPackageId("com.app.a", 0x7f)
+ .addFileReference("@com.app.a:layout/main", ResourceId(0x7f020000),
+ "res/layout/main.xml")
+ .addReference("@com.app.a:layout/other", ResourceId(0x7f020001),
+ "@com.app.a:layout/main")
+ .addString("@com.app.a:string/text", {}, "hi")
+ .addValue("@com.app.a:id/foo", {}, util::make_unique<Id>())
.build();
Symbol publicSymbol;
publicSymbol.state = SymbolState::kPublic;
- ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@com.app.a:layout/main"),
+ ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie("@com.app.a:layout/main"),
ResourceId(0x7f020000),
publicSymbol, context->getDiagnostics()));
- Id* id = test::getValue<Id>(table.get(), u"@com.app.a:id/foo");
+ Id* id = test::getValue<Id>(table.get(), "@com.app.a:id/foo");
ASSERT_NE(nullptr, id);
// Make a plural.
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
- plural->values[Plural::One] = util::make_unique<String>(table->stringPool.makeRef(u"one"));
- ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:plurals/hey"),
- ConfigDescription{}, std::string(), std::move(plural),
+ plural->values[Plural::One] = util::make_unique<String>(table->stringPool.makeRef("one"));
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie("@com.app.a:plurals/hey"),
+ ConfigDescription{}, {}, std::move(plural),
context->getDiagnostics()));
// Make a resource with different products.
- ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:integer/one"),
- test::parseConfigOrDie("land"), std::string(),
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie("@com.app.a:integer/one"),
+ test::parseConfigOrDie("land"), {},
test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
context->getDiagnostics()));
- ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:integer/one"),
- test::parseConfigOrDie("land"), std::string("tablet"),
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie("@com.app.a:integer/one"),
+ test::parseConfigOrDie("land"), "tablet",
test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
context->getDiagnostics()));
@@ -66,10 +62,10 @@
// The reference should point to a resource outside of this table to test that both
// name and id get serialized.
Reference expectedRef;
- expectedRef.name = test::parseNameOrDie(u"@android:layout/main");
+ expectedRef.name = test::parseNameOrDie("@android:layout/main");
expectedRef.id = ResourceId(0x01020000);
- ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:layout/abc"),
- ConfigDescription::defaultConfig(), std::string(),
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie("@com.app.a:layout/abc"),
+ ConfigDescription::defaultConfig(), {},
util::make_unique<Reference>(expectedRef),
context->getDiagnostics()));
@@ -81,28 +77,28 @@
context->getDiagnostics());
ASSERT_NE(nullptr, newTable);
- Id* newId = test::getValue<Id>(newTable.get(), u"@com.app.a:id/foo");
+ Id* newId = test::getValue<Id>(newTable.get(), "@com.app.a:id/foo");
ASSERT_NE(nullptr, newId);
EXPECT_EQ(id->isWeak(), newId->isWeak());
Maybe<ResourceTable::SearchResult> result = newTable->findResource(
- test::parseNameOrDie(u"@com.app.a:layout/main"));
+ test::parseNameOrDie("@com.app.a:layout/main"));
AAPT_ASSERT_TRUE(result);
EXPECT_EQ(SymbolState::kPublic, result.value().type->symbolStatus.state);
EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state);
// Find the product-dependent values
BinaryPrimitive* prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
- newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "");
+ newTable.get(), "@com.app.a:integer/one", test::parseConfigOrDie("land"), "");
ASSERT_NE(nullptr, prim);
EXPECT_EQ(123u, prim->value.data);
prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
- newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
+ newTable.get(), "@com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
ASSERT_NE(nullptr, prim);
EXPECT_EQ(321u, prim->value.data);
- Reference* actualRef = test::getValue<Reference>(newTable.get(), u"@com.app.a:layout/abc");
+ Reference* actualRef = test::getValue<Reference>(newTable.get(), "@com.app.a:layout/abc");
ASSERT_NE(nullptr, actualRef);
AAPT_ASSERT_TRUE(actualRef->name);
AAPT_ASSERT_TRUE(actualRef->id);
@@ -115,9 +111,9 @@
ResourceFile f;
f.config = test::parseConfigOrDie("hdpi-v9");
- f.name = test::parseNameOrDie(u"@com.app.a:layout/main");
+ f.name = test::parseNameOrDie("@com.app.a:layout/main");
f.source.path = "res/layout-hdpi-v9/main.xml";
- f.exportedSymbols.push_back(SourcedResourceName{ test::parseNameOrDie(u"@+id/unchecked"), 23u });
+ f.exportedSymbols.push_back(SourcedResourceName{ test::parseNameOrDie("@+id/unchecked"), 23u });
const std::string expectedData = "1234";
@@ -136,7 +132,7 @@
const pb::CompiledFile* newPbFile = inFileStream.CompiledFile();
ASSERT_NE(nullptr, newPbFile);
- std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(*newPbFile, Source{ "test" },
+ std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(*newPbFile, Source("test"),
context->getDiagnostics());
ASSERT_NE(nullptr, file);
@@ -145,7 +141,7 @@
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(inFileStream.data()) & 0x03);
ASSERT_EQ(1u, file->exportedSymbols.size());
- EXPECT_EQ(test::parseNameOrDie(u"@+id/unchecked"), file->exportedSymbols[0].name);
+ EXPECT_EQ(test::parseNameOrDie("@+id/unchecked"), file->exportedSymbols[0].name);
}
TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
diff --git a/tools/aapt2/split/TableSplitter_test.cpp b/tools/aapt2/split/TableSplitter_test.cpp
index 2d013e4..a6dfd62 100644
--- a/tools/aapt2/split/TableSplitter_test.cpp
+++ b/tools/aapt2/split/TableSplitter_test.cpp
@@ -21,15 +21,15 @@
TEST(TableSplitterTest, NoSplitPreferredDensity) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .addFileReference(u"@android:drawable/icon", u"res/drawable-mdpi/icon.png",
+ .addFileReference("@android:drawable/icon", "res/drawable-mdpi/icon.png",
test::parseConfigOrDie("mdpi"))
- .addFileReference(u"@android:drawable/icon", u"res/drawable-hdpi/icon.png",
+ .addFileReference("@android:drawable/icon", "res/drawable-hdpi/icon.png",
test::parseConfigOrDie("hdpi"))
- .addFileReference(u"@android:drawable/icon", u"res/drawable-xhdpi/icon.png",
+ .addFileReference("@android:drawable/icon", "res/drawable-xhdpi/icon.png",
test::parseConfigOrDie("xhdpi"))
- .addFileReference(u"@android:drawable/icon", u"res/drawable-xxhdpi/icon.png",
+ .addFileReference("@android:drawable/icon", "res/drawable-xxhdpi/icon.png",
test::parseConfigOrDie("xxhdpi"))
- .addSimple(u"@android:string/one")
+ .addSimple("@android:string/one")
.build();
TableSplitterOptions options;
@@ -38,24 +38,24 @@
splitter.splitTable(table.get());
EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(table.get(),
- u"@android:drawable/icon",
+ "@android:drawable/icon",
test::parseConfigOrDie("mdpi")));
EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(table.get(),
- u"@android:drawable/icon",
+ "@android:drawable/icon",
test::parseConfigOrDie("hdpi")));
EXPECT_NE(nullptr, test::getValueForConfig<FileReference>(table.get(),
- u"@android:drawable/icon",
+ "@android:drawable/icon",
test::parseConfigOrDie("xhdpi")));
EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(table.get(),
- u"@android:drawable/icon",
+ "@android:drawable/icon",
test::parseConfigOrDie("xxhdpi")));
- EXPECT_NE(nullptr, test::getValue<Id>(table.get(), u"@android:string/one"));
+ EXPECT_NE(nullptr, test::getValue<Id>(table.get(), "@android:string/one"));
}
TEST(TableSplitterTest, SplitTableByConfigAndDensity) {
ResourceTable table;
- const ResourceName foo = test::parseNameOrDie(u"@android:string/foo");
+ const ResourceName foo = test::parseNameOrDie("@android:string/foo");
ASSERT_TRUE(table.addResource(foo, test::parseConfigOrDie("land-hdpi"), {},
util::make_unique<Id>(),
test::getDiagnostics()));
@@ -79,25 +79,25 @@
ResourceTable* splitTwo = splitter.getSplits()[1].get();
// Since a split was defined, all densities should be gone from base.
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, "@android:string/foo",
test::parseConfigOrDie("land-hdpi")));
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, "@android:string/foo",
test::parseConfigOrDie("land-xhdpi")));
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, "@android:string/foo",
test::parseConfigOrDie("land-xxhdpi")));
- EXPECT_NE(nullptr, test::getValueForConfig<Id>(splitOne, u"@android:string/foo",
+ EXPECT_NE(nullptr, test::getValueForConfig<Id>(splitOne, "@android:string/foo",
test::parseConfigOrDie("land-hdpi")));
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitOne, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitOne, "@android:string/foo",
test::parseConfigOrDie("land-xhdpi")));
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitOne, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitOne, "@android:string/foo",
test::parseConfigOrDie("land-xxhdpi")));
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitTwo, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitTwo, "@android:string/foo",
test::parseConfigOrDie("land-hdpi")));
- EXPECT_NE(nullptr, test::getValueForConfig<Id>(splitTwo, u"@android:string/foo",
+ EXPECT_NE(nullptr, test::getValueForConfig<Id>(splitTwo, "@android:string/foo",
test::parseConfigOrDie("land-xhdpi")));
- EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitTwo, u"@android:string/foo",
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitTwo, "@android:string/foo",
test::parseConfigOrDie("land-xxhdpi")));
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index fb1d8f8..c0c0160 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -40,81 +40,81 @@
return &mTable->stringPool;
}
- ResourceTableBuilder& setPackageId(const StringPiece16& packageName, uint8_t id) {
+ ResourceTableBuilder& setPackageId(const StringPiece& packageName, uint8_t id) {
ResourceTablePackage* package = mTable->createPackage(packageName, id);
assert(package);
return *this;
}
- ResourceTableBuilder& addSimple(const StringPiece16& name, const ResourceId id = {}) {
+ ResourceTableBuilder& addSimple(const StringPiece& name, const ResourceId id = {}) {
return addValue(name, id, util::make_unique<Id>());
}
- ResourceTableBuilder& addSimple(const StringPiece16& name, const ConfigDescription& config,
+ ResourceTableBuilder& addSimple(const StringPiece& name, const ConfigDescription& config,
const ResourceId id = {}) {
return addValue(name, config, id, util::make_unique<Id>());
}
- ResourceTableBuilder& addReference(const StringPiece16& name, const StringPiece16& ref) {
+ ResourceTableBuilder& addReference(const StringPiece& name, const StringPiece& ref) {
return addReference(name, {}, ref);
}
- ResourceTableBuilder& addReference(const StringPiece16& name, const ResourceId id,
- const StringPiece16& ref) {
+ ResourceTableBuilder& addReference(const StringPiece& name, const ResourceId id,
+ const StringPiece& ref) {
return addValue(name, id, util::make_unique<Reference>(parseNameOrDie(ref)));
}
- ResourceTableBuilder& addString(const StringPiece16& name, const StringPiece16& str) {
+ ResourceTableBuilder& addString(const StringPiece& name, const StringPiece& str) {
return addString(name, {}, str);
}
- ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id,
- const StringPiece16& str) {
+ ResourceTableBuilder& addString(const StringPiece& name, const ResourceId id,
+ const StringPiece& str) {
return addValue(name, id, util::make_unique<String>(mTable->stringPool.makeRef(str)));
}
- ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id,
- const ConfigDescription& config, const StringPiece16& str) {
+ ResourceTableBuilder& addString(const StringPiece& name, const ResourceId id,
+ const ConfigDescription& config, const StringPiece& str) {
return addValue(name, config, id,
util::make_unique<String>(mTable->stringPool.makeRef(str)));
}
- ResourceTableBuilder& addFileReference(const StringPiece16& name, const StringPiece16& path) {
+ ResourceTableBuilder& addFileReference(const StringPiece& name, const StringPiece& path) {
return addFileReference(name, {}, path);
}
- ResourceTableBuilder& addFileReference(const StringPiece16& name, const ResourceId id,
- const StringPiece16& path) {
+ ResourceTableBuilder& addFileReference(const StringPiece& name, const ResourceId id,
+ const StringPiece& path) {
return addValue(name, id,
util::make_unique<FileReference>(mTable->stringPool.makeRef(path)));
}
- ResourceTableBuilder& addFileReference(const StringPiece16& name, const StringPiece16& path,
+ ResourceTableBuilder& addFileReference(const StringPiece& name, const StringPiece& path,
const ConfigDescription& config) {
return addValue(name, config, {},
util::make_unique<FileReference>(mTable->stringPool.makeRef(path)));
}
- ResourceTableBuilder& addValue(const StringPiece16& name,
+ ResourceTableBuilder& addValue(const StringPiece& name,
std::unique_ptr<Value> value) {
return addValue(name, {}, std::move(value));
}
- ResourceTableBuilder& addValue(const StringPiece16& name, const ResourceId id,
+ ResourceTableBuilder& addValue(const StringPiece& name, const ResourceId id,
std::unique_ptr<Value> value) {
return addValue(name, {}, id, std::move(value));
}
- ResourceTableBuilder& addValue(const StringPiece16& name, const ConfigDescription& config,
+ ResourceTableBuilder& addValue(const StringPiece& name, const ConfigDescription& config,
const ResourceId id, std::unique_ptr<Value> value) {
ResourceName resName = parseNameOrDie(name);
- bool result = mTable->addResourceAllowMangled(resName, id, config, std::string(),
+ bool result = mTable->addResourceAllowMangled(resName, id, config, {},
std::move(value), &mDiagnostics);
assert(result);
return *this;
}
- ResourceTableBuilder& setSymbolState(const StringPiece16& name, ResourceId id,
+ ResourceTableBuilder& setSymbolState(const StringPiece& name, ResourceId id,
SymbolState state) {
ResourceName resName = parseNameOrDie(name);
Symbol symbol;
@@ -129,7 +129,7 @@
}
};
-inline std::unique_ptr<Reference> buildReference(const StringPiece16& ref,
+inline std::unique_ptr<Reference> buildReference(const StringPiece& ref,
Maybe<ResourceId> id = {}) {
std::unique_ptr<Reference> reference = util::make_unique<Reference>(parseNameOrDie(ref));
reference->id = id;
@@ -160,7 +160,7 @@
return *this;
}
- ValueBuilder& setComment(const StringPiece16& str) {
+ ValueBuilder& setComment(const StringPiece& str) {
mValue->setComment(str);
return *this;
}
@@ -184,9 +184,9 @@
return *this;
}
- AttributeBuilder& addItem(const StringPiece16& name, uint32_t value) {
+ AttributeBuilder& addItem(const StringPiece& name, uint32_t value) {
mAttr->symbols.push_back(Attribute::Symbol{
- Reference(ResourceName{ {}, ResourceType::kId, name.toString()}),
+ Reference(ResourceName({}, ResourceType::kId, name)),
value});
return *this;
}
@@ -201,17 +201,17 @@
std::unique_ptr<Style> mStyle = util::make_unique<Style>();
public:
- StyleBuilder& setParent(const StringPiece16& str) {
+ StyleBuilder& setParent(const StringPiece& str) {
mStyle->parent = Reference(parseNameOrDie(str));
return *this;
}
- StyleBuilder& addItem(const StringPiece16& str, std::unique_ptr<Item> value) {
+ StyleBuilder& addItem(const StringPiece& str, std::unique_ptr<Item> value) {
mStyle->entries.push_back(Style::Entry{ Reference(parseNameOrDie(str)), std::move(value) });
return *this;
}
- StyleBuilder& addItem(const StringPiece16& str, ResourceId id, std::unique_ptr<Item> value) {
+ StyleBuilder& addItem(const StringPiece& str, ResourceId id, std::unique_ptr<Item> value) {
addItem(str, std::move(value));
mStyle->entries.back().key.id = id;
return *this;
@@ -227,7 +227,7 @@
std::unique_ptr<Styleable> mStyleable = util::make_unique<Styleable>();
public:
- StyleableBuilder& addItem(const StringPiece16& str, Maybe<ResourceId> id = {}) {
+ StyleableBuilder& addItem(const StringPiece& str, Maybe<ResourceId> id = {}) {
mStyleable->entries.push_back(Reference(parseNameOrDie(str)));
mStyleable->entries.back().id = id;
return *this;
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index faccd477..b2eaba6 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -62,7 +62,7 @@
return &diag;
}
-inline ResourceName parseNameOrDie(const StringPiece16& str) {
+inline ResourceName parseNameOrDie(const StringPiece& str) {
ResourceNameRef ref;
bool result = ResourceUtils::tryParseReference(str, &ref);
assert(result && "invalid resource name");
@@ -77,7 +77,7 @@
}
template <typename T> T* getValueForConfigAndProduct(ResourceTable* table,
- const StringPiece16& resName,
+ const StringPiece& resName,
const ConfigDescription& config,
const StringPiece& product) {
Maybe<ResourceTable::SearchResult> result = table->findResource(parseNameOrDie(resName));
@@ -90,12 +90,12 @@
return nullptr;
}
-template <typename T> T* getValueForConfig(ResourceTable* table, const StringPiece16& resName,
+template <typename T> T* getValueForConfig(ResourceTable* table, const StringPiece& resName,
const ConfigDescription& config) {
return getValueForConfigAndProduct<T>(table, resName, config, {});
}
-template <typename T> T* getValue(ResourceTable* table, const StringPiece16& resName) {
+template <typename T> T* getValue(ResourceTable* table, const StringPiece& resName) {
return getValueForConfig<T>(table, resName, {});
}
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 36f568b..b053e07 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -19,7 +19,6 @@
#include "NameMangler.h"
#include "util/Util.h"
-
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
#include "test/Common.h"
@@ -40,7 +39,7 @@
return &mDiagnostics;
}
- const std::u16string& getCompilationPackage() override {
+ const std::string& getCompilationPackage() override {
assert(mCompilationPackage && "package name not set");
return mCompilationPackage.value();
}
@@ -65,7 +64,7 @@
private:
friend class ContextBuilder;
- Maybe<std::u16string> mCompilationPackage;
+ Maybe<std::string> mCompilationPackage;
Maybe<uint8_t> mPackageId;
StdErrDiagnostics mDiagnostics;
SymbolTable mSymbols;
@@ -78,7 +77,7 @@
std::unique_ptr<Context> mContext = std::unique_ptr<Context>(new Context());
public:
- ContextBuilder& setCompilationPackage(const StringPiece16& package) {
+ ContextBuilder& setCompilationPackage(const StringPiece& package) {
mContext->mCompilationPackage = package.toString();
return *this;
}
@@ -110,7 +109,7 @@
class StaticSymbolSourceBuilder {
public:
- StaticSymbolSourceBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
+ StaticSymbolSourceBuilder& addPublicSymbol(const StringPiece& name, ResourceId id,
std::unique_ptr<Attribute> attr = {}) {
std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
id, std::move(attr), true);
@@ -120,7 +119,7 @@
return *this;
}
- StaticSymbolSourceBuilder& addSymbol(const StringPiece16& name, ResourceId id,
+ StaticSymbolSourceBuilder& addSymbol(const StringPiece& name, ResourceId id,
std::unique_ptr<Attribute> attr = {}) {
std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
id, std::move(attr), false);
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index d2eccbc..4fd77c8 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -178,7 +178,8 @@
packageName[i] = util::deviceToHost16(packageHeader->name[i]);
}
- ResourceTablePackage* package = mTable->createPackage(packageName, (uint8_t) packageId);
+ ResourceTablePackage* package = mTable->createPackage(util::utf16ToUtf8(packageName),
+ static_cast<uint8_t>(packageId));
if (!package) {
mContext->getDiagnostics()->error(DiagMessage(mSource)
<< "incompatible package '" << packageName
@@ -308,12 +309,12 @@
ConfigDescription config;
config.copyFromDtoH(type->config);
- StringPiece16 typeStr16 = util::getString(mTypePool, type->id - 1);
+ const std::string typeStr = util::getString(mTypePool, type->id - 1);
- const ResourceType* parsedType = parseResourceType(typeStr16);
+ const ResourceType* parsedType = parseResourceType(typeStr);
if (!parsedType) {
mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "invalid type name '" << typeStr16
+ << "invalid type name '" << typeStr
<< "' for type with ID " << (int) type->id);
return false;
}
@@ -327,7 +328,7 @@
const ResourceName name(package->name, *parsedType,
util::getString(mKeyPool,
- util::deviceToHost32(entry->key.index)).toString());
+ util::deviceToHost32(entry->key.index)));
const ResourceId resId(package->id.value(), type->id, static_cast<uint16_t>(it.index()));
@@ -387,16 +388,16 @@
const uint32_t data = util::deviceToHost32(value->data);
if (value->dataType == Res_value::TYPE_STRING) {
- StringPiece16 str = util::getString(mValuePool, data);
+ const std::string str = util::getString(mValuePool, data);
const ResStringPool_span* spans = mValuePool.styleAt(data);
// Check if the string has a valid style associated with it.
if (spans != nullptr && spans->name.index != ResStringPool_span::END) {
- StyleString styleStr = { str.toString() };
+ StyleString styleStr = { str };
while (spans->name.index != ResStringPool_span::END) {
styleStr.spans.push_back(Span{
- util::getString(mValuePool, spans->name.index).toString(),
+ util::getString(mValuePool, spans->name.index),
spans->firstChar,
spans->lastChar
});
@@ -406,7 +407,7 @@
styleStr, StringPool::Context{1, config}));
} else {
if (name.type != ResourceType::kString &&
- util::stringStartsWith<char16_t>(str, u"res/")) {
+ util::stringStartsWith(str, "res/")) {
// This must be a FileReference.
return util::make_unique<FileReference>(mTable->stringPool.makeRef(
str, StringPool::Context{ 0, config }));
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index f5e49f1..c9b3811 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -157,7 +157,7 @@
std::string packageToPath(const StringPiece& package) {
std::string outPath;
- for (StringPiece part : util::tokenize<char>(package, '.')) {
+ for (StringPiece part : util::tokenize(package, '.')) {
appendPath(&outPath, part);
}
return outPath;
@@ -199,7 +199,7 @@
return false;
}
- for (StringPiece line : util::tokenize<char>(contents, ' ')) {
+ for (StringPiece line : util::tokenize(contents, ' ')) {
line = util::trimWhitespace(line);
if (!line.empty()) {
outArgList->push_back(line.toString());
diff --git a/tools/aapt2/util/StringPiece_test.cpp b/tools/aapt2/util/StringPiece_test.cpp
index 853a9a4..a87065a 100644
--- a/tools/aapt2/util/StringPiece_test.cpp
+++ b/tools/aapt2/util/StringPiece_test.cpp
@@ -34,16 +34,16 @@
}
TEST(StringPieceTest, PiecesHaveCorrectSortOrder) {
- std::u16string testing(u"testing");
- std::u16string banana(u"banana");
- std::u16string car(u"car");
+ std::string testing("testing");
+ std::string banana("banana");
+ std::string car("car");
- EXPECT_TRUE(StringPiece16(testing) > banana);
- EXPECT_TRUE(StringPiece16(testing) > car);
- EXPECT_TRUE(StringPiece16(banana) < testing);
- EXPECT_TRUE(StringPiece16(banana) < car);
- EXPECT_TRUE(StringPiece16(car) < testing);
- EXPECT_TRUE(StringPiece16(car) > banana);
+ EXPECT_TRUE(StringPiece(testing) > banana);
+ EXPECT_TRUE(StringPiece(testing) > car);
+ EXPECT_TRUE(StringPiece(banana) < testing);
+ EXPECT_TRUE(StringPiece(banana) < car);
+ EXPECT_TRUE(StringPiece(car) < testing);
+ EXPECT_TRUE(StringPiece(car) > banana);
}
TEST(StringPieceTest, PiecesHaveCorrectSortOrderUtf8) {
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index c41eb05..3c0e9bde 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -54,23 +54,18 @@
return splitAndTransform(str, sep, ::tolower);
}
-StringPiece16 trimWhitespace(const StringPiece16& str) {
- if (str.size() == 0 || str.data() == nullptr) {
- return str;
+bool stringStartsWith(const StringPiece& str, const StringPiece& prefix) {
+ if (str.size() < prefix.size()) {
+ return false;
}
+ return str.substr(0, prefix.size()) == prefix;
+}
- const char16_t* start = str.data();
- const char16_t* end = str.data() + str.length();
-
- while (start != end && util::isspace16(*start)) {
- start++;
+bool stringEndsWith(const StringPiece& str, const StringPiece& suffix) {
+ if (str.size() < suffix.size()) {
+ return false;
}
-
- while (end != start && util::isspace16(*(end - 1))) {
- end--;
- }
-
- return StringPiece16(start, end - start);
+ return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
}
StringPiece trimWhitespace(const StringPiece& str) {
@@ -92,11 +87,11 @@
return StringPiece(start, end - start);
}
-StringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str,
- const StringPiece16& allowedChars) {
+StringPiece::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece& str,
+ const StringPiece& allowedChars) {
const auto endIter = str.end();
for (auto iter = str.begin(); iter != endIter; ++iter) {
- char16_t c = *iter;
+ char c = *iter;
if ((c >= u'a' && c <= u'z') ||
(c >= u'A' && c <= u'Z') ||
(c >= u'0' && c <= u'9')) {
@@ -104,7 +99,7 @@
}
bool match = false;
- for (char16_t i : allowedChars) {
+ for (char i : allowedChars) {
if (c == i) {
match = true;
break;
@@ -118,51 +113,51 @@
return endIter;
}
-bool isJavaClassName(const StringPiece16& str) {
+bool isJavaClassName(const StringPiece& str) {
size_t pieces = 0;
- for (const StringPiece16& piece : tokenize(str, u'.')) {
+ for (const StringPiece& piece : tokenize(str, '.')) {
pieces++;
if (piece.empty()) {
return false;
}
// Can't have starting or trailing $ character.
- if (piece.data()[0] == u'$' || piece.data()[piece.size() - 1] == u'$') {
+ if (piece.data()[0] == '$' || piece.data()[piece.size() - 1] == '$') {
return false;
}
- if (findNonAlphaNumericAndNotInSet(piece, u"$_") != piece.end()) {
+ if (findNonAlphaNumericAndNotInSet(piece, "$_") != piece.end()) {
return false;
}
}
return pieces >= 2;
}
-bool isJavaPackageName(const StringPiece16& str) {
+bool isJavaPackageName(const StringPiece& str) {
if (str.empty()) {
return false;
}
size_t pieces = 0;
- for (const StringPiece16& piece : tokenize(str, u'.')) {
+ for (const StringPiece& piece : tokenize(str, '.')) {
pieces++;
if (piece.empty()) {
return false;
}
- if (piece.data()[0] == u'_' || piece.data()[piece.size() - 1] == u'_') {
+ if (piece.data()[0] == '_' || piece.data()[piece.size() - 1] == '_') {
return false;
}
- if (findNonAlphaNumericAndNotInSet(piece, u"_") != piece.end()) {
+ if (findNonAlphaNumericAndNotInSet(piece, "_") != piece.end()) {
return false;
}
}
return pieces >= 1;
}
-Maybe<std::u16string> getFullyQualifiedClassName(const StringPiece16& package,
- const StringPiece16& className) {
+Maybe<std::string> getFullyQualifiedClassName(const StringPiece& package,
+ const StringPiece& className) {
if (className.empty()) {
return {};
}
@@ -175,9 +170,9 @@
return {};
}
- std::u16string result(package.data(), package.size());
- if (className.data()[0] != u'.') {
- result += u'.';
+ std::string result(package.data(), package.size());
+ if (className.data()[0] != '.') {
+ result += '.';
}
result.append(className.data(), className.size());
@@ -187,23 +182,23 @@
return result;
}
-static size_t consumeDigits(const char16_t* start, const char16_t* end) {
- const char16_t* c = start;
- for (; c != end && *c >= u'0' && *c <= u'9'; c++) {}
+static size_t consumeDigits(const char* start, const char* end) {
+ const char* c = start;
+ for (; c != end && *c >= '0' && *c <= '9'; c++) {}
return static_cast<size_t>(c - start);
}
-bool verifyJavaStringFormat(const StringPiece16& str) {
- const char16_t* c = str.begin();
- const char16_t* const end = str.end();
+bool verifyJavaStringFormat(const StringPiece& str) {
+ const char* c = str.begin();
+ const char* const end = str.end();
size_t argCount = 0;
bool nonpositional = false;
while (c != end) {
- if (*c == u'%' && c + 1 < end) {
+ if (*c == '%' && c + 1 < end) {
c++;
- if (*c == u'%') {
+ if (*c == '%') {
c++;
continue;
}
@@ -213,11 +208,11 @@
size_t numDigits = consumeDigits(c, end);
if (numDigits > 0) {
c += numDigits;
- if (c != end && *c != u'$') {
+ if (c != end && *c != '$') {
// The digits were a size, but not a positional argument.
nonpositional = true;
}
- } else if (*c == u'<') {
+ } else if (*c == '<') {
// Reusing last argument, bad idea since positions can be moved around
// during translation.
nonpositional = true;
@@ -225,7 +220,7 @@
c++;
// Optionally we can have a $ after
- if (c != end && *c == u'$') {
+ if (c != end && *c == '$') {
c++;
}
} else {
@@ -233,13 +228,13 @@
}
// Ignore size, width, flags, etc.
- while (c != end && (*c == u'-' ||
- *c == u'#' ||
- *c == u'+' ||
- *c == u' ' ||
- *c == u',' ||
- *c == u'(' ||
- (*c >= u'0' && *c <= '9'))) {
+ while (c != end && (*c == '-' ||
+ *c == '#' ||
+ *c == '+' ||
+ *c == ' ' ||
+ *c == ',' ||
+ *c == '(' ||
+ (*c >= '0' && *c <= '9'))) {
c++;
}
@@ -286,11 +281,11 @@
return true;
}
-static Maybe<char16_t> parseUnicodeCodepoint(const char16_t** start, const char16_t* end) {
- char16_t code = 0;
+static Maybe<std::string> parseUnicodeCodepoint(const char** start, const char* end) {
+ char32_t code = 0;
for (size_t i = 0; i < 4 && *start != end; i++, (*start)++) {
- char16_t c = **start;
- int a;
+ char c = **start;
+ char32_t a;
if (c >= '0' && c <= '9') {
a = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -298,51 +293,60 @@
} else if (c >= 'A' && c <= 'F') {
a = c - 'A' + 10;
} else {
- return make_nothing<char16_t>();
+ return {};
}
code = (code << 4) | a;
}
- return make_value(code);
+
+ ssize_t len = utf32_to_utf8_length(&code, 1);
+ if (len < 0) {
+ return {};
+ }
+
+ std::string resultUtf8;
+ resultUtf8.resize(len);
+ utf32_to_utf8(&code, 1, &*resultUtf8.begin(), len + 1);
+ return resultUtf8;
}
-StringBuilder& StringBuilder::append(const StringPiece16& str) {
+StringBuilder& StringBuilder::append(const StringPiece& str) {
if (!mError.empty()) {
return *this;
}
- const char16_t* const end = str.end();
- const char16_t* start = str.begin();
- const char16_t* current = start;
+ const char* const end = str.end();
+ const char* start = str.begin();
+ const char* current = start;
while (current != end) {
if (mLastCharWasEscape) {
switch (*current) {
- case u't':
- mStr += u'\t';
+ case 't':
+ mStr += '\t';
break;
- case u'n':
- mStr += u'\n';
+ case 'n':
+ mStr += '\n';
break;
- case u'#':
- mStr += u'#';
+ case '#':
+ mStr += '#';
break;
- case u'@':
- mStr += u'@';
+ case '@':
+ mStr += '@';
break;
- case u'?':
- mStr += u'?';
+ case '?':
+ mStr += '?';
break;
- case u'"':
- mStr += u'"';
+ case '"':
+ mStr += '"';
break;
- case u'\'':
- mStr += u'\'';
+ case '\'':
+ mStr += '\'';
break;
- case u'\\':
- mStr += u'\\';
+ case '\\':
+ mStr += '\\';
break;
- case u'u': {
+ case 'u': {
current++;
- Maybe<char16_t> c = parseUnicodeCodepoint(¤t, end);
+ Maybe<std::string> c = parseUnicodeCodepoint(¤t, end);
if (!c) {
mError = "invalid unicode escape sequence";
return *this;
@@ -358,7 +362,7 @@
}
mLastCharWasEscape = false;
start = current + 1;
- } else if (*current == u'"') {
+ } else if (*current == '"') {
if (!mQuote && mTrailingSpace) {
// We found an opening quote, and we have
// trailing space, so we should append that
@@ -367,7 +371,7 @@
// We had trailing whitespace, so
// replace with a single space.
if (!mStr.empty()) {
- mStr += u' ';
+ mStr += ' ';
}
mTrailingSpace = false;
}
@@ -375,17 +379,17 @@
mQuote = !mQuote;
mStr.append(start, current - start);
start = current + 1;
- } else if (*current == u'\'' && !mQuote) {
+ } else if (*current == '\'' && !mQuote) {
// This should be escaped.
mError = "unescaped apostrophe";
return *this;
- } else if (*current == u'\\') {
+ } else if (*current == '\\') {
// This is an escape sequence, convert to the real value.
if (!mQuote && mTrailingSpace) {
// We had trailing whitespace, so
// replace with a single space.
if (!mStr.empty()) {
- mStr += u' ';
+ mStr += ' ';
}
mTrailingSpace = false;
}
@@ -394,7 +398,7 @@
mLastCharWasEscape = true;
} else if (!mQuote) {
// This is not quoted text, so look for whitespace.
- if (isspace16(*current)) {
+ if (isspace(*current)) {
// We found whitespace, see if we have seen some
// before.
if (!mTrailingSpace) {
@@ -410,7 +414,7 @@
// We saw trailing space before, so replace all
// that trailing space with one space.
if (!mStr.empty()) {
- mStr += u' ';
+ mStr += ' ';
}
mTrailingSpace = false;
}
@@ -441,10 +445,8 @@
}
std::string utf8;
- // Make room for '\0' explicitly.
- utf8.resize(utf8Length + 1);
- utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin(), utf8Length + 1);
utf8.resize(utf8Length);
+ utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin(), utf8Length + 1);
return utf8;
}
@@ -467,15 +469,58 @@
return data;
}
-bool extractResFilePathParts(const StringPiece16& path, StringPiece16* outPrefix,
- StringPiece16* outEntry, StringPiece16* outSuffix) {
- if (!stringStartsWith<char16_t>(path, u"res/")) {
+typename Tokenizer::iterator& Tokenizer::iterator::operator++() {
+ const char* start = mToken.end();
+ const char* end = mStr.end();
+ if (start == end) {
+ mEnd = true;
+ mToken.assign(mToken.end(), 0);
+ return *this;
+ }
+
+ start += 1;
+ const char* current = start;
+ while (current != end) {
+ if (*current == mSeparator) {
+ mToken.assign(start, current - start);
+ return *this;
+ }
+ ++current;
+ }
+ mToken.assign(start, end - start);
+ return *this;
+}
+
+bool Tokenizer::iterator::operator==(const iterator& rhs) const {
+ // We check equality here a bit differently.
+ // We need to know that the addresses are the same.
+ return mToken.begin() == rhs.mToken.begin() && mToken.end() == rhs.mToken.end() &&
+ mEnd == rhs.mEnd;
+}
+
+bool Tokenizer::iterator::operator!=(const iterator& rhs) const {
+ return !(*this == rhs);
+}
+
+Tokenizer::iterator::iterator(StringPiece s, char sep, StringPiece tok, bool end) :
+ mStr(s), mSeparator(sep), mToken(tok), mEnd(end) {
+}
+
+Tokenizer::Tokenizer(StringPiece str, char sep) :
+ mBegin(++iterator(str, sep, StringPiece(str.begin() - 1, 0), false)),
+ mEnd(str, sep, StringPiece(str.end(), 0), true) {
+}
+
+bool extractResFilePathParts(const StringPiece& path, StringPiece* outPrefix,
+ StringPiece* outEntry, StringPiece* outSuffix) {
+ const StringPiece resPrefix("res/");
+ if (!stringStartsWith(path, resPrefix)) {
return false;
}
- StringPiece16::const_iterator lastOccurence = path.end();
- for (auto iter = path.begin() + StringPiece16(u"res/").size(); iter != path.end(); ++iter) {
- if (*iter == u'/') {
+ StringPiece::const_iterator lastOccurence = path.end();
+ for (auto iter = path.begin() + resPrefix.size(); iter != path.end(); ++iter) {
+ if (*iter == '/') {
lastOccurence = iter;
}
}
@@ -484,12 +529,30 @@
return false;
}
- auto iter = std::find(lastOccurence, path.end(), u'.');
- *outSuffix = StringPiece16(iter, path.end() - iter);
- *outEntry = StringPiece16(lastOccurence + 1, iter - lastOccurence - 1);
- *outPrefix = StringPiece16(path.begin(), lastOccurence - path.begin() + 1);
+ auto iter = std::find(lastOccurence, path.end(), '.');
+ *outSuffix = StringPiece(iter, path.end() - iter);
+ *outEntry = StringPiece(lastOccurence + 1, iter - lastOccurence - 1);
+ *outPrefix = StringPiece(path.begin(), lastOccurence - path.begin() + 1);
return true;
}
+StringPiece16 getString16(const android::ResStringPool& pool, size_t idx) {
+ size_t len;
+ const char16_t* str = pool.stringAt(idx, &len);
+ if (str != nullptr) {
+ return StringPiece16(str, len);
+ }
+ return StringPiece16();
+}
+
+std::string getString(const android::ResStringPool& pool, size_t idx) {
+ size_t len;
+ const char* str = pool.string8At(idx, &len);
+ if (str != nullptr) {
+ return std::string(str, len);
+ }
+ return utf16ToUtf8(getString16(pool, idx));
+}
+
} // namespace util
} // namespace aapt
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 0dacbd7..4a10987 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -37,30 +37,18 @@
/**
* Returns true if the string starts with prefix.
*/
-template <typename T>
-bool stringStartsWith(const BasicStringPiece<T>& str, const BasicStringPiece<T>& prefix) {
- if (str.size() < prefix.size()) {
- return false;
- }
- return str.substr(0, prefix.size()) == prefix;
-}
+bool stringStartsWith(const StringPiece& str, const StringPiece& prefix);
/**
* Returns true if the string ends with suffix.
*/
-template <typename T>
-bool stringEndsWith(const BasicStringPiece<T>& str, const BasicStringPiece<T>& suffix) {
- if (str.size() < suffix.size()) {
- return false;
- }
- return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
-}
+bool stringEndsWith(const StringPiece& str, const StringPiece& suffix);
/**
* Creates a new StringPiece16 that points to a substring
* of the original string without leading or trailing whitespace.
*/
-StringPiece16 trimWhitespace(const StringPiece16& str);
+StringPiece trimWhitespace(const StringPiece& str);
StringPiece trimWhitespace(const StringPiece& str);
@@ -76,18 +64,18 @@
* Returns an iterator to the first character that is not alpha-numeric and that
* is not in the allowedChars set.
*/
-StringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str,
- const StringPiece16& allowedChars);
+StringPiece::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece& str,
+ const StringPiece& allowedChars);
/**
* Tests that the string is a valid Java class name.
*/
-bool isJavaClassName(const StringPiece16& str);
+bool isJavaClassName(const StringPiece& str);
/**
* Tests that the string is a valid Java package name.
*/
-bool isJavaPackageName(const StringPiece16& str);
+bool isJavaPackageName(const StringPiece& str);
/**
* Converts the class name to a fully qualified class name from the given `package`. Ex:
@@ -97,9 +85,8 @@
* .a.b --> package.a.b
* asdf.adsf --> asdf.adsf
*/
-Maybe<std::u16string> getFullyQualifiedClassName(const StringPiece16& package,
- const StringPiece16& className);
-
+Maybe<std::string> getFullyQualifiedClassName(const StringPiece& package,
+ const StringPiece& className);
/**
* Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
@@ -147,25 +134,17 @@
}
/**
- * Helper method to extract a string from a StringPool.
+ * Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
+ * the conversion to UTF-16 happens within ResStringPool.
*/
-inline StringPiece16 getString(const android::ResStringPool& pool, size_t idx) {
- size_t len;
- const char16_t* str = pool.stringAt(idx, &len);
- if (str != nullptr) {
- return StringPiece16(str, len);
- }
- return StringPiece16();
-}
+StringPiece16 getString16(const android::ResStringPool& pool, size_t idx);
-inline StringPiece getString8(const android::ResStringPool& pool, size_t idx) {
- size_t len;
- const char* str = pool.string8At(idx, &len);
- if (str != nullptr) {
- return StringPiece(str, len);
- }
- return StringPiece();
-}
+/**
+ * Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
+ * the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
+ * which maintains no state or cache. This means we must return an std::string copy.
+ */
+std::string getString(const android::ResStringPool& pool, size_t idx);
/**
* Checks that the Java string format contains no non-positional arguments (arguments without
@@ -173,24 +152,24 @@
* because translations may rearrange the order of the arguments in the string, which will
* break the string interpolation.
*/
-bool verifyJavaStringFormat(const StringPiece16& str);
+bool verifyJavaStringFormat(const StringPiece& str);
class StringBuilder {
public:
- StringBuilder& append(const StringPiece16& str);
- const std::u16string& str() const;
+ StringBuilder& append(const StringPiece& str);
+ const std::string& str() const;
const std::string& error() const;
operator bool() const;
private:
- std::u16string mStr;
+ std::string mStr;
bool mQuote = false;
bool mTrailingSpace = false;
bool mLastCharWasEscape = false;
std::string mError;
};
-inline const std::u16string& StringBuilder::str() const {
+inline const std::string& StringBuilder::str() const {
return mStr;
}
@@ -206,7 +185,7 @@
* Converts a UTF8 string to a UTF16 string.
*/
std::u16string utf8ToUtf16(const StringPiece& utf8);
-std::string utf16ToUtf8(const StringPiece16& utf8);
+std::string utf16ToUtf8(const StringPiece16& utf16);
/**
* Writes the entire BigBuffer to the output stream.
@@ -222,7 +201,6 @@
* A Tokenizer implemented as an iterable collection. It does not allocate
* any memory on the heap nor use standard containers.
*/
-template <typename Char>
class Tokenizer {
public:
class iterator {
@@ -231,96 +209,41 @@
iterator& operator=(const iterator&) = default;
iterator& operator++();
- BasicStringPiece<Char> operator*();
+
+ StringPiece operator*() {
+ return mToken;
+ }
bool operator==(const iterator& rhs) const;
bool operator!=(const iterator& rhs) const;
private:
- friend class Tokenizer<Char>;
+ friend class Tokenizer;
- iterator(BasicStringPiece<Char> s, Char sep, BasicStringPiece<Char> tok, bool end);
+ iterator(StringPiece s, char sep, StringPiece tok, bool end);
- BasicStringPiece<Char> mStr;
- Char mSeparator;
- BasicStringPiece<Char> mToken;
+ StringPiece mStr;
+ char mSeparator;
+ StringPiece mToken;
bool mEnd;
};
- Tokenizer(BasicStringPiece<Char> str, Char sep);
- iterator begin();
- iterator end();
+ Tokenizer(StringPiece str, char sep);
+
+ iterator begin() {
+ return mBegin;
+ }
+
+ iterator end() {
+ return mEnd;
+ }
private:
const iterator mBegin;
const iterator mEnd;
};
-template <typename Char>
-inline Tokenizer<Char> tokenize(BasicStringPiece<Char> str, Char sep) {
- return Tokenizer<Char>(str, sep);
-}
-
-template <typename Char>
-typename Tokenizer<Char>::iterator& Tokenizer<Char>::iterator::operator++() {
- const Char* start = mToken.end();
- const Char* end = mStr.end();
- if (start == end) {
- mEnd = true;
- mToken.assign(mToken.end(), 0);
- return *this;
- }
-
- start += 1;
- const Char* current = start;
- while (current != end) {
- if (*current == mSeparator) {
- mToken.assign(start, current - start);
- return *this;
- }
- ++current;
- }
- mToken.assign(start, end - start);
- return *this;
-}
-
-template <typename Char>
-inline BasicStringPiece<Char> Tokenizer<Char>::iterator::operator*() {
- return mToken;
-}
-
-template <typename Char>
-inline bool Tokenizer<Char>::iterator::operator==(const iterator& rhs) const {
- // We check equality here a bit differently.
- // We need to know that the addresses are the same.
- return mToken.begin() == rhs.mToken.begin() && mToken.end() == rhs.mToken.end() &&
- mEnd == rhs.mEnd;
-}
-
-template <typename Char>
-inline bool Tokenizer<Char>::iterator::operator!=(const iterator& rhs) const {
- return !(*this == rhs);
-}
-
-template <typename Char>
-inline Tokenizer<Char>::iterator::iterator(BasicStringPiece<Char> s, Char sep,
- BasicStringPiece<Char> tok, bool end) :
- mStr(s), mSeparator(sep), mToken(tok), mEnd(end) {
-}
-
-template <typename Char>
-inline typename Tokenizer<Char>::iterator Tokenizer<Char>::begin() {
- return mBegin;
-}
-
-template <typename Char>
-inline typename Tokenizer<Char>::iterator Tokenizer<Char>::end() {
- return mEnd;
-}
-
-template <typename Char>
-inline Tokenizer<Char>::Tokenizer(BasicStringPiece<Char> str, Char sep) :
- mBegin(++iterator(str, sep, BasicStringPiece<Char>(str.begin() - 1, 0), false)),
- mEnd(str, sep, BasicStringPiece<Char>(str.end(), 0), true) {
+inline Tokenizer tokenize(StringPiece str, char sep) {
+ return Tokenizer(str, sep);
}
inline uint16_t hostToDevice16(uint16_t value) {
@@ -348,8 +271,8 @@
*
* Returns true if successful.
*/
-bool extractResFilePathParts(const StringPiece16& path, StringPiece16* outPrefix,
- StringPiece16* outEntry, StringPiece16* outSuffix);
+bool extractResFilePathParts(const StringPiece& path, StringPiece* outPrefix,
+ StringPiece* outEntry, StringPiece* outSuffix);
} // namespace util
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index fad1afb..0e27213 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -14,192 +14,191 @@
* limitations under the License.
*/
-#include "test/Common.h"
+#include "test/Test.h"
#include "util/StringPiece.h"
#include "util/Util.h"
-#include <gtest/gtest.h>
#include <string>
namespace aapt {
TEST(UtilTest, TrimOnlyWhitespace) {
- const std::u16string full = u"\n ";
+ const std::string full = "\n ";
- StringPiece16 trimmed = util::trimWhitespace(full);
+ StringPiece trimmed = util::trimWhitespace(full);
EXPECT_TRUE(trimmed.empty());
EXPECT_EQ(0u, trimmed.size());
}
TEST(UtilTest, StringEndsWith) {
- EXPECT_TRUE(util::stringEndsWith<char>("hello.xml", ".xml"));
+ EXPECT_TRUE(util::stringEndsWith("hello.xml", ".xml"));
}
TEST(UtilTest, StringStartsWith) {
- EXPECT_TRUE(util::stringStartsWith<char>("hello.xml", "he"));
+ EXPECT_TRUE(util::stringStartsWith("hello.xml", "he"));
}
TEST(UtilTest, StringBuilderSplitEscapeSequence) {
- EXPECT_EQ(StringPiece16(u"this is a new\nline."),
- util::StringBuilder().append(u"this is a new\\")
- .append(u"nline.")
+ EXPECT_EQ(StringPiece("this is a new\nline."),
+ util::StringBuilder().append("this is a new\\")
+ .append("nline.")
.str());
}
TEST(UtilTest, StringBuilderWhitespaceRemoval) {
- EXPECT_EQ(StringPiece16(u"hey guys this is so cool"),
- util::StringBuilder().append(u" hey guys ")
- .append(u" this is so cool ")
+ EXPECT_EQ(StringPiece("hey guys this is so cool"),
+ util::StringBuilder().append(" hey guys ")
+ .append(" this is so cool ")
.str());
- EXPECT_EQ(StringPiece16(u" wow, so many \t spaces. what?"),
- util::StringBuilder().append(u" \" wow, so many \t ")
- .append(u"spaces. \"what? ")
+ EXPECT_EQ(StringPiece(" wow, so many \t spaces. what?"),
+ util::StringBuilder().append(" \" wow, so many \t ")
+ .append("spaces. \"what? ")
.str());
- EXPECT_EQ(StringPiece16(u"where is the pie?"),
- util::StringBuilder().append(u" where \t ")
- .append(u" \nis the "" pie?")
+ EXPECT_EQ(StringPiece("where is the pie?"),
+ util::StringBuilder().append(" where \t ")
+ .append(" \nis the "" pie?")
.str());
}
TEST(UtilTest, StringBuilderEscaping) {
- EXPECT_EQ(StringPiece16(u"hey guys\n this \t is so\\ cool"),
- util::StringBuilder().append(u" hey guys\\n ")
- .append(u" this \\t is so\\\\ cool ")
+ EXPECT_EQ(StringPiece("hey guys\n this \t is so\\ cool"),
+ util::StringBuilder().append(" hey guys\\n ")
+ .append(" this \\t is so\\\\ cool ")
.str());
- EXPECT_EQ(StringPiece16(u"@?#\\\'"),
- util::StringBuilder().append(u"\\@\\?\\#\\\\\\'")
+ EXPECT_EQ(StringPiece("@?#\\\'"),
+ util::StringBuilder().append("\\@\\?\\#\\\\\\'")
.str());
}
TEST(UtilTest, StringBuilderMisplacedQuote) {
util::StringBuilder builder{};
- EXPECT_FALSE(builder.append(u"they're coming!"));
+ EXPECT_FALSE(builder.append("they're coming!"));
}
TEST(UtilTest, StringBuilderUnicodeCodes) {
- EXPECT_EQ(StringPiece16(u"\u00AF\u0AF0 woah"),
- util::StringBuilder().append(u"\\u00AF\\u0AF0 woah")
+ EXPECT_EQ(std::string("\u00AF\u0AF0 woah"),
+ util::StringBuilder().append("\\u00AF\\u0AF0 woah")
.str());
- EXPECT_FALSE(util::StringBuilder().append(u"\\u00 yo"));
+ EXPECT_FALSE(util::StringBuilder().append("\\u00 yo"));
}
TEST(UtilTest, TokenizeInput) {
- auto tokenizer = util::tokenize(StringPiece16(u"this| is|the|end"), u'|');
+ auto tokenizer = util::tokenize(StringPiece("this| is|the|end"), '|');
auto iter = tokenizer.begin();
- ASSERT_EQ(*iter, StringPiece16(u"this"));
+ ASSERT_EQ(*iter, StringPiece("this"));
++iter;
- ASSERT_EQ(*iter, StringPiece16(u" is"));
+ ASSERT_EQ(*iter, StringPiece(" is"));
++iter;
- ASSERT_EQ(*iter, StringPiece16(u"the"));
+ ASSERT_EQ(*iter, StringPiece("the"));
++iter;
- ASSERT_EQ(*iter, StringPiece16(u"end"));
+ ASSERT_EQ(*iter, StringPiece("end"));
++iter;
ASSERT_EQ(tokenizer.end(), iter);
}
TEST(UtilTest, TokenizeEmptyString) {
- auto tokenizer = util::tokenize(StringPiece16(u""), u'|');
+ auto tokenizer = util::tokenize(StringPiece(""), '|');
auto iter = tokenizer.begin();
ASSERT_NE(tokenizer.end(), iter);
- ASSERT_EQ(StringPiece16(), *iter);
+ ASSERT_EQ(StringPiece(), *iter);
++iter;
ASSERT_EQ(tokenizer.end(), iter);
}
TEST(UtilTest, TokenizeAtEnd) {
- auto tokenizer = util::tokenize(StringPiece16(u"one."), u'.');
+ auto tokenizer = util::tokenize(StringPiece("one."), '.');
auto iter = tokenizer.begin();
- ASSERT_EQ(*iter, StringPiece16(u"one"));
+ ASSERT_EQ(*iter, StringPiece("one"));
++iter;
ASSERT_NE(iter, tokenizer.end());
- ASSERT_EQ(*iter, StringPiece16());
+ ASSERT_EQ(*iter, StringPiece());
}
TEST(UtilTest, IsJavaClassName) {
- EXPECT_TRUE(util::isJavaClassName(u"android.test.Class"));
- EXPECT_TRUE(util::isJavaClassName(u"android.test.Class$Inner"));
- EXPECT_TRUE(util::isJavaClassName(u"android_test.test.Class"));
- EXPECT_TRUE(util::isJavaClassName(u"_android_.test._Class_"));
- EXPECT_FALSE(util::isJavaClassName(u"android.test.$Inner"));
- EXPECT_FALSE(util::isJavaClassName(u"android.test.Inner$"));
- EXPECT_FALSE(util::isJavaClassName(u".test.Class"));
- EXPECT_FALSE(util::isJavaClassName(u"android"));
+ EXPECT_TRUE(util::isJavaClassName("android.test.Class"));
+ EXPECT_TRUE(util::isJavaClassName("android.test.Class$Inner"));
+ EXPECT_TRUE(util::isJavaClassName("android_test.test.Class"));
+ EXPECT_TRUE(util::isJavaClassName("_android_.test._Class_"));
+ EXPECT_FALSE(util::isJavaClassName("android.test.$Inner"));
+ EXPECT_FALSE(util::isJavaClassName("android.test.Inner$"));
+ EXPECT_FALSE(util::isJavaClassName(".test.Class"));
+ EXPECT_FALSE(util::isJavaClassName("android"));
}
TEST(UtilTest, IsJavaPackageName) {
- EXPECT_TRUE(util::isJavaPackageName(u"android"));
- EXPECT_TRUE(util::isJavaPackageName(u"android.test"));
- EXPECT_TRUE(util::isJavaPackageName(u"android.test_thing"));
- EXPECT_FALSE(util::isJavaPackageName(u"_android"));
- EXPECT_FALSE(util::isJavaPackageName(u"android_"));
- EXPECT_FALSE(util::isJavaPackageName(u"android."));
- EXPECT_FALSE(util::isJavaPackageName(u".android"));
- EXPECT_FALSE(util::isJavaPackageName(u"android._test"));
- EXPECT_FALSE(util::isJavaPackageName(u".."));
+ EXPECT_TRUE(util::isJavaPackageName("android"));
+ EXPECT_TRUE(util::isJavaPackageName("android.test"));
+ EXPECT_TRUE(util::isJavaPackageName("android.test_thing"));
+ EXPECT_FALSE(util::isJavaPackageName("_android"));
+ EXPECT_FALSE(util::isJavaPackageName("android_"));
+ EXPECT_FALSE(util::isJavaPackageName("android."));
+ EXPECT_FALSE(util::isJavaPackageName(".android"));
+ EXPECT_FALSE(util::isJavaPackageName("android._test"));
+ EXPECT_FALSE(util::isJavaPackageName(".."));
}
TEST(UtilTest, FullyQualifiedClassName) {
- Maybe<std::u16string> res = util::getFullyQualifiedClassName(u"android", u".asdf");
+ Maybe<std::string> res = util::getFullyQualifiedClassName("android", ".asdf");
AAPT_ASSERT_TRUE(res);
- EXPECT_EQ(res.value(), u"android.asdf");
+ EXPECT_EQ(res.value(), "android.asdf");
- res = util::getFullyQualifiedClassName(u"android", u".a.b");
+ res = util::getFullyQualifiedClassName("android", ".a.b");
AAPT_ASSERT_TRUE(res);
- EXPECT_EQ(res.value(), u"android.a.b");
+ EXPECT_EQ(res.value(), "android.a.b");
- res = util::getFullyQualifiedClassName(u"android", u"a.b");
+ res = util::getFullyQualifiedClassName("android", "a.b");
AAPT_ASSERT_TRUE(res);
- EXPECT_EQ(res.value(), u"a.b");
+ EXPECT_EQ(res.value(), "a.b");
- res = util::getFullyQualifiedClassName(u"", u"a.b");
+ res = util::getFullyQualifiedClassName("", "a.b");
AAPT_ASSERT_TRUE(res);
- EXPECT_EQ(res.value(), u"a.b");
+ EXPECT_EQ(res.value(), "a.b");
- res = util::getFullyQualifiedClassName(u"android", u"Class");
+ res = util::getFullyQualifiedClassName("android", "Class");
AAPT_ASSERT_TRUE(res);
- EXPECT_EQ(res.value(), u"android.Class");
+ EXPECT_EQ(res.value(), "android.Class");
- res = util::getFullyQualifiedClassName(u"", u"");
+ res = util::getFullyQualifiedClassName("", "");
AAPT_ASSERT_FALSE(res);
- res = util::getFullyQualifiedClassName(u"android", u"./Apple");
+ res = util::getFullyQualifiedClassName("android", "./Apple");
AAPT_ASSERT_FALSE(res);
}
TEST(UtilTest, ExtractResourcePathComponents) {
- StringPiece16 prefix, entry, suffix;
- ASSERT_TRUE(util::extractResFilePathParts(u"res/xml-sw600dp/entry.xml", &prefix, &entry,
+ StringPiece prefix, entry, suffix;
+ ASSERT_TRUE(util::extractResFilePathParts("res/xml-sw600dp/entry.xml", &prefix, &entry,
&suffix));
- EXPECT_EQ(prefix, u"res/xml-sw600dp/");
- EXPECT_EQ(entry, u"entry");
- EXPECT_EQ(suffix, u".xml");
+ EXPECT_EQ(prefix, "res/xml-sw600dp/");
+ EXPECT_EQ(entry, "entry");
+ EXPECT_EQ(suffix, ".xml");
- ASSERT_TRUE(util::extractResFilePathParts(u"res/xml-sw600dp/entry.9.png", &prefix, &entry,
+ ASSERT_TRUE(util::extractResFilePathParts("res/xml-sw600dp/entry.9.png", &prefix, &entry,
&suffix));
- EXPECT_EQ(prefix, u"res/xml-sw600dp/");
- EXPECT_EQ(entry, u"entry");
- EXPECT_EQ(suffix, u".9.png");
+ EXPECT_EQ(prefix, "res/xml-sw600dp/");
+ EXPECT_EQ(entry, "entry");
+ EXPECT_EQ(suffix, ".9.png");
- EXPECT_FALSE(util::extractResFilePathParts(u"AndroidManifest.xml", &prefix, &entry, &suffix));
- EXPECT_FALSE(util::extractResFilePathParts(u"res/.xml", &prefix, &entry, &suffix));
+ EXPECT_FALSE(util::extractResFilePathParts("AndroidManifest.xml", &prefix, &entry, &suffix));
+ EXPECT_FALSE(util::extractResFilePathParts("res/.xml", &prefix, &entry, &suffix));
- ASSERT_TRUE(util::extractResFilePathParts(u"res//.", &prefix, &entry, &suffix));
- EXPECT_EQ(prefix, u"res//");
- EXPECT_EQ(entry, u"");
- EXPECT_EQ(suffix, u".");
+ ASSERT_TRUE(util::extractResFilePathParts("res//.", &prefix, &entry, &suffix));
+ EXPECT_EQ(prefix, "res//");
+ EXPECT_EQ(entry, "");
+ EXPECT_EQ(suffix, ".");
}
TEST(UtilTest, VerifyJavaStringFormat) {
- ASSERT_TRUE(util::verifyJavaStringFormat(u"%09.34f"));
- ASSERT_TRUE(util::verifyJavaStringFormat(u"%9$.34f %8$"));
- ASSERT_TRUE(util::verifyJavaStringFormat(u"%% %%"));
- ASSERT_FALSE(util::verifyJavaStringFormat(u"%09$f %f"));
- ASSERT_FALSE(util::verifyJavaStringFormat(u"%09f %08s"));
+ ASSERT_TRUE(util::verifyJavaStringFormat("%09.34f"));
+ ASSERT_TRUE(util::verifyJavaStringFormat("%9$.34f %8$"));
+ ASSERT_TRUE(util::verifyJavaStringFormat("%% %%"));
+ ASSERT_FALSE(util::verifyJavaStringFormat("%09$f %f"));
+ ASSERT_FALSE(util::verifyJavaStringFormat("%09f %08s"));
}
} // namespace aapt
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index 0ef67ea..745079c 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -57,8 +57,7 @@
for (Element* childEl : el->getChildElements()) {
if (childEl->namespaceUri.empty()) {
- std::map<std::u16string, XmlNodeAction>::const_iterator iter =
- mMap.find(childEl->name);
+ std::map<std::string, XmlNodeAction>::const_iterator iter = mMap.find(childEl->name);
if (iter != mMap.end()) {
error |= !iter->second.execute(policy, diag, childEl);
continue;
@@ -91,7 +90,7 @@
}
if (el->namespaceUri.empty()) {
- std::map<std::u16string, XmlNodeAction>::const_iterator iter = mMap.find(el->name);
+ std::map<std::string, XmlNodeAction>::const_iterator iter = mMap.find(el->name);
if (iter != mMap.end()) {
return iter->second.execute(policy, &sourceDiag, el);
}
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 36b94db..cad508c 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -55,7 +55,7 @@
* Find or create a child XmlNodeAction that will be performed for the child element
* with the name `name`.
*/
- XmlNodeAction& operator[](const std::u16string& name) {
+ XmlNodeAction& operator[](const std::string& name) {
return mMap[name];
}
@@ -70,7 +70,7 @@
bool execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const;
- std::map<std::u16string, XmlNodeAction> mMap;
+ std::map<std::string, XmlNodeAction> mMap;
std::vector<ActionFuncWithDiag> mActions;
};
@@ -86,7 +86,7 @@
* Find or create a root XmlNodeAction that will be performed for the root XML element
* with the name `name`.
*/
- XmlNodeAction& operator[](const std::u16string& name) {
+ XmlNodeAction& operator[](const std::string& name) {
return mMap[name];
}
@@ -97,7 +97,7 @@
bool execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
private:
- std::map<std::u16string, XmlNodeAction> mMap;
+ std::map<std::string, XmlNodeAction> mMap;
DISALLOW_COPY_AND_ASSIGN(XmlActionExecutor);
};
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
index ebf287a..106e856 100644
--- a/tools/aapt2/xml/XmlActionExecutor_test.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -22,8 +22,8 @@
TEST(XmlActionExecutorTest, BuildsAccessibleNestedPattern) {
XmlActionExecutor executor;
- XmlNodeAction& manifestAction = executor[u"manifest"];
- XmlNodeAction& applicationAction = manifestAction[u"application"];
+ XmlNodeAction& manifestAction = executor["manifest"];
+ XmlNodeAction& applicationAction = manifestAction["application"];
Element* manifestEl = nullptr;
manifestAction.action([&](Element* manifest) -> bool {
@@ -42,15 +42,15 @@
StdErrDiagnostics diag;
ASSERT_TRUE(executor.execute(XmlActionExecutorPolicy::None, &diag, doc.get()));
ASSERT_NE(nullptr, manifestEl);
- EXPECT_EQ(std::u16string(u"manifest"), manifestEl->name);
+ EXPECT_EQ(std::string("manifest"), manifestEl->name);
ASSERT_NE(nullptr, applicationEl);
- EXPECT_EQ(std::u16string(u"application"), applicationEl->name);
+ EXPECT_EQ(std::string("application"), applicationEl->name);
}
TEST(XmlActionExecutorTest, FailsWhenUndefinedHierarchyExists) {
XmlActionExecutor executor;
- executor[u"manifest"][u"application"];
+ executor["manifest"]["application"];
std::unique_ptr<XmlResource> doc = test::buildXmlDom(
"<manifest><application /><activity /></manifest>");
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 0ce333a..39bd5bf 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -33,13 +33,13 @@
struct Stack {
std::unique_ptr<xml::Node> root;
std::stack<xml::Node*> nodeStack;
- std::u16string pendingComment;
+ std::string pendingComment;
};
/**
* Extracts the namespace and name of an expanded element or attribute name.
*/
-static void splitName(const char* name, std::u16string* outNs, std::u16string* outName) {
+static void splitName(const char* name, std::string* outNs, std::string* outName) {
const char* p = name;
while (*p != 0 && *p != kXmlNamespaceSep) {
p++;
@@ -47,10 +47,10 @@
if (*p == 0) {
outNs->clear();
- *outName = util::utf8ToUtf16(name);
+ *outName = StringPiece(name).toString();
} else {
- *outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
- *outName = util::utf8ToUtf16(p + 1);
+ *outNs = StringPiece(name, (p - name)).toString();
+ *outName = StringPiece(p + 1).toString();
}
}
@@ -76,11 +76,11 @@
std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
if (prefix) {
- ns->namespacePrefix = util::utf8ToUtf16(prefix);
+ ns->namespacePrefix = StringPiece(prefix).toString();
}
if (uri) {
- ns->namespaceUri = util::utf8ToUtf16(uri);
+ ns->namespaceUri = StringPiece(uri).toString();
}
addToStack(stack, parser, std::move(ns));
@@ -109,7 +109,7 @@
while (*attrs) {
Attribute attribute;
splitName(*attrs++, &attribute.namespaceUri, &attribute.name);
- attribute.value = util::utf8ToUtf16(*attrs++);
+ attribute.value = StringPiece(*attrs++).toString();
// Insert in sorted order.
auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
@@ -144,14 +144,14 @@
if (!currentParent->children.empty()) {
Node* lastChild = currentParent->children.back().get();
if (Text* text = nodeCast<Text>(lastChild)) {
- text->text += util::utf8ToUtf16(StringPiece(s, len));
+ text->text += StringPiece(s, len).toString();
return;
}
}
}
std::unique_ptr<Text> text = util::make_unique<Text>();
- text->text = util::utf8ToUtf16(StringPiece(s, len));
+ text->text = StringPiece(s, len).toString();
addToStack(stack, parser, std::move(text));
}
@@ -162,7 +162,7 @@
if (!stack->pendingComment.empty()) {
stack->pendingComment += '\n';
}
- stack->pendingComment += util::utf8ToUtf16(comment);
+ stack->pendingComment += comment;
}
std::unique_ptr<XmlResource> inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
@@ -209,17 +209,17 @@
size_t len;
const char16_t* str16 = parser->getAttributeNamespace(i, &len);
if (str16) {
- attr.namespaceUri.assign(str16, len);
+ attr.namespaceUri = util::utf16ToUtf8(StringPiece16(str16, len));
}
str16 = parser->getAttributeName(i, &len);
if (str16) {
- attr.name.assign(str16, len);
+ attr.name = util::utf16ToUtf8(StringPiece16(str16, len));
}
str16 = parser->getAttributeStringValue(i, &len);
if (str16) {
- attr.value.assign(str16, len);
+ attr.value = util::utf16ToUtf8(StringPiece16(str16, len));
}
el->attributes.push_back(std::move(attr));
}
@@ -250,12 +250,12 @@
size_t len;
const char16_t* str16 = tree.getNamespacePrefix(&len);
if (str16) {
- node->namespacePrefix.assign(str16, len);
+ node->namespacePrefix = util::utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getNamespaceUri(&len);
if (str16) {
- node->namespaceUri.assign(str16, len);
+ node->namespaceUri = util::utf16ToUtf8(StringPiece16(str16, len));
}
newNode = std::move(node);
break;
@@ -266,12 +266,12 @@
size_t len;
const char16_t* str16 = tree.getElementNamespace(&len);
if (str16) {
- node->namespaceUri.assign(str16, len);
+ node->namespaceUri = util::utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getElementName(&len);
if (str16) {
- node->name.assign(str16, len);
+ node->name = util::utf16ToUtf8(StringPiece16(str16, len));
}
copyAttributes(node.get(), &tree);
@@ -285,7 +285,7 @@
size_t len;
const char16_t* str16 = tree.getText(&len);
if (str16) {
- node->text.assign(str16, len);
+ node->text = util::utf16ToUtf8(StringPiece16(str16, len));
}
newNode = std::move(node);
break;
@@ -347,7 +347,7 @@
children.push_back(std::move(child));
}
-Attribute* Element::findAttribute(const StringPiece16& ns, const StringPiece16& name) {
+Attribute* Element::findAttribute(const StringPiece& ns, const StringPiece& name) {
for (auto& attr : attributes) {
if (ns == attr.namespaceUri && name == attr.name) {
return &attr;
@@ -356,13 +356,13 @@
return nullptr;
}
-Element* Element::findChild(const StringPiece16& ns, const StringPiece16& name) {
+Element* Element::findChild(const StringPiece& ns, const StringPiece& name) {
return findChildWithAttribute(ns, name, {}, {}, {});
}
-Element* Element::findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name,
- const StringPiece16& attrNs, const StringPiece16& attrName,
- const StringPiece16& attrValue) {
+Element* Element::findChildWithAttribute(const StringPiece& ns, const StringPiece& name,
+ const StringPiece& attrNs, const StringPiece& attrName,
+ const StringPiece& attrValue) {
for (auto& childNode : children) {
Node* child = childNode.get();
while (nodeCast<Namespace>(child)) {
@@ -422,7 +422,7 @@
}
Maybe<ExtractedPackage> PackageAwareVisitor::transformPackageAlias(
- const StringPiece16& alias, const StringPiece16& localPackage) const {
+ const StringPiece& alias, const StringPiece& localPackage) const {
if (alias.empty()) {
return ExtractedPackage{ localPackage.toString(), false /* private */ };
}
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index b374d20..d083d82 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -41,7 +41,7 @@
Node* parent = nullptr;
size_t lineNumber = 0;
size_t columnNumber = 0;
- std::u16string comment;
+ std::string comment;
std::vector<std::unique_ptr<Node>> children;
virtual ~Node() = default;
@@ -63,8 +63,8 @@
* A Namespace XML node. Can only have one child.
*/
struct Namespace : public BaseNode<Namespace> {
- std::u16string namespacePrefix;
- std::u16string namespaceUri;
+ std::string namespacePrefix;
+ std::string namespaceUri;
};
struct AaptAttribute {
@@ -76,9 +76,9 @@
* An XML attribute.
*/
struct Attribute {
- std::u16string namespaceUri;
- std::u16string name;
- std::u16string value;
+ std::string namespaceUri;
+ std::string name;
+ std::string value;
Maybe<AaptAttribute> compiledAttribute;
std::unique_ptr<Item> compiledValue;
@@ -88,16 +88,16 @@
* An Element XML node.
*/
struct Element : public BaseNode<Element> {
- std::u16string namespaceUri;
- std::u16string name;
+ std::string namespaceUri;
+ std::string name;
std::vector<Attribute> attributes;
- Attribute* findAttribute(const StringPiece16& ns, const StringPiece16& name);
- xml::Element* findChild(const StringPiece16& ns, const StringPiece16& name);
- xml::Element* findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name,
- const StringPiece16& attrNs,
- const StringPiece16& attrName,
- const StringPiece16& attrValue);
+ Attribute* findAttribute(const StringPiece& ns, const StringPiece& name);
+ xml::Element* findChild(const StringPiece& ns, const StringPiece& name);
+ xml::Element* findChildWithAttribute(const StringPiece& ns, const StringPiece& name,
+ const StringPiece& attrNs,
+ const StringPiece& attrName,
+ const StringPiece& attrValue);
std::vector<xml::Element*> getChildElements();
};
@@ -105,7 +105,7 @@
* A Text (CDATA) XML node. Can not have any children.
*/
struct Text : public BaseNode<Text> {
- std::u16string text;
+ std::string text;
};
/**
@@ -175,7 +175,7 @@
class PackageAwareVisitor : public Visitor, public IPackageDeclStack {
private:
struct PackageDecl {
- std::u16string prefix;
+ std::string prefix;
ExtractedPackage package;
};
@@ -186,7 +186,7 @@
void visit(Namespace* ns) override;
Maybe<ExtractedPackage> transformPackageAlias(
- const StringPiece16& alias, const StringPiece16& localPackage) const override;
+ const StringPiece& alias, const StringPiece& localPackage) const override;
};
// Implementations
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 431ee2c..1909f75 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -43,8 +43,8 @@
xml::Namespace* ns = xml::nodeCast<xml::Namespace>(doc->root.get());
ASSERT_NE(ns, nullptr);
- EXPECT_EQ(ns->namespaceUri, u"http://schemas.android.com/apk/res/android");
- EXPECT_EQ(ns->namespacePrefix, u"android");
+ EXPECT_EQ(ns->namespaceUri, xml::kSchemaAndroid);
+ EXPECT_EQ(ns->namespacePrefix, "android");
}
} // namespace aapt
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index 323ec05..4a944f1 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -98,7 +98,7 @@
return mLastError;
}
-const std::u16string& XmlPullParser::getComment() const {
+const std::string& XmlPullParser::getComment() const {
return mEventQueue.front().data1;
}
@@ -110,14 +110,14 @@
return mEventQueue.front().depth;
}
-const std::u16string& XmlPullParser::getText() const {
+const std::string& XmlPullParser::getText() const {
if (getEvent() != Event::kText) {
return mEmpty;
}
return mEventQueue.front().data1;
}
-const std::u16string& XmlPullParser::getNamespacePrefix() const {
+const std::string& XmlPullParser::getNamespacePrefix() const {
const Event currentEvent = getEvent();
if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
return mEmpty;
@@ -125,7 +125,7 @@
return mEventQueue.front().data1;
}
-const std::u16string& XmlPullParser::getNamespaceUri() const {
+const std::string& XmlPullParser::getNamespaceUri() const {
const Event currentEvent = getEvent();
if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
return mEmpty;
@@ -134,7 +134,7 @@
}
Maybe<ExtractedPackage> XmlPullParser::transformPackageAlias(
- const StringPiece16& alias, const StringPiece16& localPackage) const {
+ const StringPiece& alias, const StringPiece& localPackage) const {
if (alias.empty()) {
return ExtractedPackage{ localPackage.toString(), false /* private */ };
}
@@ -152,7 +152,7 @@
return {};
}
-const std::u16string& XmlPullParser::getElementNamespace() const {
+const std::string& XmlPullParser::getElementNamespace() const {
const Event currentEvent = getEvent();
if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
return mEmpty;
@@ -160,7 +160,7 @@
return mEventQueue.front().data1;
}
-const std::u16string& XmlPullParser::getElementName() const {
+const std::string& XmlPullParser::getElementName() const {
const Event currentEvent = getEvent();
if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
return mEmpty;
@@ -186,31 +186,31 @@
/**
* Extracts the namespace and name of an expanded element or attribute name.
*/
-static void splitName(const char* name, std::u16string& outNs, std::u16string& outName) {
+static void splitName(const char* name, std::string& outNs, std::string& outName) {
const char* p = name;
while (*p != 0 && *p != kXmlNamespaceSep) {
p++;
}
if (*p == 0) {
- outNs = std::u16string();
- outName = util::utf8ToUtf16(name);
+ outNs = std::string();
+ outName = name;
} else {
- outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
- outName = util::utf8ToUtf16(p + 1);
+ outNs = StringPiece(name, (p - name)).toString();
+ outName = p + 1;
}
}
void XMLCALL XmlPullParser::startNamespaceHandler(void* userData, const char* prefix,
const char* uri) {
XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
- std::u16string namespaceUri = uri != nullptr ? util::utf8ToUtf16(uri) : std::u16string();
+ std::string namespaceUri = uri != nullptr ? uri : std::string();
parser->mNamespaceUris.push(namespaceUri);
parser->mEventQueue.push(EventData{
Event::kStartNamespace,
XML_GetCurrentLineNumber(parser->mParser),
parser->mDepth++,
- prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
+ prefix != nullptr ? prefix : std::string(),
namespaceUri
});
}
@@ -227,7 +227,7 @@
while (*attrs) {
Attribute attribute;
splitName(*attrs++, attribute.namespaceUri, attribute.name);
- attribute.value = util::utf8ToUtf16(*attrs++);
+ attribute.value = *attrs++;
// Insert in sorted order.
auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), attribute);
@@ -245,7 +245,7 @@
Event::kText,
XML_GetCurrentLineNumber(parser->mParser),
parser->mDepth,
- util::utf8ToUtf16(StringPiece(s, len))
+ StringPiece(s, len).toString()
});
}
@@ -268,7 +268,7 @@
Event::kEndNamespace,
XML_GetCurrentLineNumber(parser->mParser),
--(parser->mDepth),
- prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
+ prefix != nullptr ? prefix : std::string(),
parser->mNamespaceUris.top()
});
parser->mNamespaceUris.pop();
@@ -281,22 +281,22 @@
Event::kComment,
XML_GetCurrentLineNumber(parser->mParser),
parser->mDepth,
- util::utf8ToUtf16(comment)
+ comment
});
}
-Maybe<StringPiece16> findAttribute(const XmlPullParser* parser, const StringPiece16& name) {
- auto iter = parser->findAttribute(u"", name);
+Maybe<StringPiece> findAttribute(const XmlPullParser* parser, const StringPiece& name) {
+ auto iter = parser->findAttribute("", name);
if (iter != parser->endAttributes()) {
- return StringPiece16(util::trimWhitespace(iter->value));
+ return StringPiece(util::trimWhitespace(iter->value));
}
return {};
}
-Maybe<StringPiece16> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece16& name) {
- auto iter = parser->findAttribute(u"", name);
+Maybe<StringPiece> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece& name) {
+ auto iter = parser->findAttribute("", name);
if (iter != parser->endAttributes()) {
- StringPiece16 trimmed = util::trimWhitespace(iter->value);
+ StringPiece trimmed = util::trimWhitespace(iter->value);
if (!trimmed.empty()) {
return trimmed;
}
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index 7e7070e..ee51b36 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -80,28 +80,28 @@
// These are available for all nodes.
//
- const std::u16string& getComment() const;
+ const std::string& getComment() const;
size_t getLineNumber() const;
size_t getDepth() const;
/**
* Returns the character data for a Text event.
*/
- const std::u16string& getText() const;
+ const std::string& getText() const;
//
// Namespace prefix and URI are available for StartNamespace and EndNamespace.
//
- const std::u16string& getNamespacePrefix() const;
- const std::u16string& getNamespaceUri() const;
+ const std::string& getNamespacePrefix() const;
+ const std::string& getNamespaceUri() const;
//
// These are available for StartElement and EndElement.
//
- const std::u16string& getElementNamespace() const;
- const std::u16string& getElementName() const;
+ const std::string& getElementNamespace() const;
+ const std::string& getElementName() const;
/*
* Uses the current stack of namespaces to resolve the package. Eg:
@@ -115,7 +115,7 @@
* 'package' will be set to 'defaultPackage'.
*/
Maybe<ExtractedPackage> transformPackageAlias(
- const StringPiece16& alias, const StringPiece16& localPackage) const override;
+ const StringPiece& alias, const StringPiece& localPackage) const override;
//
// Remaining methods are for retrieving information about attributes
@@ -126,9 +126,9 @@
//
struct Attribute {
- std::u16string namespaceUri;
- std::u16string name;
- std::u16string value;
+ std::string namespaceUri;
+ std::string name;
+ std::string value;
int compare(const Attribute& rhs) const;
bool operator<(const Attribute& rhs) const;
@@ -141,7 +141,7 @@
const_iterator beginAttributes() const;
const_iterator endAttributes() const;
size_t getAttributeCount() const;
- const_iterator findAttribute(StringPiece16 namespaceUri, StringPiece16 name) const;
+ const_iterator findAttribute(StringPiece namespaceUri, StringPiece name) const;
private:
static void XMLCALL startNamespaceHandler(void* userData, const char* prefix, const char* uri);
@@ -155,8 +155,8 @@
Event event;
size_t lineNumber;
size_t depth;
- std::u16string data1;
- std::u16string data2;
+ std::string data1;
+ std::string data2;
std::vector<Attribute> attributes;
};
@@ -165,12 +165,12 @@
char mBuffer[16384];
std::queue<EventData> mEventQueue;
std::string mLastError;
- const std::u16string mEmpty;
+ const std::string mEmpty;
size_t mDepth;
- std::stack<std::u16string> mNamespaceUris;
+ std::stack<std::string> mNamespaceUris;
struct PackageDecl {
- std::u16string prefix;
+ std::string prefix;
ExtractedPackage package;
};
std::vector<PackageDecl> mPackageAliases;
@@ -179,13 +179,13 @@
/**
* Finds the attribute in the current element within the global namespace.
*/
-Maybe<StringPiece16> findAttribute(const XmlPullParser* parser, const StringPiece16& name);
+Maybe<StringPiece> findAttribute(const XmlPullParser* parser, const StringPiece& name);
/**
* Finds the attribute in the current element within the global namespace. The attribute's value
* must not be the empty string.
*/
-Maybe<StringPiece16> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece16& name);
+Maybe<StringPiece> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece& name);
//
// Implementation
@@ -270,12 +270,12 @@
return compare(rhs) != 0;
}
-inline XmlPullParser::const_iterator XmlPullParser::findAttribute(StringPiece16 namespaceUri,
- StringPiece16 name) const {
+inline XmlPullParser::const_iterator XmlPullParser::findAttribute(StringPiece namespaceUri,
+ StringPiece name) const {
const auto endIter = endAttributes();
const auto iter = std::lower_bound(beginAttributes(), endIter,
- std::pair<StringPiece16, StringPiece16>(namespaceUri, name),
- [](const Attribute& attr, const std::pair<StringPiece16, StringPiece16>& rhs) -> bool {
+ std::pair<StringPiece, StringPiece>(namespaceUri, name),
+ [](const Attribute& attr, const std::pair<StringPiece, StringPiece>& rhs) -> bool {
int cmp = attr.namespaceUri.compare(0, attr.namespaceUri.size(),
rhs.first.data(), rhs.first.size());
if (cmp < 0) return true;
diff --git a/tools/aapt2/xml/XmlPullParser_test.cpp b/tools/aapt2/xml/XmlPullParser_test.cpp
index 8fa2c6d..2c1fdc7 100644
--- a/tools/aapt2/xml/XmlPullParser_test.cpp
+++ b/tools/aapt2/xml/XmlPullParser_test.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
+#include "test/Test.h"
#include "util/StringPiece.h"
#include "xml/XmlPullParser.h"
-#include <gtest/gtest.h>
#include <sstream>
namespace aapt {
@@ -32,21 +32,21 @@
ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthOuter));
EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent());
- EXPECT_EQ(StringPiece16(u"a"), StringPiece16(parser.getElementName()));
+ EXPECT_EQ(StringPiece("a"), StringPiece(parser.getElementName()));
const size_t depthA = parser.getDepth();
ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthA));
EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent());
- EXPECT_EQ(StringPiece16(u"b"), StringPiece16(parser.getElementName()));
+ EXPECT_EQ(StringPiece("b"), StringPiece(parser.getElementName()));
const size_t depthB = parser.getDepth();
ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthB));
EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent());
- EXPECT_EQ(StringPiece16(u"c"), StringPiece16(parser.getElementName()));
+ EXPECT_EQ(StringPiece("c"), StringPiece(parser.getElementName()));
ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthB));
EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent());
- EXPECT_EQ(StringPiece16(u"e"), StringPiece16(parser.getElementName()));
+ EXPECT_EQ(StringPiece("e"), StringPiece(parser.getElementName()));
ASSERT_FALSE(xml::XmlPullParser::nextChildNode(&parser, depthOuter));
EXPECT_EQ(xml::XmlPullParser::Event::kEndDocument, parser.getEvent());
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index ab9f544..0e9d005 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -23,19 +23,25 @@
namespace aapt {
namespace xml {
-Maybe<ExtractedPackage> extractPackageFromNamespace(const std::u16string& namespaceUri) {
- if (util::stringStartsWith<char16_t>(namespaceUri, kSchemaPublicPrefix)) {
- StringPiece16 schemaPrefix = kSchemaPublicPrefix;
- StringPiece16 package = namespaceUri;
+std::string buildPackageNamespace(const StringPiece& package) {
+ std::string result = kSchemaPublicPrefix;
+ result.append(package.data(), package.size());
+ return result;
+}
+
+Maybe<ExtractedPackage> extractPackageFromNamespace(const std::string& namespaceUri) {
+ if (util::stringStartsWith(namespaceUri, kSchemaPublicPrefix)) {
+ StringPiece schemaPrefix = kSchemaPublicPrefix;
+ StringPiece package = namespaceUri;
package = package.substr(schemaPrefix.size(), package.size() - schemaPrefix.size());
if (package.empty()) {
return {};
}
return ExtractedPackage{ package.toString(), false /* isPrivate */ };
- } else if (util::stringStartsWith<char16_t>(namespaceUri, kSchemaPrivatePrefix)) {
- StringPiece16 schemaPrefix = kSchemaPrivatePrefix;
- StringPiece16 package = namespaceUri;
+ } else if (util::stringStartsWith(namespaceUri, kSchemaPrivatePrefix)) {
+ StringPiece schemaPrefix = kSchemaPrivatePrefix;
+ StringPiece package = namespaceUri;
package = package.substr(schemaPrefix.size(), package.size() - schemaPrefix.size());
if (package.empty()) {
return {};
@@ -43,13 +49,13 @@
return ExtractedPackage{ package.toString(), true /* isPrivate */ };
} else if (namespaceUri == kSchemaAuto) {
- return ExtractedPackage{ std::u16string(), true /* isPrivate */ };
+ return ExtractedPackage{ std::string(), true /* isPrivate */ };
}
return {};
}
void transformReferenceFromNamespace(IPackageDeclStack* declStack,
- const StringPiece16& localPackage, Reference* inRef) {
+ const StringPiece& localPackage, Reference* inRef) {
if (inRef->name) {
if (Maybe<ExtractedPackage> transformedPackage =
declStack->transformPackageAlias(inRef->name.value().package, localPackage)) {
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 98e5520..f0d59b7 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -25,10 +25,10 @@
namespace aapt {
namespace xml {
-constexpr const char16_t* kSchemaAuto = u"http://schemas.android.com/apk/res-auto";
-constexpr const char16_t* kSchemaPublicPrefix = u"http://schemas.android.com/apk/res/";
-constexpr const char16_t* kSchemaPrivatePrefix = u"http://schemas.android.com/apk/prv/res/";
-constexpr const char16_t* kSchemaAndroid = u"http://schemas.android.com/apk/res/android";
+constexpr const char* kSchemaAuto = "http://schemas.android.com/apk/res-auto";
+constexpr const char* kSchemaPublicPrefix = "http://schemas.android.com/apk/res/";
+constexpr const char* kSchemaPrivatePrefix = "http://schemas.android.com/apk/prv/res/";
+constexpr const char* kSchemaAndroid = "http://schemas.android.com/apk/res/android";
/**
* Result of extracting a package name from a namespace URI declaration.
@@ -38,7 +38,7 @@
* The name of the package. This can be the empty string, which means that the package
* should be assumed to be the package being compiled.
*/
- std::u16string package;
+ std::string package;
/**
* True if the package's private namespace was declared. This means that private resources
@@ -55,7 +55,14 @@
* Special case: if namespaceUri is http://schemas.android.com/apk/res-auto,
* returns an empty package name.
*/
-Maybe<ExtractedPackage> extractPackageFromNamespace(const std::u16string& namespaceUri);
+Maybe<ExtractedPackage> extractPackageFromNamespace(const std::string& namespaceUri);
+
+/**
+ * Returns an XML Android namespace for the given package of the form:
+ *
+ * http://schemas.android.com/apk/res/<package>
+ */
+std::string buildPackageNamespace(const StringPiece& package);
/**
* Interface representing a stack of XML namespace declarations. When looking up the package
@@ -68,7 +75,7 @@
* Returns an ExtractedPackage struct if the alias given corresponds with a package declaration.
*/
virtual Maybe<ExtractedPackage> transformPackageAlias(
- const StringPiece16& alias, const StringPiece16& localPackage) const = 0;
+ const StringPiece& alias, const StringPiece& localPackage) const = 0;
};
/**
@@ -77,7 +84,7 @@
* the package declaration was private.
*/
void transformReferenceFromNamespace(IPackageDeclStack* declStack,
- const StringPiece16& localPackage, Reference* inRef);
+ const StringPiece& localPackage, Reference* inRef);
} // namespace xml
} // namespace aapt
diff --git a/tools/aapt2/xml/XmlUtil_test.cpp b/tools/aapt2/xml/XmlUtil_test.cpp
index 319e770..cbeb8bc 100644
--- a/tools/aapt2/xml/XmlUtil_test.cpp
+++ b/tools/aapt2/xml/XmlUtil_test.cpp
@@ -14,40 +14,37 @@
* limitations under the License.
*/
-#include "test/Common.h"
+#include "test/Test.h"
#include "xml/XmlUtil.h"
-#include <gtest/gtest.h>
-
namespace aapt {
TEST(XmlUtilTest, ExtractPackageFromNamespace) {
- AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace(u"com.android"));
- AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace(u"http://schemas.android.com/apk"));
- AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace(u"http://schemas.android.com/apk/res"));
- AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace(u"http://schemas.android.com/apk/res/"));
- AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace(
- u"http://schemas.android.com/apk/prv/res/"));
+ AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace("com.android"));
+ AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace("http://schemas.android.com/apk"));
+ AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace("http://schemas.android.com/apk/res"));
+ AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace("http://schemas.android.com/apk/res/"));
+ AAPT_ASSERT_FALSE(xml::extractPackageFromNamespace("http://schemas.android.com/apk/prv/res/"));
Maybe<xml::ExtractedPackage> p =
- xml::extractPackageFromNamespace(u"http://schemas.android.com/apk/res/a");
+ xml::extractPackageFromNamespace("http://schemas.android.com/apk/res/a");
AAPT_ASSERT_TRUE(p);
- EXPECT_EQ(std::u16string(u"a"), p.value().package);
+ EXPECT_EQ(std::string("a"), p.value().package);
EXPECT_FALSE(p.value().privateNamespace);
- p = xml::extractPackageFromNamespace(u"http://schemas.android.com/apk/prv/res/android");
+ p = xml::extractPackageFromNamespace("http://schemas.android.com/apk/prv/res/android");
AAPT_ASSERT_TRUE(p);
- EXPECT_EQ(std::u16string(u"android"), p.value().package);
+ EXPECT_EQ(std::string("android"), p.value().package);
EXPECT_TRUE(p.value().privateNamespace);
- p = xml::extractPackageFromNamespace(u"http://schemas.android.com/apk/prv/res/com.test");
+ p = xml::extractPackageFromNamespace("http://schemas.android.com/apk/prv/res/com.test");
AAPT_ASSERT_TRUE(p);
- EXPECT_EQ(std::u16string(u"com.test"), p.value().package);
+ EXPECT_EQ(std::string("com.test"), p.value().package);
EXPECT_TRUE(p.value().privateNamespace);
- p = xml::extractPackageFromNamespace(u"http://schemas.android.com/apk/res-auto");
+ p = xml::extractPackageFromNamespace("http://schemas.android.com/apk/res-auto");
AAPT_ASSERT_TRUE(p);
- EXPECT_EQ(std::u16string(), p.value().package);
+ EXPECT_EQ(std::string(), p.value().package);
EXPECT_TRUE(p.value().privateNamespace);
}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 2e717a6..1dd53a9 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -256,23 +256,33 @@
def check_emoji_coverage(all_emoji, equivalent_emoji):
+ emoji_font = get_emoji_font()
+ check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
+
+
+def get_emoji_font():
emoji_fonts = [
record.font for record in _fallback_chain
if 'Zsye' in record.scripts]
assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
- emoji_font = emoji_fonts[0]
- coverage = get_emoji_map(emoji_font)
+ return emoji_fonts[0]
+
+def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
+ coverage = get_emoji_map(emoji_font)
for sequence in all_emoji:
assert sequence in coverage, (
'%s is not supported in the emoji font.' % printable(sequence))
+ # disable temporarily - we cover more than this
+ """
for sequence in coverage:
if sequence in {0x0000, 0x000D, 0x0020}:
# The font needs to support a few extra characters, which is OK
continue
assert sequence in all_emoji, (
'Emoji font should not support %s.' % printable(sequence))
+ """
for first, second in sorted(equivalent_emoji.items()):
assert coverage[first] == coverage[second], (
@@ -280,6 +290,8 @@
printable(first),
printable(second)))
+ # disable temporarily - some equivalent sequences we don't even know about
+ """
for glyph in set(coverage.values()):
maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph]
if len(maps_to_glyph) > 1:
@@ -295,7 +307,7 @@
'The sequences %s should not result in the same glyph %s' % (
printable(equivalent_seqs),
glyph))
-
+ """
def check_emoji_defaults(default_emoji):
missing_text_chars = _emoji_properties['Emoji'] - default_emoji
@@ -412,6 +424,16 @@
path.join(ucd_path, 'emoji-zwj-sequences.txt'))
+ # add in UN flag
+ UN_seq = flag_sequence('UN')
+ _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence'
+
+
+ # add in UN flag
+ UN_seq = flag_sequence('UN')
+ _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence'
+
+
def flag_sequence(territory_code):
return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
@@ -468,6 +490,11 @@
(0x1F468, 0x200D, 0x1F469, 0x200D, 0x1F466): 0x1F46A,
}
+
+def is_fitzpatrick_modifier(cp):
+ return 0x1f3fb <= cp <= 0x1f3ff
+
+
def compute_expected_emoji():
equivalent_emoji = {}
sequence_pieces = set()
@@ -485,7 +512,15 @@
sequence_pieces.update(sequence)
# Add reverse of all emoji ZWJ sequences, which are added to the fonts
# as a workaround to get the sequences work in RTL text.
- reversed_seq = tuple(reversed(sequence))
+ reversed_seq = list(reversed(sequence))
+ # if there are fitzpatrick modifiers in the sequence, keep them after
+ # the emoji they modify
+ for i in xrange(1, len(reversed_seq)):
+ if is_fitzpatrick_modifier(reversed_seq[i - 1]):
+ tmp = reversed_seq[i]
+ reversed_seq[i] = reversed_seq[i-1]
+ reversed_seq[i-1] = tmp
+ reversed_seq = tuple(reversed_seq)
all_sequences.add(reversed_seq)
equivalent_emoji[reversed_seq] = sequence
@@ -521,8 +556,8 @@
def main():
- target_out = sys.argv[1]
global _fonts_dir
+ target_out = sys.argv[1]
_fonts_dir = path.join(target_out, 'fonts')
fonts_xml_path = path.join(target_out, 'etc', 'fonts.xml')
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4e4da8b..49ab9f9 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -590,4 +590,9 @@
@Override
public void removeWallpaperInputConsumer() throws RemoteException {}
+
+ @Override
+ public Bitmap screenshotWallpaper() throws RemoteException {
+ return null;
+ }
}
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/nan/ConfigRequest.java
index 759098e..cd47359 100644
--- a/wifi/java/android/net/wifi/nan/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/nan/ConfigRequest.java
@@ -16,6 +16,7 @@
package android.net.wifi.nan;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
index b95140e..a4e590b 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
@@ -28,7 +28,7 @@
{
void onConnectSuccess();
void onConnectFail(int reason);
- void onIdentityChanged();
+ void onIdentityChanged(in byte[] mac);
void onRangingSuccess(int rangingId, in RttManager.ParcelableRttResults results);
void onRangingFailure(int rangingId, int reason, in String description);
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
index d7cba8f..a4969bd 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -23,6 +23,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
@@ -58,7 +59,7 @@
/**
* @hide
*/
- public final String mServiceName;
+ public final byte[] mServiceName;
/**
* @hide
@@ -110,7 +111,7 @@
*/
public final boolean mEnableTerminateNotification;
- private PublishConfig(String serviceName, byte[] serviceSpecificInfo,
+ private PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo,
int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter,
int rxFilterLength, int publishType, int publichCount, int ttlSec,
boolean enableTerminateNotification) {
@@ -147,7 +148,10 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mServiceName);
+ dest.writeInt(mServiceName.length);
+ if (mServiceName.length != 0) {
+ dest.writeByteArray(mServiceName);
+ }
dest.writeInt(mServiceSpecificInfoLength);
if (mServiceSpecificInfoLength != 0) {
dest.writeByteArray(mServiceSpecificInfo, 0, mServiceSpecificInfoLength);
@@ -174,7 +178,11 @@
@Override
public PublishConfig createFromParcel(Parcel in) {
- String serviceName = in.readString();
+ int serviceNameLength = in.readInt();
+ byte[] serviceName = new byte[serviceNameLength];
+ if (serviceNameLength != 0) {
+ in.readByteArray(serviceName);
+ }
int ssiLength = in.readInt();
byte[] ssi = new byte[ssiLength];
if (ssiLength != 0) {
@@ -213,7 +221,7 @@
PublishConfig lhs = (PublishConfig) o;
- if (!mServiceName.equals(lhs.mServiceName)
+ if (!Arrays.equals(mServiceName, lhs.mServiceName)
|| mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength
|| mTxFilterLength != lhs.mTxFilterLength
|| mRxFilterLength != lhs.mRxFilterLength) {
@@ -259,7 +267,7 @@
public int hashCode() {
int result = 17;
- result = 31 * result + mServiceName.hashCode();
+ result = 31 * result + Arrays.hashCode(mServiceName);
result = 31 * result + mServiceSpecificInfoLength;
result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
result = 31 * result + mTxFilterLength;
@@ -281,6 +289,8 @@
* @hide
*/
public void validate() throws IllegalArgumentException {
+ WifiNanUtils.validateServiceName(mServiceName);
+
if (mServiceSpecificInfoLength != 0 && (mServiceSpecificInfo == null
|| mServiceSpecificInfo.length < mServiceSpecificInfoLength)) {
throw new IllegalArgumentException("Non-matching combination of "
@@ -290,10 +300,18 @@
throw new IllegalArgumentException(
"Non-matching combination of txFilter and txFilterLength");
}
+ if (!TlvBufferUtils.isValid(mTxFilter, mTxFilterLength, 0, 1)) {
+ throw new IllegalArgumentException(
+ "Invalid txFilter configuration - LV fields do not match up to length");
+ }
if (mRxFilterLength != 0 && (mRxFilter == null || mRxFilter.length < mRxFilterLength)) {
throw new IllegalArgumentException(
"Non-matching combination of rxFilter and rxFilterLength");
}
+ if (!TlvBufferUtils.isValid(mRxFilter, mRxFilterLength, 0, 1)) {
+ throw new IllegalArgumentException(
+ "Invalid rxFilter configuration - LV fields do not match up to length");
+ }
if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) {
throw new IllegalArgumentException("Invalid publishType - " + mPublishType);
}
@@ -317,7 +335,7 @@
* Builder used to build {@link PublishConfig} objects.
*/
public static final class Builder {
- private String mServiceName;
+ private byte[] mServiceName;
private int mServiceSpecificInfoLength;
private byte[] mServiceSpecificInfo = new byte[0];
private int mTxFilterLength;
@@ -333,12 +351,20 @@
* Specify the service name of the publish session. The actual on-air
* value is a 6 byte hashed representation of this string.
*
+ * Per spec: The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
+ * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
+ * values (A-Z, a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte
+ * UTF-8 characters are acceptable in a Service Name.
+ *
* @param serviceName The service name for the publish session.
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
public Builder setServiceName(@NonNull String serviceName) {
- mServiceName = serviceName;
+ if (serviceName == null) {
+ throw new IllegalArgumentException("Invalid service name - must be non-null");
+ }
+ mServiceName = serviceName.getBytes(StandardCharsets.UTF_8);
return this;
}
@@ -380,8 +406,8 @@
* {@code builder.setXXX(..).setXXX(..)}.
*/
public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) {
- mServiceSpecificInfoLength = serviceSpecificInfoStr.length();
mServiceSpecificInfo = serviceSpecificInfoStr.getBytes();
+ mServiceSpecificInfoLength = mServiceSpecificInfo.length;
return this;
}
diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
index 847c8d0..0d3ea01 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -23,6 +23,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
@@ -76,7 +77,7 @@
/**
* @hide
*/
- public final String mServiceName;
+ public final byte[] mServiceName;
/**
* @hide
@@ -133,7 +134,7 @@
*/
public final boolean mEnableTerminateNotification;
- private SubscribeConfig(String serviceName, byte[] serviceSpecificInfo,
+ private SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo,
int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter,
int rxFilterLength, int subscribeType, int publichCount, int ttlSec, int matchStyle,
boolean enableTerminateNotification) {
@@ -171,7 +172,10 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mServiceName);
+ dest.writeInt(mServiceName.length);
+ if (mServiceName.length != 0) {
+ dest.writeByteArray(mServiceName);
+ }
dest.writeInt(mServiceSpecificInfoLength);
if (mServiceSpecificInfoLength != 0) {
dest.writeByteArray(mServiceSpecificInfo, 0, mServiceSpecificInfoLength);
@@ -199,7 +203,11 @@
@Override
public SubscribeConfig createFromParcel(Parcel in) {
- String serviceName = in.readString();
+ int serviceNameLength = in.readInt();
+ byte[] serviceName = new byte[serviceNameLength];
+ if (serviceNameLength != 0) {
+ in.readByteArray(serviceName);
+ }
int ssiLength = in.readInt();
byte[] ssi = new byte[ssiLength];
if (ssiLength != 0) {
@@ -239,7 +247,7 @@
SubscribeConfig lhs = (SubscribeConfig) o;
- if (!mServiceName.equals(lhs.mServiceName)
+ if (!Arrays.equals(mServiceName, lhs.mServiceName)
|| mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength
|| mTxFilterLength != lhs.mTxFilterLength
|| mRxFilterLength != lhs.mRxFilterLength) {
@@ -285,7 +293,7 @@
public int hashCode() {
int result = 17;
- result = 31 * result + mServiceName.hashCode();
+ result = 31 * result + Arrays.hashCode(mServiceName);
result = 31 * result + mServiceSpecificInfoLength;
result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
result = 31 * result + mTxFilterLength;
@@ -308,6 +316,8 @@
* @hide
*/
public void validate() throws IllegalArgumentException {
+ WifiNanUtils.validateServiceName(mServiceName);
+
if (mServiceSpecificInfoLength != 0 && (mServiceSpecificInfo == null
|| mServiceSpecificInfo.length < mServiceSpecificInfoLength)) {
throw new IllegalArgumentException("Non-matching combination of "
@@ -317,10 +327,18 @@
throw new IllegalArgumentException(
"Non-matching combination of txFilter and txFilterLength");
}
+ if (!TlvBufferUtils.isValid(mTxFilter, mTxFilterLength, 0, 1)) {
+ throw new IllegalArgumentException(
+ "Invalid txFilter configuration - LV fields do not match up to length");
+ }
if (mRxFilterLength != 0 && (mRxFilter == null || mRxFilter.length < mRxFilterLength)) {
throw new IllegalArgumentException(
"Non-matching combination of rxFilter and rxFilterLength");
}
+ if (!TlvBufferUtils.isValid(mRxFilter, mRxFilterLength, 0, 1)) {
+ throw new IllegalArgumentException(
+ "Invalid rxFilter configuration - LV fields do not match up to length");
+ }
if (mSubscribeType < SUBSCRIBE_TYPE_PASSIVE || mSubscribeType > SUBSCRIBE_TYPE_ACTIVE) {
throw new IllegalArgumentException("Invalid subscribeType - " + mSubscribeType);
}
@@ -348,7 +366,7 @@
* Builder used to build {@link SubscribeConfig} objects.
*/
public static final class Builder {
- private String mServiceName;
+ private byte[] mServiceName;
private int mServiceSpecificInfoLength;
private byte[] mServiceSpecificInfo = new byte[0];
private int mTxFilterLength;
@@ -365,12 +383,20 @@
* Specify the service name of the subscribe session. The actual on-air
* value is a 6 byte hashed representation of this string.
*
+ * Per spec: The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
+ * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
+ * values (A-Z, a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte
+ * UTF-8 characters are acceptable in a Service Name.
+ *
* @param serviceName The service name for the subscribe session.
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
public Builder setServiceName(@NonNull String serviceName) {
- mServiceName = serviceName;
+ if (serviceName == null) {
+ throw new IllegalArgumentException("Invalid service name - must be non-null");
+ }
+ mServiceName = serviceName.getBytes(StandardCharsets.UTF_8);
return this;
}
@@ -413,8 +439,8 @@
* {@code builder.setXXX(..).setXXX(..)}.
*/
public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) {
- mServiceSpecificInfoLength = serviceSpecificInfoStr.length();
mServiceSpecificInfo = serviceSpecificInfoStr.getBytes();
+ mServiceSpecificInfoLength = mServiceSpecificInfo.length;
return this;
}
diff --git a/wifi/java/android/net/wifi/nan/TlvBufferUtils.java b/wifi/java/android/net/wifi/nan/TlvBufferUtils.java
index ea8785a..da7ecd8 100644
--- a/wifi/java/android/net/wifi/nan/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/nan/TlvBufferUtils.java
@@ -224,7 +224,8 @@
* {@code ctr.putXXX(..).putXXX(..)}.
*/
public TlvConstructor putString(int type, String data) {
- return putByteArray(type, data.getBytes(), 0, data.length());
+ byte[] bytes = data.getBytes();
+ return putByteArray(type, bytes, 0, bytes.length);
}
/**
@@ -487,4 +488,43 @@
};
}
}
+
+ /**
+ * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
+ * fields correctly fill the specified length (and do not overshoot).
+ *
+ * @param array The (T)LV array to verify.
+ * @param length The number of bytes in the array to consider (starting at offset 0).
+ * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
+ * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2.
+ * @return A boolean indicating whether the array is valid (true) or invalid (false).
+ */
+ public static boolean isValid(byte[] array, int length, int typeSize, int lengthSize) {
+ if (typeSize < 0 || typeSize > 2) {
+ throw new IllegalArgumentException(
+ "Invalid arguments - typeSize must be 0, 1, or 2: typeSize=" + typeSize);
+ }
+ if (lengthSize <= 0 || lengthSize > 2) {
+ throw new IllegalArgumentException(
+ "Invalid arguments - lengthSize must be 1 or 2: lengthSize=" + lengthSize);
+ }
+ if (length < 0 || length > array.length) {
+ throw new IllegalArgumentException(
+ "Invalid arguments - length must be non-negative and <= array.length: length="
+ + length + ", array.length=" + array.length);
+ }
+
+ int nextTlvIndex = 0;
+ while (nextTlvIndex + typeSize + lengthSize <= length) {
+ nextTlvIndex += typeSize;
+ if (lengthSize == 1) {
+ nextTlvIndex += lengthSize + array[nextTlvIndex];
+ } else {
+ nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex,
+ ByteOrder.BIG_ENDIAN);
+ }
+ }
+
+ return nextTlvIndex == length;
+ }
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
index 2b9a5fa..148307d 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
@@ -62,7 +62,7 @@
* Called when NAN connect operation
* {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)}
* is completed. Doesn't necessarily mean that have joined or started a NAN
- * cluster. An indication is provided by {@link #onIdentityChanged()}.
+ * cluster. An indication is provided by {@link #onIdentityChanged(byte[])}.
*/
public void onConnectSuccess() {
/* empty */
@@ -81,12 +81,14 @@
}
/**
- * Called when NAN identity has changed. This may be due to joining a
- * cluster, starting a cluster, or discovery interface change. The
- * implication is that peers you've been communicating with may no longer
- * recognize you and you need to re-establish your identity.
+ * Called when NAN identity has changed and after {@link #onConnectSuccess()}. Call may be
+ * due to joining a cluster, starting a cluster, or discovery interface change. The
+ * implication is that peers you've been communicating with may no longer recognize you and
+ * you need to re-establish your identity.
+ * @param mac The MAC address of the NAN discovery interface. Depending on the permission
+ * model may be all 0's.
*/
- public void onIdentityChanged() {
+ public void onIdentityChanged(byte[] mac) {
/* empty */
}
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 9055622..a58cdb7 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -16,10 +16,12 @@
package android.net.wifi.nan;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.net.wifi.RttManager;
import android.os.Binder;
import android.os.Bundle;
@@ -28,11 +30,19 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.util.Base64;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import libcore.util.HexEncoding;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Arrays;
@@ -59,6 +69,101 @@
private static final int INVALID_CLIENT_ID = 0;
/**
+ * Keys used to generate a Network Specifier for the NAN network request. The network specifier
+ * is formatted as a JSON string.
+ */
+
+ /**
+ * TYPE_1A: role, client_id, session_id, peer_id, token
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_1A = 0;
+
+ /**
+ * TYPE_1B: role, client_id, session_id, peer_id [only permitted for RESPONDER]
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_1B = 1;
+
+ /**
+ * TYPE_1C: role, client_id, session_id, token [only permitted for RESPONDER]
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_1C = 2;
+
+ /**
+ * TYPE_1C: role, client_id, session_id [only permitted for RESPONDER]
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_1D = 3;
+
+ /**
+ * TYPE_2A: role, client_id, peer_mac, token
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_2A = 4;
+
+ /**
+ * TYPE_2B: role, client_id, peer_mac [only permitted for RESPONDER]
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_2B = 5;
+
+ /**
+ * TYPE_2C: role, client_id, token [only permitted for RESPONDER]
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_2C = 6;
+
+ /**
+ * TYPE_2D: role, client_id [only permitted for RESPONDER]
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_2D = 7;
+
+ /**
+ * @hide
+ */
+ public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_2D;
+
+ /**
+ * @hide
+ */
+
+ public static final String NETWORK_SPECIFIER_KEY_TYPE = "type";
+
+ /**
+ * @hide
+ */
+
+ public static final String NETWORK_SPECIFIER_KEY_ROLE = "role";
+
+ /**
+ * @hide
+ */
+
+ public static final String NETWORK_SPECIFIER_KEY_CLIENT_ID = "client_id";
+ /**
+ * @hide
+ */
+ public static final String NETWORK_SPECIFIER_KEY_SESSION_ID = "session_id";
+
+ /**
+ * @hide
+ */
+ public static final String NETWORK_SPECIFIER_KEY_PEER_ID = "peer_id";
+
+ /**
+ * @hide
+ */
+ public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac";
+
+ /**
+ * @hide
+ */
+ public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
+
+ /**
* Broadcast intent action to indicate whether Wi-Fi NAN is enabled or
* disabled. An extra {@link #EXTRA_WIFI_STATE} provides the state
* information as int.
@@ -92,6 +197,27 @@
*/
public static final int WIFI_NAN_STATE_ENABLED = 2;
+ @IntDef({
+ WIFI_NAN_DATA_PATH_ROLE_INITIATOR, WIFI_NAN_DATA_PATH_ROLE_RESPONDER})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DataPathRole {
+ }
+
+ /**
+ * Data-path creation role is that of INITIATOR. Used in
+ * {@link #createNetworkSpecifier(int, byte[], byte[], int)} and
+ * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[], int)}.
+ */
+ public static final int WIFI_NAN_DATA_PATH_ROLE_INITIATOR = 0;
+
+ /**
+ * Data-path creation role is that of RESPONDER. Used in
+ * {@link #createNetworkSpecifier(int, byte[], byte[], int)} and
+ * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[], int)}.
+ */
+
+ public static final int WIFI_NAN_DATA_PATH_ROLE_RESPONDER = 1;
+
private final IWifiNanManager mService;
private final Object mLock = new Object(); // lock access to the following vars
@@ -457,6 +583,181 @@
}
}
+ /**
+ * {@hide}
+ */
+ public String createNetworkSpecifier(@DataPathRole int role, int sessionId, int peerId,
+ byte[] token, int tokenLength) {
+ if (VDBG) {
+ Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
+ + ", peerId=" + peerId + ", token=" + token + ", tokenLength=" + tokenLength);
+ }
+
+ int type;
+ if (token != null && peerId != 0) {
+ type = NETWORK_SPECIFIER_TYPE_1A;
+ } else if (token == null && peerId != 0) {
+ type = NETWORK_SPECIFIER_TYPE_1B;
+ } else if (token != null && peerId == 0) {
+ type = NETWORK_SPECIFIER_TYPE_1C;
+ } else {
+ type = NETWORK_SPECIFIER_TYPE_1D;
+ }
+
+ if (role != WIFI_NAN_DATA_PATH_ROLE_INITIATOR
+ && role != WIFI_NAN_DATA_PATH_ROLE_RESPONDER) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid 'role' argument when creating a network "
+ + "specifier");
+ }
+ if (role == WIFI_NAN_DATA_PATH_ROLE_INITIATOR) {
+ if (token == null) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
+ }
+ if (peerId == 0) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid peer ID (value of 0) - not permitted on "
+ + "INITIATOR");
+ }
+ }
+ if (tokenLength != 0 && (token == null || token.length < tokenLength)) {
+ throw new IllegalArgumentException(
+ "Non-matching combination of token and tokenLength");
+ }
+
+ int clientId;
+ synchronized (mLock) {
+ if (mClientId == INVALID_CLIENT_ID) {
+ Log.e(TAG,
+ "createNetworkSpecifier: called with invalid client ID - not connected "
+ + "first?");
+ return null;
+ }
+
+ clientId = mClientId;
+ }
+
+ JSONObject json;
+ try {
+ json = new JSONObject();
+ json.put(NETWORK_SPECIFIER_KEY_TYPE, type);
+ json.put(NETWORK_SPECIFIER_KEY_ROLE, role);
+ json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId);
+ json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId);
+ if (peerId != 0) {
+ json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerId);
+ }
+ if (token != null) {
+ json.put(NETWORK_SPECIFIER_KEY_TOKEN,
+ Base64.encodeToString(token, 0, tokenLength, Base64.DEFAULT));
+ }
+ } catch (JSONException e) {
+ return "";
+ }
+
+ return json.toString();
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
+ * WiFi NAN data-path connection to the specified peer. The peer MAC cannot be obtained
+ * through {@link WifiNanManager} services - but could be obtained out-of-bound - it refers
+ * to the MAC address of the NAN discovery interface of the peer NAN device.
+ *
+ * @param role The role of this device:
+ * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's NAN discovery interface. A null is permitted
+ * for a RESPONDER - which implies that any peer can connect.
+ * @param token An arbitrary token (message) to be passed to the peer as part of the
+ * data-path setup process. On the RESPONDER a null token is permitted and
+ * matches any peer token - an empty token requires the peer token to be empty
+ * as well.
+ * @param tokenLength The number of significant (usable) bytes from the {@code token} parameter.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to {@link
+ * android.net.ConnectivityManager#requestNetwork(NetworkRequest,
+ * ConnectivityManager.NetworkCallback)}
+ * [or other varierties of that API].
+ */
+ public String createNetworkSpecifier(@DataPathRole int role, @Nullable byte[] peer,
+ @Nullable byte[] token, int tokenLength) {
+ if (VDBG) {
+ Log.v(TAG,
+ "createNetworkSpecifier: role=" + role + ", token=" + token + ", tokenLength="
+ + tokenLength);
+ }
+
+ int type;
+ if (token != null && peer != null) {
+ type = NETWORK_SPECIFIER_TYPE_2A;
+ } else if (token == null && peer != null) {
+ type = NETWORK_SPECIFIER_TYPE_2B;
+ } else if (token != null && peer == null) {
+ type = NETWORK_SPECIFIER_TYPE_2C;
+ } else { // both are null
+ type = NETWORK_SPECIFIER_TYPE_2D;
+ }
+
+ if (role != WIFI_NAN_DATA_PATH_ROLE_INITIATOR
+ && role != WIFI_NAN_DATA_PATH_ROLE_RESPONDER) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid 'role' argument when creating a network "
+ + "specifier");
+ }
+ if (role == WIFI_NAN_DATA_PATH_ROLE_INITIATOR) {
+ if (peer == null || peer.length != 6) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid peer MAC address");
+ }
+ if (token == null) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
+ }
+ } else {
+ if (peer != null && peer.length != 6) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid peer MAC address");
+ }
+ }
+ if (tokenLength != 0 && (token == null || token.length < tokenLength)) {
+ throw new IllegalArgumentException(
+ "Non-matching combination of token and tokenLength");
+ }
+
+ int clientId;
+ synchronized (mLock) {
+ if (mClientId == INVALID_CLIENT_ID) {
+ Log.e(TAG,
+ "createNetworkSpecifier: called with invalid client ID - not connected "
+ + "first?");
+ return null;
+ }
+
+ clientId = mClientId;
+ }
+
+ JSONObject json;
+ try {
+ json = new JSONObject();
+ json.put(NETWORK_SPECIFIER_KEY_TYPE, type);
+ json.put(NETWORK_SPECIFIER_KEY_ROLE, role);
+ json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId);
+ if (peer != null) {
+ json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer)));
+ }
+ if (token != null) {
+ json.put(NETWORK_SPECIFIER_KEY_TOKEN,
+ Base64.encodeToString(token, 0, tokenLength, Base64.DEFAULT));
+ }
+ } catch (JSONException e) {
+ return "";
+ }
+
+ return json.toString();
+ }
+
private static class WifiNanEventCallbackProxy extends IWifiNanEventCallback.Stub {
private static final int CALLBACK_CONNECT_SUCCESS = 0;
private static final int CALLBACK_CONNECT_FAIL = 1;
@@ -519,7 +820,7 @@
originalCallback.onConnectFail(msg.arg1);
break;
case CALLBACK_IDENTITY_CHANGED:
- originalCallback.onIdentityChanged();
+ originalCallback.onIdentityChanged((byte[]) msg.obj);
break;
case CALLBACK_RANGING_SUCCESS: {
RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
@@ -575,10 +876,11 @@
}
@Override
- public void onIdentityChanged() {
- if (VDBG) Log.v(TAG, "onIdentityChanged");
+ public void onIdentityChanged(byte[] mac) {
+ if (VDBG) Log.v(TAG, "onIdentityChanged: mac=" + new String(HexEncoding.encode(mac)));
Message msg = mHandler.obtainMessage(CALLBACK_IDENTITY_CHANGED);
+ msg.obj = mac;
mHandler.sendMessage(msg);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index 3533c02..8eb2f89 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -16,6 +16,8 @@
package android.net.wifi.nan;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.wifi.RttManager;
import android.util.Log;
@@ -166,6 +168,7 @@
* {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to
* a peer ID - not to a MAC address.
* @param listener The listener to receive the results of the ranging session.
+ * @hide PROPOSED_NAN_SYSTEM_API [TODO: b/28847998 - track RTT API & visilibity]
*/
public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) {
if (mTerminated) {
@@ -181,4 +184,43 @@
mgr.startRanging(mSessionId, params, listener);
}
}
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
+ * WiFi NAN data-path connection to the specified peer. The peer ID is in the context of a
+ * previous match or received message in this session.
+ *
+ * @param role The role of this device:
+ * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
+ * @param peerId The peer ID obtained through
+ * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} or
+ * {@link WifiNanSessionCallback#onMessageReceived(int, byte[], int)}. On the RESPONDER a
+ * value of 0 is permitted which matches any peer.
+ * @param token An arbitrary token (message) to be passed to the peer as part of the
+ * data-path setup process. On the RESPONDER a null token is permitted and
+ * matches any peer token - an empty token requires the peer token to be empty
+ * as well.
+ * @param tokenLength The number of significant (usable) bytes from the {@code token} parameter.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to {@link
+ * android.net.ConnectivityManager#requestNetwork(NetworkRequest,
+ * ConnectivityManager.NetworkCallback)}
+ * [or other varierties of that API].
+ */
+ public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role, int peerId,
+ @Nullable byte[] token, int tokenLength) {
+ if (mTerminated) {
+ Log.w(TAG, "createNetworkSpecifier: called on terminated session");
+ return null;
+ } else {
+ WifiNanManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.w(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
+ return null;
+ }
+
+ return mgr.createNetworkSpecifier(role, mSessionId, peerId, token, tokenLength);
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanUtils.java b/wifi/java/android/net/wifi/nan/WifiNanUtils.java
new file mode 100644
index 0000000..c0f36b4
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanUtils.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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.net.wifi.nan;
+
+/**
+ * Provides utilities for the Wifi NAN manager/service.
+ *
+ * @hide
+ */
+public class WifiNanUtils {
+ /**
+ * Per spec: The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length. The
+ * only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric values (A-Z,
+ * a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte UTF-8 characters
+ * are acceptable in a Service Name.
+ */
+ public static void validateServiceName(byte[] serviceNameData) throws IllegalArgumentException {
+ if (serviceNameData == null) {
+ throw new IllegalArgumentException("Invalid service name - null");
+ }
+
+ if (serviceNameData.length < 1 || serviceNameData.length > 255) {
+ throw new IllegalArgumentException("Invalid service name length - must be between "
+ + "1 and 255 bytes (UTF-8 encoding)");
+ }
+
+ int index = 0;
+ while (index < serviceNameData.length) {
+ byte b = serviceNameData[index];
+ if ((b & 0x80) == 0x00) {
+ if (!((b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')
+ || b == '-' || b == '.')) {
+ throw new IllegalArgumentException("Invalid service name - illegal characters,"
+ + " allowed = (0-9, a-z,A-Z, -, .)");
+ }
+ }
+ ++index;
+ }
+ }
+}