Merge "Add some methods to manage slice permissios" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index d65a61d..27aa008 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1605,17 +1605,17 @@
field public static final int holo_purple = 17170458; // 0x106001a
field public static final int holo_red_dark = 17170455; // 0x1060017
field public static final int holo_red_light = 17170454; // 0x1060016
- field public static final int primary_text_dark = 17170433; // 0x1060001
- field public static final int primary_text_dark_nodisable = 17170434; // 0x1060002
- field public static final int primary_text_light = 17170435; // 0x1060003
- field public static final int primary_text_light_nodisable = 17170436; // 0x1060004
- field public static final int secondary_text_dark = 17170437; // 0x1060005
- field public static final int secondary_text_dark_nodisable = 17170438; // 0x1060006
- field public static final int secondary_text_light = 17170439; // 0x1060007
- field public static final int secondary_text_light_nodisable = 17170440; // 0x1060008
+ field public static final deprecated int primary_text_dark = 17170433; // 0x1060001
+ field public static final deprecated int primary_text_dark_nodisable = 17170434; // 0x1060002
+ field public static final deprecated int primary_text_light = 17170435; // 0x1060003
+ field public static final deprecated int primary_text_light_nodisable = 17170436; // 0x1060004
+ field public static final deprecated int secondary_text_dark = 17170437; // 0x1060005
+ field public static final deprecated int secondary_text_dark_nodisable = 17170438; // 0x1060006
+ field public static final deprecated int secondary_text_light = 17170439; // 0x1060007
+ field public static final deprecated int secondary_text_light_nodisable = 17170440; // 0x1060008
field public static final int tab_indicator_text = 17170441; // 0x1060009
- field public static final int tertiary_text_dark = 17170448; // 0x1060010
- field public static final int tertiary_text_light = 17170449; // 0x1060011
+ field public static final deprecated int tertiary_text_dark = 17170448; // 0x1060010
+ field public static final deprecated int tertiary_text_light = 17170449; // 0x1060011
field public static final int transparent = 17170445; // 0x106000d
field public static final int white = 17170443; // 0x106000b
field public static final int widget_edittext_dark = 17170442; // 0x106000a
@@ -6468,7 +6468,6 @@
method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(android.content.ComponentName);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
- method public java.lang.String getPasswordBlacklistName(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -6577,7 +6576,6 @@
method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
method public void setOverrideApnsEnabled(android.content.ComponentName, boolean);
method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
- method public boolean setPasswordBlacklist(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -13655,17 +13653,17 @@
method public boolean isDecodeAsAlphaMaskEnabled();
method public boolean isMutableRequired();
method public boolean isUnpremultipliedRequired();
- method public android.graphics.ImageDecoder setAllocator(int);
- method public android.graphics.ImageDecoder setConserveMemory(boolean);
- method public android.graphics.ImageDecoder setCrop(android.graphics.Rect);
- method public android.graphics.ImageDecoder setDecodeAsAlphaMaskEnabled(boolean);
- method public android.graphics.ImageDecoder setMutableRequired(boolean);
- method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
- method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
- method public android.graphics.ImageDecoder setTargetColorSpace(android.graphics.ColorSpace);
- method public android.graphics.ImageDecoder setTargetSampleSize(int);
- method public android.graphics.ImageDecoder setTargetSize(int, int);
- method public android.graphics.ImageDecoder setUnpremultipliedRequired(boolean);
+ method public void setAllocator(int);
+ method public void setConserveMemory(boolean);
+ method public void setCrop(android.graphics.Rect);
+ method public void setDecodeAsAlphaMaskEnabled(boolean);
+ method public void setMutableRequired(boolean);
+ method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
+ method public void setPostProcessor(android.graphics.PostProcessor);
+ method public void setTargetColorSpace(android.graphics.ColorSpace);
+ method public void setTargetSampleSize(int);
+ method public void setTargetSize(int, int);
+ method public void setUnpremultipliedRequired(boolean);
field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
@@ -21969,6 +21967,7 @@
}
public final class AudioDeviceInfo {
+ method public java.lang.String getAddress();
method public int[] getChannelCounts();
method public int[] getChannelIndexMasks();
method public int[] getChannelMasks();
@@ -24460,6 +24459,7 @@
}
public final class MicrophoneInfo {
+ method public java.lang.String getAddress();
method public java.util.List<android.util.Pair<java.lang.Integer, java.lang.Integer>> getChannelMapping();
method public java.lang.String getDescription();
method public int getDirectionality();
@@ -27016,8 +27016,8 @@
public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
method public void close() throws java.io.IOException;
+ method public java.io.FileDescriptor getFileDescriptor();
method public int getPort();
- method public java.io.FileDescriptor getSocket();
}
public final class IpSecTransform implements java.lang.AutoCloseable {
@@ -27246,6 +27246,8 @@
public class NetworkRequest implements android.os.Parcelable {
method public int describeContents();
+ method public boolean hasCapability(int);
+ method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
}
@@ -38568,6 +38570,7 @@
method public boolean isRandomizedEncryptionRequired();
method public boolean isStrongBoxBacked();
method public boolean isTrustedUserPresenceRequired();
+ method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38595,6 +38598,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -38687,6 +38691,7 @@
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isTrustedUserPresenceRequired();
+ method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38706,6 +38711,7 @@
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index ed763ba..165c6ae 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3105,6 +3105,10 @@
field public static final int ERROR_INVALID_NETWORK = 1; // 0x1
}
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
+ }
+
public class NetworkKey implements android.os.Parcelable {
ctor public NetworkKey(android.net.WifiKey);
method public int describeContents();
@@ -5552,6 +5556,7 @@
package android.telephony.ims {
public final class ImsCallForwardInfo implements android.os.Parcelable {
+ ctor public ImsCallForwardInfo(int, int, int, int, java.lang.String, int);
method public int describeContents();
method public int getCondition();
method public java.lang.String getNumber();
@@ -5866,7 +5871,7 @@
}
public final class ImsSsData implements android.os.Parcelable {
- ctor public ImsSsData();
+ ctor public ImsSsData(int, int, int, int, int);
method public int describeContents();
method public boolean isTypeBarring();
method public boolean isTypeCf();
@@ -5917,7 +5922,7 @@
}
public final class ImsSsInfo implements android.os.Parcelable {
- ctor public ImsSsInfo();
+ ctor public ImsSsInfo(int, java.lang.String);
method public int describeContents();
method public java.lang.String getIcbNum();
method public int getStatus();
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 2b85ec0..c6e561f 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -34,11 +34,11 @@
FdBuffer::~FdBuffer() {}
-status_t FdBuffer::read(unique_fd* fd, int64_t timeout) {
- struct pollfd pfds = {.fd = fd->get(), .events = POLLIN};
+status_t FdBuffer::read(int fd, int64_t timeout) {
+ struct pollfd pfds = {.fd = fd, .events = POLLIN};
mStartTime = uptimeMillis();
- fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
while (true) {
if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
@@ -67,16 +67,16 @@
VLOG("return event has error %s", strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
} else {
- ssize_t amt = ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
+ ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
- VLOG("Fail to read %d: %s", fd->get(), strerror(errno));
+ VLOG("Fail to read %d: %s", fd, strerror(errno));
return -errno;
}
} else if (amt == 0) {
- VLOG("Reached EOF of fd=%d", fd->get());
+ VLOG("Reached EOF of fd=%d", fd);
break;
}
mBuffer.wp()->move(amt);
@@ -87,7 +87,7 @@
return NO_ERROR;
}
-status_t FdBuffer::readFully(unique_fd* fd) {
+status_t FdBuffer::readFully(int fd) {
mStartTime = uptimeMillis();
while (true) {
@@ -99,10 +99,10 @@
}
if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
- ssize_t amt = TEMP_FAILURE_RETRY(
- ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()));
+ ssize_t amt =
+ TEMP_FAILURE_RETRY(::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite()));
if (amt < 0) {
- VLOG("Fail to read %d: %s", fd->get(), strerror(errno));
+ VLOG("Fail to read %d: %s", fd, strerror(errno));
return -errno;
} else if (amt == 0) {
VLOG("Done reading %zu bytes", mBuffer.size());
@@ -116,20 +116,20 @@
return NO_ERROR;
}
-status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd,
+status_t FdBuffer::readProcessedDataInStream(int fd, unique_fd toFd, unique_fd fromFd,
int64_t timeoutMs, const bool isSysfs) {
struct pollfd pfds[] = {
- {.fd = fd->get(), .events = POLLIN},
- {.fd = toFd->get(), .events = POLLOUT},
- {.fd = fromFd->get(), .events = POLLIN},
+ {.fd = fd, .events = POLLIN},
+ {.fd = toFd.get(), .events = POLLOUT},
+ {.fd = fromFd.get(), .events = POLLIN},
};
mStartTime = uptimeMillis();
// mark all fds non blocking
- fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK);
- fcntl(toFd->get(), F_SETFL, fcntl(toFd->get(), F_GETFL, 0) | O_NONBLOCK);
- fcntl(fromFd->get(), F_SETFL, fcntl(fromFd->get(), F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+ fcntl(toFd.get(), F_SETFL, fcntl(toFd.get(), F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fromFd.get(), F_SETFL, fcntl(fromFd.get(), F_GETFL, 0) | O_NONBLOCK);
// A circular buffer holds data read from fd and writes to parsing process
uint8_t cirBuf[BUFFER_SIZE];
@@ -166,10 +166,10 @@
for (int i = 0; i < 3; ++i) {
if ((pfds[i].revents & POLLERR) != 0) {
if (i == 0 && isSysfs) {
- VLOG("fd %d is sysfs, ignore its POLLERR return value", fd->get());
+ VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
continue;
}
- VLOG("fd[%d]=%d returns error events: %s", i, fd->get(), strerror(errno));
+ VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
}
}
@@ -178,17 +178,17 @@
if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) {
ssize_t amt;
if (rpos >= wpos) {
- amt = ::read(fd->get(), cirBuf + rpos, BUFFER_SIZE - rpos);
+ amt = ::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos);
} else {
- amt = ::read(fd->get(), cirBuf + rpos, wpos - rpos);
+ amt = ::read(fd, cirBuf + rpos, wpos - rpos);
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- VLOG("Fail to read fd %d: %s", fd->get(), strerror(errno));
+ VLOG("Fail to read fd %d: %s", fd, strerror(errno));
return -errno;
} // otherwise just continue
} else if (amt == 0) {
- VLOG("Reached EOF of input file %d", fd->get());
+ VLOG("Reached EOF of input file %d", fd);
pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0].
} else {
rpos += amt;
@@ -200,13 +200,13 @@
if (cirSize > 0 && pfds[1].fd != -1) {
ssize_t amt;
if (rpos > wpos) {
- amt = ::write(toFd->get(), cirBuf + wpos, rpos - wpos);
+ amt = ::write(toFd.get(), cirBuf + wpos, rpos - wpos);
} else {
- amt = ::write(toFd->get(), cirBuf + wpos, BUFFER_SIZE - wpos);
+ amt = ::write(toFd.get(), cirBuf + wpos, BUFFER_SIZE - wpos);
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- VLOG("Fail to write toFd %d: %s", toFd->get(), strerror(errno));
+ VLOG("Fail to write toFd.get() %d: %s", toFd.get(), strerror(errno));
return -errno;
} // otherwise just continue
} else {
@@ -217,8 +217,8 @@
// if buffer is empty and fd is closed, close write fd.
if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) {
- VLOG("Close write pipe %d", toFd->get());
- toFd->reset();
+ VLOG("Close write pipe %d", toFd.get());
+ toFd.reset();
pfds[1].fd = -1;
}
@@ -231,14 +231,14 @@
}
// read from parsing process
- ssize_t amt = ::read(fromFd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
+ ssize_t amt = ::read(fromFd.get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- VLOG("Fail to read fromFd %d: %s", fromFd->get(), strerror(errno));
+ VLOG("Fail to read fromFd.get() %d: %s", fromFd.get(), strerror(errno));
return -errno;
} // otherwise just continue
} else if (amt == 0) {
- VLOG("Reached EOF of fromFd %d", fromFd->get());
+ VLOG("Reached EOF of fromFd.get() %d", fromFd.get());
break;
} else {
mBuffer.wp()->move(amt);
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index db3a74b..f467da8 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -40,13 +40,13 @@
* Returns NO_ERROR if there were no errors or if we timed out.
* Will mark the file O_NONBLOCK.
*/
- status_t read(unique_fd* fd, int64_t timeoutMs);
+ status_t read(int fd, int64_t timeoutMs);
/**
* Read the data until we hit eof.
* Returns NO_ERROR if there were no errors.
*/
- status_t readFully(unique_fd* fd);
+ status_t readFully(int fd);
/**
* Read processed results by streaming data to a parsing process, e.g. incident helper.
@@ -58,8 +58,8 @@
*
* Poll will return POLLERR if fd is from sysfs, handle this edge case.
*/
- status_t readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd,
- int64_t timeoutMs, const bool isSysfs = false);
+ status_t readProcessedDataInStream(int fd, unique_fd toFd, unique_fd fromFd, int64_t timeoutMs,
+ const bool isSysfs = false);
/**
* Whether we timed out.
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index aeccefd..d02b4dd 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -352,8 +352,7 @@
printPrivacy(p, out, String8(""));
} else if (opt == "parse") {
FdBuffer buf;
- unique_fd infd(fileno(in));
- status_t error = buf.read(&infd, 60000);
+ status_t error = buf.read(fileno(in), 60000);
if (error != NO_ERROR) {
fprintf(err, "Error reading from stdin\n");
return error;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 3b57d34..3f693fa 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -264,8 +264,9 @@
}
// parent process
- status_t readStatus = buffer.readProcessedDataInStream(
- &fd, &p2cPipe.writeFd(), &c2pPipe.readFd(), this->timeoutMs, mIsSysfs);
+ status_t readStatus = buffer.readProcessedDataInStream(fd.get(), std::move(p2cPipe.writeFd()),
+ std::move(c2pPipe.readFd()),
+ this->timeoutMs, mIsSysfs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
@@ -319,8 +320,10 @@
index++; // look at the next file.
}
VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd.get());
- if (fd.get() == -1) return -1;
-
+ if (fd.get() == -1) {
+ ALOGW("GZipSection %s can't open all the files", this->name.string());
+ return NO_ERROR; // e.g. LAST_KMSG will reach here in user build.
+ }
FdBuffer buffer;
Fpipe p2cPipe;
Fpipe c2pPipe;
@@ -354,9 +357,9 @@
VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos,
dataBeginAt);
- status_t readStatus =
- buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), &c2pPipe.readFd(),
- this->timeoutMs, isSysfs(mFilenames[index]));
+ status_t readStatus = buffer.readProcessedDataInStream(
+ fd.get(), std::move(p2cPipe.writeFd()), std::move(c2pPipe.readFd()), this->timeoutMs,
+ isSysfs(mFilenames[index]));
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s",
@@ -466,7 +469,7 @@
pthread_attr_destroy(&attr);
// Loop reading until either the timeout or the worker side is done (i.e. eof).
- err = buffer.read(&data->pipe.readFd(), this->timeoutMs);
+ err = buffer.read(data->pipe.readFd().get(), this->timeoutMs);
if (err != NO_ERROR) {
// TODO: Log this error into the incident report.
ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
@@ -573,7 +576,7 @@
}
cmdPipe.writeFd().reset();
- status_t readStatus = buffer.read(&ihPipe.readFd(), this->timeoutMs);
+ status_t readStatus = buffer.read(ihPipe.readFd().get(), this->timeoutMs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s",
this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
@@ -892,7 +895,7 @@
// Parent process.
// Read from the pipe concurrently to avoid blocking the child.
FdBuffer buffer;
- err = buffer.readFully(&dumpPipe.readFd());
+ err = buffer.readFully(dumpPipe.readFd().get());
if (err != NO_ERROR) {
ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err);
dumpPipe.readFd().reset();
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index bf77017..7a05d7e 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -37,7 +37,6 @@
public:
virtual void SetUp() override {
ASSERT_NE(tf.fd, -1);
- tffd.reset(tf.fd);
ASSERT_NE(p2cPipe.init(), -1);
ASSERT_NE(c2pPipe.init(), -1);
}
@@ -57,13 +56,13 @@
EXPECT_EQ(expected[i], '\0');
}
- bool DoDataStream(unique_fd* rFd, unique_fd* wFd) {
+ bool DoDataStream(const unique_fd& rFd, const unique_fd& wFd) {
char buf[BUFFER_SIZE];
ssize_t nRead;
- while ((nRead = read(rFd->get(), buf, BUFFER_SIZE)) > 0) {
+ while ((nRead = read(rFd.get(), buf, BUFFER_SIZE)) > 0) {
ssize_t nWritten = 0;
while (nWritten < nRead) {
- ssize_t amt = write(wFd->get(), buf + nWritten, nRead - nWritten);
+ ssize_t amt = write(wFd.get(), buf + nWritten, nRead - nWritten);
if (amt < 0) {
return false;
}
@@ -76,7 +75,6 @@
protected:
FdBuffer buffer;
TemporaryFile tf;
- unique_fd tffd;
Fpipe p2cPipe;
Fpipe c2pPipe;
@@ -87,7 +85,7 @@
TEST_F(FdBufferTest, ReadAndWrite) {
std::string testdata = "FdBuffer test string";
ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
- ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
AssertBufferReadSuccessful(testdata.size());
AssertBufferContent(testdata.c_str());
}
@@ -100,7 +98,7 @@
TEST_F(FdBufferTest, ReadAndIterate) {
std::string testdata = "FdBuffer test string";
ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
- ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
int i = 0;
EncodedBuffer::iterator it = buffer.data();
@@ -128,7 +126,7 @@
} else {
c2pPipe.writeFd().reset();
- status_t status = buffer.read(&c2pPipe.readFd(), QUICK_TIMEOUT_MS);
+ status_t status = buffer.read(c2pPipe.readFd().get(), QUICK_TIMEOUT_MS);
ASSERT_EQ(NO_ERROR, status);
EXPECT_TRUE(buffer.timedOut());
@@ -148,7 +146,7 @@
p2cPipe.writeFd().reset();
c2pPipe.readFd().reset();
ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
- ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+ ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
// Must exit here otherwise the child process will continue executing the test binary.
@@ -157,8 +155,9 @@
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
- &c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR,
+ buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
+ std::move(c2pPipe.readFd()), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -189,8 +188,9 @@
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
- &c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR,
+ buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
+ std::move(c2pPipe.readFd()), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -206,7 +206,7 @@
if (pid == 0) {
p2cPipe.writeFd().reset();
c2pPipe.readFd().reset();
- ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+ ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
_exit(EXIT_SUCCESS);
@@ -214,8 +214,9 @@
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
- &c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR,
+ buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
+ std::move(c2pPipe.readFd()), READ_TIMEOUT));
AssertBufferReadSuccessful(0);
AssertBufferContent("");
wait(&pid);
@@ -233,7 +234,7 @@
if (pid == 0) {
p2cPipe.writeFd().reset();
c2pPipe.readFd().reset();
- ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+ ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
_exit(EXIT_SUCCESS);
@@ -241,8 +242,9 @@
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(),
- &c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR,
+ buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
+ std::move(c2pPipe.readFd()), READ_TIMEOUT));
EXPECT_EQ(buffer.size(), fourMB);
EXPECT_FALSE(buffer.timedOut());
EXPECT_TRUE(buffer.truncated());
@@ -278,8 +280,9 @@
p2cPipe.readFd().reset();
c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
- &c2pPipe.readFd(), QUICK_TIMEOUT_MS));
+ ASSERT_EQ(NO_ERROR,
+ buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
+ std::move(c2pPipe.readFd()), QUICK_TIMEOUT_MS));
EXPECT_TRUE(buffer.timedOut());
kill(pid, SIGKILL); // reap the child process
}
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 5edc0c7..10c2981 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -38,7 +38,7 @@
const uint8_t MESSAGE_TYPE = 11;
const string STRING_FIELD_0 = "\x02\viamtestdata";
const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
-const string STRING_FIELD_2 = "\x12\vwhatthefuck";
+const string STRING_FIELD_2 = "\x12\vandroidwins";
const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
@@ -58,8 +58,7 @@
void writeToFdBuffer(string str) {
ASSERT_TRUE(WriteStringToFile(str, tf.path));
- unique_fd tffd(tf.fd);
- ASSERT_EQ(NO_ERROR, buffer.read(&tffd, 10000));
+ ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
ASSERT_EQ(str.size(), buffer.size());
}
@@ -274,4 +273,4 @@
autoMsg->children = list;
string expected = "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(DEST_AUTOMATIC, expected, 1, autoMsg);
-}
\ No newline at end of file
+}
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index f93839b..2f6698b 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -19,6 +19,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <android/os/IncidentReportArgs.h>
+#include <android/util/protobuf.h>
#include <frameworks/base/libs/incident/proto/android/os/header.pb.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -31,12 +32,13 @@
const int QUICK_TIMEOUT_MS = 100;
const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
-const string STRING_FIELD_2 = "\x12\vwhatthefuck";
+const string STRING_FIELD_2 = "\x12\vandroidwins";
const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
using namespace android::base;
using namespace android::binder;
using namespace android::os;
+using namespace android::util;
using namespace std;
using ::testing::StrEq;
using ::testing::Test;
@@ -154,17 +156,26 @@
requests.setMainDest(android::os::DEST_LOCAL);
ASSERT_EQ(NO_ERROR, gs.Execute(&requests));
- std::string expect, gzFile, actual;
+ std::string expected, gzFile, actual;
ASSERT_TRUE(ReadFileToString(testGzFile, &gzFile));
ASSERT_TRUE(ReadFileToString(tf.path, &actual));
- expect = "\x2\xC6\x6\n\"" + testFile + "\x12\x9F\x6" + gzFile;
- EXPECT_THAT(actual, StrEq(expect));
+ // generates the expected protobuf result.
+ size_t fileLen = testFile.size();
+ size_t totalLen = 1 + get_varint_size(fileLen) + fileLen + 3 + gzFile.size();
+ uint8_t header[20];
+ header[0] = '\x2'; // header 0 << 3 + 2
+ uint8_t* ptr = write_raw_varint(header + 1, totalLen);
+ *ptr = '\n'; // header 1 << 3 + 2
+ ptr = write_raw_varint(++ptr, fileLen);
+ expected.assign((const char*)header, ptr - header);
+ expected += testFile + "\x12\x9F\x6" + gzFile;
+ EXPECT_THAT(actual, StrEq(expected));
}
TEST_F(SectionTest, GZipSectionNoFileFound) {
GZipSection gs(NOOP_PARSER, "/tmp/nonexist1", "/tmp/nonexist2", NULL);
requests.setMainFd(STDOUT_FILENO);
- ASSERT_EQ(-1, gs.Execute(&requests));
+ ASSERT_EQ(NO_ERROR, gs.Execute(&requests));
}
TEST_F(SectionTest, CommandSectionConstructor) {
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index b67764b..50b05cd 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -127,25 +127,25 @@
}
AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
- const string& name, ActivityForegroundStateChanged::Activity activity) {
+ const string& name, ActivityForegroundStateChanged::State state) {
AtomMatcher atom_matcher;
atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
field_value_matcher->set_field(4); // Activity field.
- field_value_matcher->set_eq_int(activity);
+ field_value_matcher->set_eq_int(state);
return atom_matcher;
}
AtomMatcher CreateMoveToBackgroundAtomMatcher() {
return CreateActivityForegroundStateChangedAtomMatcher(
- "MoveToBackground", ActivityForegroundStateChanged::MOVE_TO_BACKGROUND);
+ "MoveToBackground", ActivityForegroundStateChanged::BACKGROUND);
}
AtomMatcher CreateMoveToForegroundAtomMatcher() {
return CreateActivityForegroundStateChangedAtomMatcher(
- "MoveToForeground", ActivityForegroundStateChanged::MOVE_TO_FOREGROUND);
+ "MoveToForeground", ActivityForegroundStateChanged::FOREGROUND);
}
Predicate CreateScheduledJobPredicate() {
@@ -315,25 +315,25 @@
}
std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
- const int uid, const ActivityForegroundStateChanged::Activity activity, uint64_t timestampNs) {
+ const int uid, const ActivityForegroundStateChanged::State state, uint64_t timestampNs) {
auto event = std::make_unique<LogEvent>(
android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs);
event->write(uid);
event->write("pkg_name");
event->write("class_name");
- event->write(activity);
+ event->write(state);
event->init();
return event;
}
std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) {
return CreateActivityForegroundStateChangedEvent(
- uid, ActivityForegroundStateChanged::MOVE_TO_BACKGROUND, timestampNs);
+ uid, ActivityForegroundStateChanged::BACKGROUND, timestampNs);
}
std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) {
return CreateActivityForegroundStateChangedEvent(
- uid, ActivityForegroundStateChanged::MOVE_TO_FOREGROUND, timestampNs);
+ uid, ActivityForegroundStateChanged::FOREGROUND, timestampNs);
}
std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index cfb9d87..7fe8e62 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
-// TODO: Not the right package and class name
package android.os.statsd;
option java_package = "com.android.os";
option java_outer_classname = "AtomsProto";
@@ -49,7 +48,7 @@
oneof pushed {
// For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
BleScanStateChanged ble_scan_state_changed = 2;
- // TODO: 3 is blank, but need not be
+ // 3 is available for use
BleScanResultReceived ble_scan_result_received = 4;
SensorStateChanged sensor_state_changed = 5;
GpsScanStateChanged gps_scan_state_changed = 6;
@@ -60,12 +59,12 @@
LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 11;
MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12;
WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13;
- // TODO: 14-19 are blank, but need not be
+ // 14 - 19 are available
BatterySaverModeStateChanged battery_saver_mode_state_changed = 20;
DeviceIdleModeStateChanged device_idle_mode_state_changed = 21;
DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22;
AudioStateChanged audio_state_changed = 23;
- MediaCodecActivityChanged media_codec_activity_changed = 24;
+ MediaCodecStateChanged media_codec_state_changed = 24;
CameraStateChanged camera_state_changed = 25;
FlashlightStateChanged flashlight_state_changed = 26;
UidProcessStateChanged uid_process_state_changed = 27;
@@ -74,8 +73,7 @@
BatteryLevelChanged battery_level_changed = 30;
ChargingStateChanged charging_state_changed = 31;
PluggedStateChanged plugged_state_changed = 32;
- // TODO: 33 is blank, but is available for use.
- DeviceOnStatusChanged device_on_status_changed = 34;
+ // 33 - 34 are available
WakeupAlarmOccurred wakeup_alarm_occurred = 35;
KernelWakeupReported kernel_wakeup_reported = 36;
WifiLockStateChanged wifi_lock_state_changed = 37;
@@ -86,12 +84,12 @@
ActivityForegroundStateChanged activity_foreground_state_changed = 42;
IsolatedUidChanged isolated_uid_changed = 43;
PacketWakeupOccurred packet_wakeup_occurred = 44;
- DropboxErrorChanged dropbox_error_changed = 45;
+ // 45 is available
AnomalyDetected anomaly_detected = 46;
AppBreadcrumbReported app_breadcrumb_reported = 47;
- AppStartChanged app_start_changed = 48;
- AppStartCancelChanged app_start_cancel_changed = 49;
- AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50;
+ AppStartOccurred app_start_occurred = 48;
+ AppStartCanceled app_start_canceled = 49;
+ AppStartFullyDrawn app_start_fully_drawn = 50;
LmkKillOccurred lmk_kill_occurred = 51;
PictureInPictureStateChanged picture_in_picture_state_changed = 52;
WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53;
@@ -106,7 +104,7 @@
KeyguardStateChanged keyguard_state_changed = 62;
KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63;
KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64;
- AppDied app_died=65;
+ AppDied app_died = 65;
ResourceConfigurationChanged resource_configuration_changed = 66;
BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67;
BluetoothConnectionStateChanged bluetooth_connection_state_changed = 68;
@@ -119,6 +117,12 @@
MobileConnectionStateChanged mobile_connection_state_changed = 75;
MobileRadioTechnologyChanged mobile_radio_technology_changed = 76;
UsbDeviceAttached usb_device_attached = 77;
+ AppCrashOccurred app_crash_occurred = 78;
+ ANROccurred anr_occurred = 79;
+ WTFOccurred wtf_occurred = 80;
+ LowMemReported low_mem_reported = 81;
+
+
}
// Pulled events will start at field 10000.
@@ -134,7 +138,7 @@
CpuTimePerFreq cpu_time_per_freq = 10008;
CpuTimePerUid cpu_time_per_uid = 10009;
CpuTimePerUidFreq cpu_time_per_uid_freq = 10010;
- WifiActivityEnergyInfo wifi_activity_energy_info = 10011;
+ WifiActivityInfo wifi_activity_info = 10011;
ModemActivityInfo modem_activity_info = 10012;
BluetoothActivityInfo bluetooth_activity_info = 10007;
ProcessMemoryState process_memory_state = 10013;
@@ -224,21 +228,19 @@
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message ProcessLifeCycleStateChanged {
- // TODO: should be a string tagged w/ uid annotation
optional int32 uid = 1 [(is_uid) = true];
// The process name (usually same as the app name).
- optional string name = 2;
+ optional string process_name = 2;
// What lifecycle state the process changed to.
// This enum is specific to atoms.proto.
- enum Event {
- PROCESS_FINISHED = 0;
- PROCESS_STARTED = 1;
- PROCESS_CRASHED = 2;
- PROCESS_ANRED = 3;
+ enum State {
+ FINISHED = 0;
+ STARTED = 1;
+ CRASHED = 2;
}
- optional Event event = 3;
+ optional State state = 3;
}
/**
@@ -247,7 +249,6 @@
* Logged from:
* packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
*/
-// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
message BleScanStateChanged {
repeated AttributionNode attribution_node = 1;
@@ -278,7 +279,7 @@
repeated AttributionNode attribution_node = 1;
// Number of ble scan results returned.
- optional int32 num_of_results = 2;
+ optional int32 num_results = 2;
}
/**
@@ -290,7 +291,6 @@
message SensorStateChanged {
repeated AttributionNode attribution_node = 1;
- // TODO: Is there a way to get the actual name of the sensor?
// The id (int) of the sensor.
optional int32 sensor_id = 2;
@@ -329,7 +329,7 @@
repeated AttributionNode attribution_node = 1;
// Name of the sync (as named in the app). Can be chosen at run-time.
- optional string name = 2;
+ optional string sync_name = 2;
enum State {
OFF = 0;
@@ -348,7 +348,7 @@
repeated AttributionNode attribution_node = 1;
// Name of the job (as named in the app)
- optional string name = 2;
+ optional string job_name = 2;
enum State {
FINISHED = 0;
@@ -387,7 +387,7 @@
* Logged from:
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
-message MediaCodecActivityChanged {
+message MediaCodecStateChanged {
repeated AttributionNode attribution_node = 1;
enum State {
@@ -561,22 +561,6 @@
optional android.os.BatteryPluggedStateEnum state = 1;
}
-// TODO: Define this more precisely.
-// TODO: Log the ON state somewhere. It isn't currently logged anywhere.
-/**
- * Logs when the device turns off or on.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message DeviceOnStatusChanged {
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 1;
-}
-
/**
* Logs when an app's wakeup alarm fires.
*
@@ -598,8 +582,7 @@
* frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message MobileRadioPowerStateChanged {
- // TODO: Add attribution instead of uid?
- optional int32 uid = 1 [(is_uid) = true];
+ repeated AttributionNode attribution_node = 1;
// Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
optional android.telephony.DataConnectionPowerStateEnum state = 2;
@@ -613,8 +596,7 @@
* frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message WifiRadioPowerStateChanged {
- // TODO: Add attribution instead of uid?
- optional int32 uid = 1 [(is_uid) = true];
+ repeated AttributionNode attribution_node = 1;
// Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
optional android.telephony.DataConnectionPowerStateEnum state = 2;
@@ -1154,7 +1136,6 @@
message DaveyOccurred {
// The UID that logged this atom.
optional int32 uid = 1 [(is_uid) = true];
- ;
// Amount of time it took to render the frame. Should be >=700ms.
optional int64 jank_duration_millis = 2;
@@ -1221,42 +1202,70 @@
optional string pkg_name = 2;
optional string class_name = 3;
- enum Activity {
- MOVE_TO_BACKGROUND = 0;
- MOVE_TO_FOREGROUND = 1;
+ enum State {
+ BACKGROUND = 0;
+ FOREGROUND = 1;
}
- optional Activity activity = 4;
+ optional State state = 4;
}
/**
- * Logs when an error is written to dropbox.
+ * Logs when an app crashes.
* Logged from:
* frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
*/
-message DropboxErrorChanged {
- // The uid if available. -1 means not available.
+message AppCrashOccurred {
optional int32 uid = 1 [(is_uid) = true];
- // Tag used when recording this error to dropbox. Contains data_ or system_ prefix.
- optional string tag = 2;
+ optional string event_type = 2;
// The name of the process.
+ // system_server if it is not by an app
optional string process_name = 3;
// The pid if available. -1 means not available.
optional sint32 pid = 4;
+}
- // 1 indicates is instant app. -1 indicates Not applicable.
- optional sint32 is_instant_app = 5;
+/**
+ * Logs when a WTF (What a Terrible Failure) happened.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message WTFOccurred {
+ optional int32 uid = 1 [(is_uid) = true];
- // The activity name if available.
- optional string activity_name = 6;
+ optional string tag = 2;
- // The package name if available.
- optional string package_name = 7;
+ // The name of the process.
+ // system_server if it is not by an app
+ optional string process_name = 3;
- // 1 indicates in foreground. -1 indicates not available.
- optional sint32 is_foreground = 8;
+ // The pid if available. -1 means not available.
+ optional sint32 pid = 4;
+}
+
+/**
+ * Logs when system server reports low memory.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message LowMemReported {
+}
+
+/**
+ * Logs when an app ANR (App Not Responding) occurs.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/AppErrors.java
+ */
+message ANROccurred {
+ optional int32 uid = 1 [(is_uid) = true];
+
+ optional string process_name = 2;
+
+ optional string short_component_name = 3;
+
+ optional string reason = 4;
}
/*
@@ -1299,7 +1308,7 @@
optional int64 alert_id = 3;
}
-message AppStartChanged {
+message AppStartOccurred {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
@@ -1307,7 +1316,7 @@
optional string pkg_name = 2;
enum TransitionType {
- APP_START_TRANSITION_TYPE_UNKNOWN = 0;
+ UNKNOWN = 0;
WARM = 1;
HOT = 2;
COLD = 3;
@@ -1346,7 +1355,7 @@
optional int32 package_optimization_compilation_reason = 15;
}
-message AppStartCancelChanged {
+message AppStartCanceled {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
@@ -1354,7 +1363,7 @@
optional string pkg_name = 2;
enum TransitionType {
- APP_START_TRANSITION_TYPE_UNKNOWN = 0;
+ UNKNOWN = 0;
WARM = 1;
HOT = 2;
COLD = 3;
@@ -1366,7 +1375,7 @@
optional string activity_name = 4;
}
-message AppStartFullyDrawnChanged {
+message AppStartFullyDrawn {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
@@ -1374,7 +1383,7 @@
optional string pkg_name = 2;
enum TransitionType {
- APP_START_TRANSITION_TYPE_UNKNOWN = 0;
+ UNKNOWN = 0;
WITH_BUNDLE = 1;
WITHOUT_BUNDLE = 2;
}
@@ -1459,8 +1468,8 @@
* frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message IsolatedUidChanged {
- // NOTE: DO NOT annotate uid field in this atom. This atom is specially handled in statsd.
// The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
+ // NOTE: DO NOT annotate uid field in this atom. This atom is specially handled in statsd.
optional int32 parent_uid = 1;
optional int32 isolated_uid = 2;
@@ -1621,9 +1630,8 @@
message WifiBytesTransferByFgBg {
optional int32 uid = 1 [(is_uid) = true];
- // 1 denotes foreground and 0 denotes background. This is called Set in
- // NetworkStats.
- optional int32 is_foreground = 2;
+ // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ optional bool is_foreground = 2;
optional int64 rx_bytes = 3;
@@ -1663,7 +1671,7 @@
// 1 denotes foreground and 0 denotes background. This is called Set in
// NetworkStats.
- optional int32 is_foreground = 2;
+ optional bool is_foreground = 2;
optional int64 rx_bytes = 3;
@@ -1760,7 +1768,7 @@
/**
* Pulls Wifi Controller Activity Energy Info
*/
-message WifiActivityEnergyInfo {
+message WifiActivityInfo {
// timestamp(wall clock) of record creation
optional uint64 timestamp_millis = 1;
// stack reported state
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 0e23bf0..2f0e885 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -120,11 +120,11 @@
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
// wifi_activity_energy_info
- {android::util::WIFI_ACTIVITY_ENERGY_INFO,
+ {android::util::WIFI_ACTIVITY_INFO,
{{},
{},
1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
+ new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}},
// modem_activity_info
{android::util::MODEM_ACTIVITY_INFO,
{{},
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index ef637df..22ff942 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -76,6 +76,7 @@
const int FIELD_ID_CONFIG_STATS_CONDITION_STATS = 14;
const int FIELD_ID_CONFIG_STATS_METRIC_STATS = 15;
const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16;
+const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17;
const int FIELD_ID_MATCHER_STATS_ID = 1;
const int FIELD_ID_MATCHER_STATS_COUNT = 2;
@@ -255,6 +256,20 @@
}
}
+void StatsdStats::noteMetricDimensionInConditionSize(
+ const ConfigKey& key, const int64_t& id, int size) {
+ lock_guard<std::mutex> lock(mLock);
+ // if name doesn't exist before, it will create the key with count 0.
+ auto statsIt = mConfigStats.find(key);
+ if (statsIt == mConfigStats.end()) {
+ return;
+ }
+ auto& metricsDimensionMap = statsIt->second->metric_dimension_in_condition_stats;
+ if (size > metricsDimensionMap[id]) {
+ metricsDimensionMap[id] = size;
+ }
+}
+
void StatsdStats::noteMatcherMatched(const ConfigKey& key, const int64_t& id) {
lock_guard<std::mutex> lock(mLock);
@@ -339,6 +354,7 @@
config.second->matcher_stats.clear();
config.second->condition_stats.clear();
config.second->metric_stats.clear();
+ config.second->metric_dimension_in_condition_stats.clear();
config.second->alert_stats.clear();
}
}
@@ -504,6 +520,13 @@
proto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_STATS_COUNT, pair.second);
proto->end(tmpToken);
}
+ for (const auto& pair : configStats.metric_dimension_in_condition_stats) {
+ uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_STATS_ID, (long long)pair.first);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_STATS_COUNT, pair.second);
+ proto->end(tmpToken);
+ }
for (const auto& pair : configStats.alert_stats) {
uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 7f8755b..bd395c4 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -57,6 +57,12 @@
// it means some data has been dropped. The map size is capped by kMaxConfigCount.
std::map<const int64_t, int> metric_stats;
+ // Stores the max number of output tuple of dimensions in condition across dimensions in what
+ // when it's bigger than kDimensionKeySizeSoftLimit. When you see the number is
+ // kDimensionKeySizeHardLimit +1, it means some data has been dropped. The map size is capped by
+ // kMaxConfigCount.
+ std::map<const int64_t, int> metric_dimension_in_condition_stats;
+
// Stores the number of times an anomaly detection alert has been declared.
// The map size is capped by kMaxConfigCount.
std::map<const int64_t, int> alert_stats;
@@ -183,6 +189,19 @@
*/
void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
+
+ /**
+ * Report the max size of output tuple of dimension in condition across dimensions in what.
+ *
+ * Note: only report when the metric has an output dimension in condition, and the max tuple
+ * count > kDimensionKeySizeSoftLimit.
+ *
+ * [key]: The config key that this metric belongs to.
+ * [id]: The id of the metric.
+ * [size]: The output tuple size.
+ */
+ void noteMetricDimensionInConditionSize(const ConfigKey& key, const int64_t& id, int size);
+
/**
* Report a matcher has been matched.
*
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index c28bb88..f02f307 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -308,11 +308,14 @@
if (mMetric2ConditionLinks.size() == 0 ||
trueDim.contains(linkedConditionDimensionKey)) {
if (!whatIt.second.empty()) {
+ auto newEventKey = MetricDimensionKey(whatIt.first, trueDim);
+ if (hitGuardRailLocked(newEventKey)) {
+ continue;
+ }
unique_ptr<DurationTracker> newTracker =
whatIt.second.begin()->second->clone(eventTime);
if (newTracker != nullptr) {
- newTracker->setEventKey(
- MetricDimensionKey(whatIt.first, trueDim));
+ newTracker->setEventKey(newEventKey);
newTracker->onConditionChanged(true, eventTime);
whatIt.second[trueDim] = std::move(newTracker);
}
@@ -370,11 +373,14 @@
for (const auto& conditionDimension : conditionDimensionsKeySet) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
if (!whatIt.second.empty()) {
+ auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension);
+ if (hitGuardRailLocked(newEventKey)) {
+ continue;
+ }
unique_ptr<DurationTracker> newTracker =
whatIt.second.begin()->second->clone(eventTime);
if (newTracker != nullptr) {
- newTracker->setEventKey(MetricDimensionKey(
- whatIt.first, conditionDimension));
+ newTracker->setEventKey(MetricDimensionKey(newEventKey));
newTracker->onSlicedConditionMayChange(overallCondition, eventTime);
whatIt.second[conditionDimension] = std::move(newTracker);
}
@@ -397,10 +403,13 @@
for (const auto& conditionDimension : conditionDimensionsKeys) {
if (!whatIt.second.empty() &&
whatIt.second.find(conditionDimension) == whatIt.second.end()) {
+ auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension);
+ if (hitGuardRailLocked(newEventKey)) {
+ continue;
+ }
auto newTracker = whatIt.second.begin()->second->clone(eventTime);
if (newTracker != nullptr) {
- newTracker->setEventKey(
- MetricDimensionKey(whatIt.first, conditionDimension));
+ newTracker->setEventKey(newEventKey);
newTracker->onSlicedConditionMayChange(overallCondition, eventTime);
whatIt.second[conditionDimension] = std::move(newTracker);
}
@@ -552,15 +561,35 @@
}
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
- // 1. Report the tuple count if the tuple count > soft limit
- if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
- size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
- // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
- if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("DurationMetric %lld dropping data for dimension key %s",
- (long long)mMetricId, newKey.toString().c_str());
- return true;
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ auto condIt = whatIt->second.find(newKey.getDimensionKeyInCondition());
+ if (condIt != whatIt->second.end()) {
+ return false;
+ }
+ if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+ size_t newTupleCount = whatIt->second.size() + 1;
+ StatsdStats::getInstance().noteMetricDimensionInConditionSize(
+ mConfigKey, mMetricId, newTupleCount);
+ // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+ if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+ ALOGE("DurationMetric %lld dropping data for condition dimension key %s",
+ (long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str());
+ return true;
+ }
+ }
+ } else {
+ // 1. Report the tuple count if the tuple count > soft limit
+ if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+ size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
+ StatsdStats::getInstance().noteMetricDimensionSize(
+ mConfigKey, mMetricId, newTupleCount);
+ // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+ if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+ ALOGE("DurationMetric %lld dropping data for what dimension key %s",
+ (long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str());
+ return true;
+ }
}
}
return false;
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index dd3b37c..a25df3f 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -241,6 +241,7 @@
repeated ConditionStats condition_stats = 14;
repeated MetricStats metric_stats = 15;
repeated AlertStats alert_stats = 16;
+ repeated MetricStats metric_dimension_in_condition_stats = 17;
}
repeated ConfigStats config_stats = 3;
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
index 920273b..3a0c224 100644
--- a/cmds/statsd/statsd.rc
+++ b/cmds/statsd/statsd.rc
@@ -20,5 +20,5 @@
on post-fs-data
# Create directory for statsd
- mkdir /data/misc/stats-data/ 0770 statsd statsd
- mkdir /data/misc/stats-service/ 0770 statsd statsd
+ mkdir /data/misc/stats-data/ 0770 statsd system
+ mkdir /data/misc/stats-service/ 0770 statsd system
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index 73e7c44..5a6aba6 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -356,7 +356,7 @@
EXPECT_EQ("location1", atom.attribution_node(0).tag());
EXPECT_EQ(2222, atom.attribution_node(1).uid());
EXPECT_EQ("location2", atom.attribution_node(1).tag());
- EXPECT_EQ(999, atom.num_of_results());
+ EXPECT_EQ(999, atom.num_results());
}
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 2e6a0f0..2b91324 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -34,7 +34,7 @@
*config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
*config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
- auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_CHANGED);
+ auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_OCCURRED);
*config.add_atom_matcher() = atomMatcher;
auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
@@ -49,18 +49,18 @@
gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
gaugeMetric->set_sampling_type(sampling_type);
auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
- fieldMatcher->set_field(android::util::APP_START_CHANGED);
+ fieldMatcher->set_field(android::util::APP_START_OCCURRED);
fieldMatcher->add_child()->set_field(3); // type (enum)
fieldMatcher->add_child()->set_field(4); // activity_name(str)
fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
*gaugeMetric->mutable_dimensions_in_what() =
- CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
+ CreateDimensions(android::util::APP_START_OCCURRED, {1 /* uid field */ });
gaugeMetric->set_bucket(FIVE_MINUTES);
auto links = gaugeMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
auto dimensionWhat = links->mutable_fields_in_what();
- dimensionWhat->set_field(android::util::APP_START_CHANGED);
+ dimensionWhat->set_field(android::util::APP_START_OCCURRED);
dimensionWhat->add_child()->set_field(1); // uid field.
auto dimensionCondition = links->mutable_fields_in_condition();
dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
@@ -68,12 +68,12 @@
return config;
}
-std::unique_ptr<LogEvent> CreateAppStartChangedEvent(
- const int uid, const string& pkg_name, AppStartChanged::TransitionType type,
+std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
+ const int uid, const string& pkg_name, AppStartOccurred::TransitionType type,
const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
int64_t activity_start_msec, uint64_t timestampNs) {
auto logEvent = std::make_unique<LogEvent>(
- android::util::APP_START_CHANGED, timestampNs);
+ android::util::APP_START_OCCURRED, timestampNs);
logEvent->write(uid);
logEvent->write(pkg_name);
logEvent->write(type);
@@ -112,32 +112,32 @@
appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::WARM, "activity_name1", "calling_pkg_name1",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid1, "app1", AppStartOccurred::WARM, "activity_name1", "calling_pkg_name1",
true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::HOT, "activity_name2", "calling_pkg_name2",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid1, "app1", AppStartOccurred::HOT, "activity_name2", "calling_pkg_name2",
true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::COLD, "activity_name3", "calling_pkg_name3",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid1, "app1", AppStartOccurred::COLD, "activity_name3", "calling_pkg_name3",
true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::WARM, "activity_name4", "calling_pkg_name4",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid1, "app1", AppStartOccurred::WARM, "activity_name4", "calling_pkg_name4",
true /*is_instant_app*/, 104 /*activity_start_msec*/,
bucketStartTimeNs + bucketSizeNs + 30));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::COLD, "activity_name5", "calling_pkg_name5",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid1, "app1", AppStartOccurred::COLD, "activity_name5", "calling_pkg_name5",
true /*is_instant_app*/, 105 /*activity_start_msec*/,
bucketStartTimeNs + 2 * bucketSizeNs));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::HOT, "activity_name6", "calling_pkg_name6",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid1, "app1", AppStartOccurred::HOT, "activity_name6", "calling_pkg_name6",
false /*is_instant_app*/, 106 /*activity_start_msec*/,
bucketStartTimeNs + 2 * bucketSizeNs + 10));
events.push_back(CreateMoveToBackgroundEvent(
appUid2, bucketStartTimeNs + bucketSizeNs + 10));
- events.push_back(CreateAppStartChangedEvent(
- appUid2, "app2", AppStartChanged::COLD, "activity_name7", "calling_pkg_name7",
+ events.push_back(CreateAppStartOccurredEvent(
+ appUid2, "app2", AppStartOccurred::COLD, "activity_name7", "calling_pkg_name7",
true /*is_instant_app*/, 201 /*activity_start_msec*/,
bucketStartTimeNs + 2 * bucketSizeNs + 10));
@@ -159,7 +159,7 @@
EXPECT_EQ(2, gaugeMetrics.data_size());
auto data = gaugeMetrics.data(0);
- EXPECT_EQ(android::util::APP_START_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -171,29 +171,29 @@
EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::HOT, data.bucket_info(0).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::HOT, data.bucket_info(0).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name2",
- data.bucket_info(0).atom(0).app_start_changed().activity_name());
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
EXPECT_EQ(102L,
- data.bucket_info(0).atom(0).app_start_changed().activity_start_millis());
- EXPECT_EQ(AppStartChanged::COLD,
- data.bucket_info(0).atom(1).app_start_changed().type());
+ data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(0).atom(1).app_start_occurred().type());
EXPECT_EQ("activity_name3",
- data.bucket_info(0).atom(1).app_start_changed().activity_name());
+ data.bucket_info(0).atom(1).app_start_occurred().activity_name());
EXPECT_EQ(103L,
- data.bucket_info(0).atom(1).app_start_changed().activity_start_millis());
+ data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
EXPECT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::WARM,
- data.bucket_info(1).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::WARM,
+ data.bucket_info(1).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name4",
- data.bucket_info(1).atom(0).app_start_changed().activity_name());
+ data.bucket_info(1).atom(0).app_start_occurred().activity_name());
EXPECT_EQ(104L,
- data.bucket_info(1).atom(0).app_start_changed().activity_start_millis());
+ data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
EXPECT_EQ(2, data.bucket_info(2).atom_size());
EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
@@ -202,41 +202,41 @@
data.bucket_info(2).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
data.bucket_info(2).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::COLD,
- data.bucket_info(2).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(2).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name5",
- data.bucket_info(2).atom(0).app_start_changed().activity_name());
+ data.bucket_info(2).atom(0).app_start_occurred().activity_name());
EXPECT_EQ(105L,
- data.bucket_info(2).atom(0).app_start_changed().activity_start_millis());
- EXPECT_EQ(AppStartChanged::HOT,
- data.bucket_info(2).atom(1).app_start_changed().type());
+ data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(2).atom(1).app_start_occurred().type());
EXPECT_EQ("activity_name6",
- data.bucket_info(2).atom(1).app_start_changed().activity_name());
+ data.bucket_info(2).atom(1).app_start_occurred().activity_name());
EXPECT_EQ(106L,
- data.bucket_info(2).atom(1).app_start_changed().activity_start_millis());
+ data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
} else {
EXPECT_EQ(1, data.bucket_info(0).atom_size());
EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::HOT, data.bucket_info(0).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::HOT, data.bucket_info(0).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name2",
- data.bucket_info(0).atom(0).app_start_changed().activity_name());
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
EXPECT_EQ(102L,
- data.bucket_info(0).atom(0).app_start_changed().activity_start_millis());
+ data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
EXPECT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::WARM,
- data.bucket_info(1).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::WARM,
+ data.bucket_info(1).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name4",
- data.bucket_info(1).atom(0).app_start_changed().activity_name());
+ data.bucket_info(1).atom(0).app_start_occurred().activity_name());
EXPECT_EQ(104L,
- data.bucket_info(1).atom(0).app_start_changed().activity_start_millis());
+ data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
EXPECT_EQ(1, data.bucket_info(2).atom_size());
EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
@@ -245,17 +245,17 @@
data.bucket_info(2).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
data.bucket_info(2).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::COLD,
- data.bucket_info(2).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(2).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name5",
- data.bucket_info(2).atom(0).app_start_changed().activity_name());
+ data.bucket_info(2).atom(0).app_start_occurred().activity_name());
EXPECT_EQ(105L,
- data.bucket_info(2).atom(0).app_start_changed().activity_start_millis());
+ data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
}
data = gaugeMetrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -266,10 +266,10 @@
EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_nanos());
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
- EXPECT_EQ(AppStartChanged::COLD, data.bucket_info(0).atom(0).app_start_changed().type());
+ EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
EXPECT_EQ("activity_name7",
- data.bucket_info(0).atom(0).app_start_changed().activity_name());
- EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_changed().activity_start_millis());
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
}
}
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 5c4eda8..04ce73a7 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -210,7 +210,7 @@
stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 1);
stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 2);
- stats.noteAtomLogged(android::util::DROPBOX_ERROR_CHANGED, now + 3);
+ stats.noteAtomLogged(android::util::APP_CRASH_OCCURRED, now + 3);
// pulled event, should ignore
stats.noteAtomLogged(android::util::WIFI_BYTES_TRANSFER, now + 4);
@@ -228,7 +228,7 @@
if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
sensorAtomGood = true;
}
- if (atomStats.tag() == android::util::DROPBOX_ERROR_CHANGED && atomStats.count() == 1) {
+ if (atomStats.tag() == android::util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
dropboxAtomGood = true;
}
}
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index ce44a35..6621500 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -152,42 +152,42 @@
}
AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
- const string& name, ActivityForegroundStateChanged::Activity activity) {
+ const string& name, ActivityForegroundStateChanged::State state) {
AtomMatcher atom_matcher;
atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
field_value_matcher->set_field(4); // Activity field.
- field_value_matcher->set_eq_int(activity);
+ field_value_matcher->set_eq_int(state);
return atom_matcher;
}
AtomMatcher CreateMoveToBackgroundAtomMatcher() {
return CreateActivityForegroundStateChangedAtomMatcher(
- "MoveToBackground", ActivityForegroundStateChanged::MOVE_TO_BACKGROUND);
+ "Background", ActivityForegroundStateChanged::BACKGROUND);
}
AtomMatcher CreateMoveToForegroundAtomMatcher() {
return CreateActivityForegroundStateChangedAtomMatcher(
- "MoveToForeground", ActivityForegroundStateChanged::MOVE_TO_FOREGROUND);
+ "Foreground", ActivityForegroundStateChanged::FOREGROUND);
}
AtomMatcher CreateProcessLifeCycleStateChangedAtomMatcher(
- const string& name, ProcessLifeCycleStateChanged::Event event) {
+ const string& name, ProcessLifeCycleStateChanged::State state) {
AtomMatcher atom_matcher;
atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
field_value_matcher->set_field(3); // Process state field.
- field_value_matcher->set_eq_int(event);
+ field_value_matcher->set_eq_int(state);
return atom_matcher;
}
AtomMatcher CreateProcessCrashAtomMatcher() {
return CreateProcessLifeCycleStateChangedAtomMatcher(
- "ProcessCrashed", ProcessLifeCycleStateChanged::PROCESS_CRASHED);
+ "Crashed", ProcessLifeCycleStateChanged::CRASHED);
}
Predicate CreateScheduledJobPredicate() {
@@ -241,8 +241,8 @@
Predicate CreateIsInBackgroundPredicate() {
Predicate predicate;
predicate.set_id(StringToId("IsInBackground"));
- predicate.mutable_simple_predicate()->set_start(StringToId("MoveToBackground"));
- predicate.mutable_simple_predicate()->set_stop(StringToId("MoveToForeground"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("Background"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("Foreground"));
return predicate;
}
@@ -373,25 +373,25 @@
}
std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
- const int uid, const ActivityForegroundStateChanged::Activity activity, uint64_t timestampNs) {
+ const int uid, const ActivityForegroundStateChanged::State state, uint64_t timestampNs) {
auto event = std::make_unique<LogEvent>(
android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs);
event->write(uid);
event->write("pkg_name");
event->write("class_name");
- event->write(activity);
+ event->write(state);
event->init();
return event;
}
std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) {
return CreateActivityForegroundStateChangedEvent(
- uid, ActivityForegroundStateChanged::MOVE_TO_BACKGROUND, timestampNs);
+ uid, ActivityForegroundStateChanged::BACKGROUND, timestampNs);
}
std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) {
return CreateActivityForegroundStateChangedEvent(
- uid, ActivityForegroundStateChanged::MOVE_TO_FOREGROUND, timestampNs);
+ uid, ActivityForegroundStateChanged::FOREGROUND, timestampNs);
}
std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(
@@ -418,19 +418,19 @@
}
std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
- const int uid, const ProcessLifeCycleStateChanged::Event event, uint64_t timestampNs) {
+ const int uid, const ProcessLifeCycleStateChanged::State state, uint64_t timestampNs) {
auto logEvent = std::make_unique<LogEvent>(
android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, timestampNs);
logEvent->write(uid);
logEvent->write("");
- logEvent->write(event);
+ logEvent->write(state);
logEvent->init();
return logEvent;
}
std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampNs) {
return CreateProcessLifeCycleStateChangedEvent(
- uid, ProcessLifeCycleStateChanged::PROCESS_CRASHED, timestampNs);
+ uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs);
}
std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
diff --git a/core/java/android/app/AppComponentFactory.java b/core/java/android/app/AppComponentFactory.java
index 4df7379..cfaeec9 100644
--- a/core/java/android/app/AppComponentFactory.java
+++ b/core/java/android/app/AppComponentFactory.java
@@ -36,6 +36,10 @@
* Allows application to override the creation of the application object. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes.
+ * <p>
+ * This method is only intended to provide a hook for instantiation. It does not provide
+ * earlier access to the Application object. The returned object will not be initialized
+ * as a Context yet and should not be used to interact with other android APIs.
*
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
@@ -50,6 +54,10 @@
* Allows application to override the creation of activities. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes.
+ * <p>
+ * This method is only intended to provide a hook for instantiation. It does not provide
+ * earlier access to the Activity object. The returned object will not be initialized
+ * as a Context yet and should not be used to interact with other android APIs.
*
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
@@ -80,6 +88,10 @@
* Allows application to override the creation of services. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes.
+ * <p>
+ * This method is only intended to provide a hook for instantiation. It does not provide
+ * earlier access to the Service object. The returned object will not be initialized
+ * as a Context yet and should not be used to interact with other android APIs.
*
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
@@ -95,6 +107,10 @@
* Allows application to override the creation of providers. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes.
+ * <p>
+ * This method is only intended to provide a hook for instantiation. It does not provide
+ * earlier access to the ContentProvider object. The returned object will not be initialized
+ * with a Context yet and should not be used to interact with other android APIs.
*
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
@@ -108,5 +124,5 @@
/**
* @hide
*/
- public static AppComponentFactory DEFAULT = new AppComponentFactory();
+ public static final AppComponentFactory DEFAULT = new AppComponentFactory();
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3c6f135..b64aae5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2747,110 +2747,6 @@
}
/**
- * The maximum number of characters allowed in the password blacklist.
- */
- private static final int PASSWORD_BLACKLIST_CHARACTER_LIMIT = 128 * 1000;
-
- /**
- * Throws an exception if the password blacklist is too large.
- *
- * @hide
- */
- public static void enforcePasswordBlacklistSize(List<String> blacklist) {
- if (blacklist == null) {
- return;
- }
- long characterCount = 0;
- for (final String item : blacklist) {
- characterCount += item.length();
- }
- if (characterCount > PASSWORD_BLACKLIST_CHARACTER_LIMIT) {
- throw new IllegalArgumentException("128 thousand blacklist character limit exceeded by "
- + (characterCount - PASSWORD_BLACKLIST_CHARACTER_LIMIT) + " characters");
- }
- }
-
- /**
- * Called by an application that is administering the device to blacklist passwords.
- * <p>
- * Any blacklisted password or PIN is prevented from being enrolled by the user or the admin.
- * Note that the match against the blacklist is case insensitive. The blacklist applies for all
- * password qualities requested by {@link #setPasswordQuality} however it is not taken into
- * consideration by {@link #isActivePasswordSufficient}.
- * <p>
- * The blacklist can be cleared by passing {@code null} or an empty list. The blacklist is
- * given a name that is used to track which blacklist is currently set by calling {@link
- * #getPasswordBlacklistName}. If the blacklist is being cleared, the name is ignored and {@link
- * #getPasswordBlacklistName} will return {@code null}. The name can only be {@code null} when
- * the blacklist is being cleared.
- * <p>
- * The blacklist is limited to a total of 128 thousand characters rather than limiting to a
- * number of entries.
- * <p>
- * This method can be called on the {@link DevicePolicyManager} instance returned by
- * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
- * profile.
- *
- * @param admin the {@link DeviceAdminReceiver} this request is associated with
- * @param name name to associate with the blacklist
- * @param blacklist list of passwords to blacklist or {@code null} to clear the blacklist
- * @return whether the new blacklist was successfully installed
- * @throws SecurityException if {@code admin} is not a device or profile owner
- * @throws IllegalArgumentException if the blacklist surpasses the character limit
- * @throws NullPointerException if {@code name} is {@code null} when setting a non-empty list
- *
- * @see #getPasswordBlacklistName
- * @see #isActivePasswordSufficient
- * @see #resetPasswordWithToken
- */
- public boolean setPasswordBlacklist(@NonNull ComponentName admin, @Nullable String name,
- @Nullable List<String> blacklist) {
- enforcePasswordBlacklistSize(blacklist);
-
- try {
- return mService.setPasswordBlacklist(admin, name, blacklist, mParentInstance);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the name of the password blacklist set by the given admin.
- *
- * @param admin the {@link DeviceAdminReceiver} this request is associated with
- * @return the name of the blacklist or {@code null} if no blacklist is set
- *
- * @see #setPasswordBlacklist
- */
- public @Nullable String getPasswordBlacklistName(@NonNull ComponentName admin) {
- try {
- return mService.getPasswordBlacklistName(admin, myUserId(), mParentInstance);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
- /**
- * Test if a given password is blacklisted.
- *
- * @param userId the user to valiate for
- * @param password the password to check against the blacklist
- * @return whether the password is blacklisted
- *
- * @see #setPasswordBlacklist
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.TEST_BLACKLISTED_PASSWORD)
- public boolean isPasswordBlacklisted(@UserIdInt int userId, @NonNull String password) {
- try {
- return mService.isPasswordBlacklisted(userId, password);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
- /**
* Determine whether the current password the user has set is sufficient to meet the policy
* requirements (e.g. quality, minimum length) that have been requested by the admins of this
* user and its participating profiles. Restrictions on profiles that have a separate challenge
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 4b39a9a..37508cd 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -79,10 +79,6 @@
long getPasswordExpiration(in ComponentName who, int userHandle, boolean parent);
- boolean setPasswordBlacklist(in ComponentName who, String name, in List<String> blacklist, boolean parent);
- String getPasswordBlacklistName(in ComponentName who, int userId, boolean parent);
- boolean isPasswordBlacklisted(int userId, String password);
-
boolean isActivePasswordSufficient(int userHandle, boolean parent);
boolean isProfileActivePasswordSufficientForParent(int userHandle);
boolean isUsingUnifiedPassword(in ComponentName admin);
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index db98ff8..0285e9f 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -82,6 +82,17 @@
* An activity can be statically linked to a slice uri by including a meta-data item
* for this key that contains a valid slice uri for the same application declaring
* the activity.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <activity android:name="com.example.mypkg.MyActivity">
+ * <meta-data android:name="android.metadata.SLICE_URI"
+ * android:value="content://com.example.mypkg/main_slice" />
+ * </activity>}
+ * </pre>
+ *
+ * @see #mapIntentToUri(Intent)
+ * @see SliceProvider#onMapIntentToUri(Intent)
*/
public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
@@ -258,16 +269,17 @@
* <p>
* This goes through a several stage resolution process to determine if any slice
* can represent this intent.
- * - If the intent contains data that {@link ContentResolver#getType} is
- * {@link SliceProvider#SLICE_TYPE} then the data will be returned.
- * - If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
+ * <ol>
+ * <li> If the intent contains data that {@link ContentResolver#getType} is
+ * {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
+ * <li>If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
* the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
- * will be returned.
- * - Lastly, if the intent explicitly points at an activity, and that activity has
+ * will be returned.</li>
+ * <li>Lastly, if the intent explicitly points at an activity, and that activity has
* meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
- * returned.
- * - If no slice is found, then {@code null} is returned.
- *
+ * returned.</li>
+ * <li>If no slice is found, then {@code null} is returned.</li>
+ * </ol>
* @param intent The intent associated with a slice.
* @return The Slice Uri provided by the app or null if none exists.
* @see Slice
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 57f0588..8034bb6 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -56,7 +56,8 @@
* new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
* <p>Keys for this algorithm must be 128 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 128.
*/
public static final String AUTH_HMAC_MD5 = "hmac(md5)";
@@ -65,7 +66,8 @@
* new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
* <p>Keys for this algorithm must be 160 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 160.
*/
public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
@@ -73,7 +75,8 @@
* SHA256 HMAC Authentication/Integrity Algorithm.
*
* <p>Keys for this algorithm must be 256 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 256.
*/
public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
@@ -81,7 +84,8 @@
* SHA384 HMAC Authentication/Integrity Algorithm.
*
* <p>Keys for this algorithm must be 384 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to 384.
*/
public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
@@ -89,7 +93,8 @@
* SHA512 HMAC Authentication/Integrity Algorithm.
*
* <p>Keys for this algorithm must be 512 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to 512.
*/
public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
@@ -112,6 +117,7 @@
AUTH_HMAC_MD5,
AUTH_HMAC_SHA1,
AUTH_HMAC_SHA256,
+ AUTH_HMAC_SHA384,
AUTH_HMAC_SHA512,
AUTH_CRYPT_AES_GCM
})
@@ -126,11 +132,14 @@
* Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
* defined as constants in this class.
*
+ * <p>For algorithms that produce an integrity check value, the truncation length is a required
+ * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)}
+ *
* @param algorithm name of the algorithm.
* @param key key padded to a multiple of 8 bits.
*/
public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
- this(algorithm, key, key.length * 8);
+ this(algorithm, key, 0);
}
/**
@@ -228,6 +237,7 @@
case AUTH_CRYPT_AES_GCM:
// The keying material for GCM is a key plus a 32-bit salt
isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
+ isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128;
break;
default:
throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index a88fe04..1525508 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -274,7 +274,8 @@
*
* @param destinationAddress the destination address for traffic bearing the requested SPI.
* For inbound traffic, the destination should be an address currently assigned on-device.
- * @param requestedSpi the requested SPI, or '0' to allocate a random SPI
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is
+ * reserved and may not be used. See RFC 4303 Section 2.1.
* @return the reserved SecurityParameterIndex
* @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
* currently allocated for this user
@@ -502,7 +503,7 @@
* signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
* IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
* caller. The caller should not close the {@code FileDescriptor} returned by {@link
- * #getSocket}, but should use {@link #close} instead.
+ * #getFileDescriptor}, but should use {@link #close} instead.
*
* <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
* of the next user who binds to that port. To prevent this scenario, these sockets are held
@@ -541,8 +542,8 @@
mCloseGuard.open("constructor");
}
- /** Get the wrapped socket. */
- public FileDescriptor getSocket() {
+ /** Get the encapsulation socket's file descriptor. */
+ public FileDescriptor getFileDescriptor() {
if (mPfd == null) {
return null;
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ff5714b..374b3ab 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -276,6 +277,7 @@
* this network can be used by system apps to upload telemetry data.
* @hide
*/
+ @SystemApi
public static final int NET_CAPABILITY_OEM_PAID = 22;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 4f92fa6..caefd89 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -17,6 +17,8 @@
package android.net;
import android.annotation.NonNull;
+import android.net.NetworkCapabilities.NetCapability;
+import android.net.NetworkCapabilities.Transport;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -427,6 +429,20 @@
return type == Type.BACKGROUND_REQUEST;
}
+ /**
+ * @see Builder#addCapability(int)
+ */
+ public boolean hasCapability(@NetCapability int capability) {
+ return networkCapabilities.hasCapability(capability);
+ }
+
+ /**
+ * @see Builder#addTransportType(int)
+ */
+ public boolean hasTransport(@Transport int transportType) {
+ return networkCapabilities.hasTransport(transportType);
+ }
+
public String toString() {
return "NetworkRequest [ " + type + " id=" + requestId +
(legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b7f6cde..b0367dc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11061,7 +11061,14 @@
*/
public static final String LOW_POWER_MODE_TRIGGER_LEVEL_MAX = "low_power_trigger_level_max";
- /**
+ /**
+ * See com.android.settingslib.fuelgauge.BatterySaverUtils.
+ * @hide
+ */
+ public static final String LOW_POWER_MODE_SUGGESTION_PARAMS =
+ "low_power_mode_suggestion_params";
+
+ /**
* If not 0, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
* extended lifetime is used.
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 1d13335..f4dcce1 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -75,6 +75,7 @@
public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
+ public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -216,6 +217,7 @@
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
+ public static final int KM_ERROR_DEVICE_LOCKED = -72;
public static final int KM_ERROR_UNIMPLEMENTED = -100;
public static final int KM_ERROR_VERSION_MISMATCH = -101;
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -262,6 +264,7 @@
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
"Invalid MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
+ sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/security/keystore/RecoveryController.java b/core/java/android/security/keystore/RecoveryController.java
index d50424d..741af12 100644
--- a/core/java/android/security/keystore/RecoveryController.java
+++ b/core/java/android/security/keystore/RecoveryController.java
@@ -443,16 +443,7 @@
*/
public byte[] generateAndStoreKey(@NonNull String alias)
throws InternalRecoveryServiceException, LockScreenRequiredException {
- try {
- return mBinder.generateAndStoreKey(alias);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } catch (ServiceSpecificException e) {
- if (e.errorCode == ERROR_INSECURE_USER) {
- throw new LockScreenRequiredException(e.getMessage());
- }
- throw wrapUnexpectedServiceSpecificException(e);
- }
+ throw new UnsupportedOperationException();
}
/**
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index e46c34c..9334aa9 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -78,23 +78,8 @@
private byte[] mEncryptedRecoveryKeyBlob;
/**
- * @hide
- * Deprecated, consider using builder.
+ * Use builder to create an instance of the class.
*/
- public KeyChainSnapshot(
- int snapshotVersion,
- @NonNull List<KeyChainProtectionParams> keyChainProtectionParams,
- @NonNull List<WrappedApplicationKey> wrappedApplicationKeys,
- @NonNull byte[] encryptedRecoveryKeyBlob) {
- mSnapshotVersion = snapshotVersion;
- mKeyChainProtectionParams =
- Preconditions.checkCollectionElementsNotNull(keyChainProtectionParams,
- "KeyChainProtectionParams");
- mEntryRecoveryData = Preconditions.checkCollectionElementsNotNull(wrappedApplicationKeys,
- "wrappedApplicationKeys");
- mEncryptedRecoveryKeyBlob = Preconditions.checkNotNull(encryptedRecoveryKeyBlob);
- }
-
private KeyChainSnapshot() {
}
@@ -108,7 +93,7 @@
}
/**
- * Number of user secret guesses allowed during Keychain recovery.
+ * Number of user secret guesses allowed during KeyChain recovery.
*/
public int getMaxAttempts() {
return mMaxAttempts;
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index fd80bb0..5165f0c 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -106,7 +106,7 @@
/**
* @hide
*/
- KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt,
+ private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt,
int memoryDifficulty) {
mAlgorithm = algorithm;
mSalt = Preconditions.checkNotNull(salt);
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index ca5f967..a006fa6 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -577,16 +577,7 @@
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
throws InternalRecoveryServiceException, LockScreenRequiredException {
- try {
- return mBinder.generateAndStoreKey(alias);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } catch (ServiceSpecificException e) {
- if (e.errorCode == ERROR_INSECURE_USER) {
- throw new LockScreenRequiredException(e.getMessage());
- }
- throw wrapUnexpectedServiceSpecificException(e);
- }
+ throw new UnsupportedOperationException("Operation is not supported, use generateKey");
}
/**
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 0690bd5..80845d9 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -157,8 +157,8 @@
* @param vaultChallenge Data passed from server for this recovery session and used to prevent
* replay attacks.
* @param secrets Secrets provided by user, the method only uses type and secret fields.
- * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
- * encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
+ * @return The binary blob with recovery claim. It is encrypted with verifierPublicKey
+ * and contains a proof of user secrets possession, session symmetric
* key and parameters necessary to identify the counter with the number of failed recovery
* attempts.
* @throws CertificateException if the {@code verifierCertPath} is invalid.
@@ -228,7 +228,8 @@
*
* @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
* @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
- * and session.
+ * and session key generated by {@link #start}.
+ * @return {@code Map} from recovered keys aliases to their references.
* @throws SessionExpiredException if {@code session} has since been closed.
* @throws DecryptionFailedException if unable to decrypt the snapshot.
* @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
@@ -288,8 +289,7 @@
}
/**
- * Deletes all data associated with {@code session}. Should not be invoked directly but via
- * {@link RecoverySession#close()}.
+ * Deletes all data associated with {@code session}.
*/
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@Override
diff --git a/core/java/android/service/notification/ScheduleCalendar.java b/core/java/android/service/notification/ScheduleCalendar.java
index 8a7ff4d..0128710 100644
--- a/core/java/android/service/notification/ScheduleCalendar.java
+++ b/core/java/android/service/notification/ScheduleCalendar.java
@@ -144,7 +144,8 @@
}
return mSchedule.exitAtAlarm
&& mSchedule.nextAlarm != 0
- && time >= mSchedule.nextAlarm;
+ && time >= mSchedule.nextAlarm
+ && isInSchedule(mSchedule.nextAlarm);
}
private boolean isInSchedule(int daysOffset, long time, long start, long end) {
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 4431bcef1..758cd2b 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -62,6 +62,7 @@
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -457,6 +458,7 @@
// get the version code, but don't do anything with it: creator knew about all our flags
porBuf.getInt();
+ HashSet<X509Certificate> certHistorySet = new HashSet<>();
while (porBuf.hasRemaining()) {
levelCount++;
ByteBuffer level = getLengthPrefixedSlice(porBuf);
@@ -495,6 +497,12 @@
lastCert = new VerbatimX509Certificate(lastCert, encodedCert);
lastSigAlgorithm = sigAlgorithm;
+ if (certHistorySet.contains(lastCert)) {
+ throw new SecurityException("Encountered duplicate entries in "
+ + "Proof-of-rotation record at certificate #" + levelCount + ". All "
+ + "signing certificates should be unique");
+ }
+ certHistorySet.add(lastCert);
certs.add(lastCert);
flagsList.add(flags);
}
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 3b8fc5c..f15e1a1 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -72,22 +72,31 @@
signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
long dataSize = apk.length() - signingBlockSize;
int[] levelOffset = calculateVerityLevelOffset(dataSize);
+ int merkleTreeSize = levelOffset[levelOffset.length - 1];
ByteBuffer output = bufferFactory.create(
- CHUNK_SIZE_BYTES + // fsverity header + extensions + padding
- levelOffset[levelOffset.length - 1]); // Merkle tree size
+ merkleTreeSize
+ + CHUNK_SIZE_BYTES); // maximum size of fsverity metadata
output.order(ByteOrder.LITTLE_ENDIAN);
- ByteBuffer header = slice(output, 0, FSVERITY_HEADER_SIZE_BYTES);
- ByteBuffer extensions = slice(output, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES);
- ByteBuffer tree = slice(output, CHUNK_SIZE_BYTES, output.limit());
+ ByteBuffer tree = slice(output, 0, merkleTreeSize);
+ ByteBuffer header = slice(output, merkleTreeSize,
+ merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES);
+ ByteBuffer extensions = slice(output, merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES,
+ merkleTreeSize + CHUNK_SIZE_BYTES);
byte[] apkDigestBytes = new byte[DIGEST_SIZE_BYTES];
ByteBuffer apkDigest = ByteBuffer.wrap(apkDigestBytes);
apkDigest.order(ByteOrder.LITTLE_ENDIAN);
+ // NB: Buffer limit is set inside once finished.
calculateFsveritySignatureInternal(apk, signatureInfo, tree, apkDigest, header, extensions);
- output.rewind();
+ // Put the reverse offset to fs-verity header at the end.
+ output.position(merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES + extensions.limit());
+ output.putInt(FSVERITY_HEADER_SIZE_BYTES + extensions.limit()
+ + 4); // size of this integer right before EOF
+ output.flip();
+
return new ApkVerityResult(output, apkDigestBytes);
}
@@ -101,7 +110,8 @@
ByteBuffer verityBlock = ByteBuffer.allocate(CHUNK_SIZE_BYTES)
.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer header = slice(verityBlock, 0, FSVERITY_HEADER_SIZE_BYTES);
- ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES);
+ ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES,
+ CHUNK_SIZE_BYTES - FSVERITY_HEADER_SIZE_BYTES);
calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);
@@ -328,10 +338,10 @@
buffer.put((byte) 12); // log2(block-size): log2(4096)
buffer.put((byte) 7); // log2(leaves-per-node): log2(4096 / 32)
- buffer.putShort((short) 1); // meta algorithm, SHA256_MODE == 1
- buffer.putShort((short) 1); // data algorithm, SHA256_MODE == 1
+ buffer.putShort((short) 1); // meta algorithm, SHA256 == 1
+ buffer.putShort((short) 1); // data algorithm, SHA256 == 1
- buffer.putInt(0x0); // flags
+ buffer.putInt(0); // flags
buffer.putInt(0); // reserved
buffer.putLong(fileSize); // original file size
@@ -362,12 +372,11 @@
//
// struct fsverity_extension_patch {
// __le64 offset;
- // u8 length;
- // u8 reserved[7];
// u8 databytes[];
// };
final int kSizeOfFsverityExtensionHeader = 8;
+ final int kExtensionSizeAlignment = 8;
{
// struct fsverity_extension #1
@@ -385,24 +394,25 @@
{
// struct fsverity_extension #2
- final int kSizeOfFsverityPatchExtension =
- 8 + // offset size
- 1 + // size of length from offset (up to 255)
- 7 + // reserved
- ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
- final int kPadding = (int) divideRoundup(kSizeOfFsverityPatchExtension % 8, 8);
+ final int kTotalSize = kSizeOfFsverityExtensionHeader
+ + 8 // offset size
+ + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
- buffer.putShort((short) // total size of extension, padded to 64-bit alignment
- (kSizeOfFsverityExtensionHeader + kSizeOfFsverityPatchExtension + kPadding));
+ buffer.putShort((short) kTotalSize);
buffer.put((byte) 1); // ID of patch extension
skip(buffer, 5); // reserved
// struct fsverity_extension_patch
- buffer.putLong(eocdOffset); // offset
- buffer.put((byte) ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE); // length
- skip(buffer, 7); // reserved
- buffer.putInt(Math.toIntExact(signingBlockOffset)); // databytes
- skip(buffer, kPadding); // padding
+ buffer.putLong(eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET); // offset
+ buffer.putInt(Math.toIntExact(signingBlockOffset)); // databytes
+
+ // The extension needs to be 0-padded at the end, since the length may not be multiple
+ // of 8.
+ int kPadding = kExtensionSizeAlignment - kTotalSize % kExtensionSizeAlignment;
+ if (kPadding == kExtensionSizeAlignment) {
+ kPadding = 0;
+ }
+ skip(buffer, kPadding); // padding
}
buffer.flip();
diff --git a/core/java/android/util/apk/VerbatimX509Certificate.java b/core/java/android/util/apk/VerbatimX509Certificate.java
index 9984c6d..391c5fc 100644
--- a/core/java/android/util/apk/VerbatimX509Certificate.java
+++ b/core/java/android/util/apk/VerbatimX509Certificate.java
@@ -18,6 +18,7 @@
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
/**
* For legacy reasons we need to return exactly the original encoded certificate bytes, instead
@@ -25,6 +26,7 @@
*/
class VerbatimX509Certificate extends WrappedX509Certificate {
private final byte[] mEncodedVerbatim;
+ private int mHash = -1;
VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) {
super(wrapped);
@@ -35,4 +37,30 @@
public byte[] getEncoded() throws CertificateEncodingException {
return mEncodedVerbatim;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof VerbatimX509Certificate)) return false;
+
+ try {
+ byte[] a = this.getEncoded();
+ byte[] b = ((VerbatimX509Certificate) o).getEncoded();
+ return Arrays.equals(a, b);
+ } catch (CertificateEncodingException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ if (mHash == -1) {
+ try {
+ mHash = Arrays.hashCode(this.getEncoded());
+ } catch (CertificateEncodingException e) {
+ mHash = 0;
+ }
+ }
+ return mHash;
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f6c669b..ea3710c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13917,11 +13917,15 @@
mAttachInfo.mUnbufferedDispatchRequested = true;
}
+ private boolean hasSize() {
+ return (mBottom > mTop) && (mRight > mLeft);
+ }
+
private boolean canTakeFocus() {
return ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
&& ((mViewFlags & FOCUSABLE) == FOCUSABLE)
&& ((mViewFlags & ENABLED_MASK) == ENABLED)
- && (sCanFocusZeroSized || !isLayoutValid() || (mBottom > mTop) && (mRight > mLeft));
+ && (sCanFocusZeroSized || !isLayoutValid() || hasSize());
}
/**
@@ -13982,7 +13986,7 @@
|| focusableChangedByAuto == 0
|| viewRootImpl == null
|| viewRootImpl.mThread == Thread.currentThread()) {
- shouldNotifyFocusableAvailable = true;
+ shouldNotifyFocusableAvailable = canTakeFocus();
}
}
}
@@ -14001,11 +14005,10 @@
needGlobalAttributesUpdate(true);
- // a view becoming visible is worth notifying the parent
- // about in case nothing has focus. even if this specific view
- // isn't focusable, it may contain something that is, so let
- // the root view try to give this focus if nothing else does.
- shouldNotifyFocusableAvailable = true;
+ // a view becoming visible is worth notifying the parent about in case nothing has
+ // focus. Even if this specific view isn't focusable, it may contain something that
+ // is, so let the root view try to give this focus if nothing else does.
+ shouldNotifyFocusableAvailable = hasSize();
}
}
@@ -14014,16 +14017,14 @@
// a view becoming enabled should notify the parent as long as the view is also
// visible and the parent wasn't already notified by becoming visible during this
// setFlags invocation.
- shouldNotifyFocusableAvailable = true;
+ shouldNotifyFocusableAvailable = canTakeFocus();
} else {
if (isFocused()) clearFocus();
}
}
- if (shouldNotifyFocusableAvailable) {
- if (mParent != null && canTakeFocus()) {
- mParent.focusableViewAvailable(this);
- }
+ if (shouldNotifyFocusableAvailable && mParent != null) {
+ mParent.focusableViewAvailable(this);
}
/* Check if the GONE bit has changed */
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 59b14f1..ae7ba19 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -61,7 +61,6 @@
void initRecoveryServiceWithSigFile(in String rootCertificateAlias,
in byte[] recoveryServiceCertFile, in byte[] recoveryServiceSigFile);
KeyChainSnapshot getKeyChainSnapshot();
- byte[] generateAndStoreKey(String alias);
String generateKey(String alias);
String importKey(String alias, in byte[] keyBytes);
String getKey(String alias);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 51dd929..e8fc598 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1000,6 +1000,11 @@
setPatternInProgress(false);
cancelLineAnimations();
notifyPatternDetected();
+ // Also clear pattern if fading is enabled
+ if (mFadePattern) {
+ clearPatternDrawLookup();
+ mPatternDisplayMode = DisplayMode.Correct;
+ }
invalidate();
}
if (PROFILE_DRAWING) {
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index c9bfa13..7f90d8e 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -448,8 +448,9 @@
jboolean hasAlpha, jlong paintHandle) {
// Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
// correct the alphaType to kOpaque_SkAlphaType.
- SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType,
- GraphicsJNI::defaultColorSpace());
+ SkImageInfo info = SkImageInfo::Make(width, height,
+ hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
+ kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.setInfo(info);
sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 0fea0dc..ea0b825 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -175,9 +175,9 @@
];
optional GZippedFileProto last_kmsg = 2007 [
- (section).type = SECTION_NONE, // disable until selinux permission is gained
+ (section).type = SECTION_GZIP,
(section).args = "/sys/fs/pstore/console-ramoops /sys/fs/pstore/console-ramoops-0 /proc/last_kmsg",
- (privacy).dest = DEST_AUTOMATIC
+ (privacy).dest = DEST_EXPLICIT
];
// System Services
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 449d3e7..c63f319 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -33,11 +33,16 @@
a light UI more visible. -->
<drawable name="screen_background_light_transparent">#80ffffff</drawable>
<color name="safe_mode_text">#80ffffff</color>
+ <!-- The color white, equivalent to 0xffffffff -->
<color name="white">#ffffffff</color>
+ <!-- The color black, equivalent to 0xff000000 -->
<color name="black">#ff000000</color>
<color name="red">#ffff0000</color>
+ <!-- Fully transparent, equivalent to 0x00000000 -->
<color name="transparent">#00000000</color>
+ <!-- Equivalent to 0xff000000 -->
<color name="background_dark">#ff000000</color>
+ <!-- Equivalent to 0xffffffff -->
<color name="background_light">#ffffffff</color>
<color name="bright_foreground_dark">@android:color/background_light</color>
<color name="bright_foreground_light">@android:color/background_dark</color>
@@ -80,6 +85,7 @@
<!-- For settings framework -->
<color name="lighter_gray">#ddd</color>
+ <!-- A dark gray, equivalent to 0xffaaaaaa -->
<color name="darker_gray">#aaa</color>
<!-- For security permissions -->
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
index 917c781..4297eea 100644
--- a/core/res/res/values/colors_holo.xml
+++ b/core/res/res/values/colors_holo.xml
@@ -50,29 +50,29 @@
<!-- General purpose colors for Holo-themed elements -->
<eat-comment />
- <!-- A light Holo shade of blue -->
+ <!-- A light Holo shade of blue. Equivalent to #ff33b5e5. -->
<color name="holo_blue_light">#ff33b5e5</color>
- <!-- A light Holo shade of gray -->
+ <!-- A light Holo shade of gray. Equivalent to #33999999. -->
<color name="holo_gray_light">#33999999</color>
- <!-- A light Holo shade of green -->
+ <!-- A light Holo shade of green. Equivalent to #ff99cc00. -->
<color name="holo_green_light">#ff99cc00</color>
- <!-- A light Holo shade of red -->
+ <!-- A light Holo shade of red. Equivalent to #ffff4444. <-->
<color name="holo_red_light">#ffff4444</color>
- <!-- A dark Holo shade of blue -->
+ <!-- A dark Holo shade of blue. Equivalent to #ff0099cc -->
<color name="holo_blue_dark">#ff0099cc</color>
- <!-- A dark Holo shade of green -->
+ <!-- A dark Holo shade of green. Equivalent to #ff669900 -->
<color name="holo_green_dark">#ff669900</color>
- <!-- A dark Holo shade of red -->
+ <!-- A dark Holo shade of red. Equivalent to #ffcc0000 -->
<color name="holo_red_dark">#ffcc0000</color>
- <!-- A Holo shade of purple -->
+ <!-- A Holo shade of purple. Equivalent to #ffaa66cc -->
<color name="holo_purple">#ffaa66cc</color>
- <!-- A light Holo shade of orange -->
+ <!-- A light Holo shade of orange. Equivalent to #ffffbb33. -->
<color name="holo_orange_light">#ffffbb33</color>
- <!-- A dark Holo shade of orange -->
+ <!-- A dark Holo shade of orange. Equivalent to ffff8800. -->
<color name="holo_orange_dark">#ffff8800</color>
- <!-- A really bright Holo shade of blue -->
+ <!-- A really bright Holo shade of blue. Equivalent to #ff00ddff. -->
<color name="holo_blue_bright">#ff00ddff</color>
- <!-- A really bright Holo shade of gray -->
+ <!-- A really bright Holo shade of gray. Equivalent to #33cccccc. -->
<color name="holo_gray_bright">#33CCCCCC</color>
<!-- Forward compatibility for Material-style theme colors -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 66d25df..2a6b331 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -30,33 +30,32 @@
<item><xliff:g id="id">@string/status_bar_rotate</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_headset</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_data_saver</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_ime</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_sync_failing</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_sync_active</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_nfc</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_tty</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_speakerphone</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_cdma_eri</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_data_connection</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_alarm_clock</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_clock</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_alarm_clock</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
</string-array>
<string translatable="false" name="status_bar_rotate">rotate</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0246c80..42cc54f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -708,23 +708,38 @@
<public type="dimen" name="thumbnail_height" id="0x01050001" />
<public type="dimen" name="thumbnail_width" id="0x01050002" />
+ <!-- Equivalent to 0xffaaaaaa -->
<public type="color" name="darker_gray" id="0x01060000" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="primary_text_dark" id="0x01060001" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="primary_text_dark_nodisable" id="0x01060002" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="primary_text_light" id="0x01060003" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="primary_text_light_nodisable" id="0x01060004" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="secondary_text_dark" id="0x01060005" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="secondary_text_dark_nodisable" id="0x01060006" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="secondary_text_light" id="0x01060007" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="secondary_text_light_nodisable" id="0x01060008" />
+ <!-- Equivalent to 0xff808080 -->
<public type="color" name="tab_indicator_text" id="0x01060009" />
+ <!-- Equivalent to 0xff000000 -->
<public type="color" name="widget_edittext_dark" id="0x0106000a" />
<public type="color" name="white" id="0x0106000b" />
<public type="color" name="black" id="0x0106000c" />
<public type="color" name="transparent" id="0x0106000d" />
+ <!-- Equivalent to 0xff000000 -->
<public type="color" name="background_dark" id="0x0106000e" />
+ <!-- Equivalent to 0xffffffff -->
<public type="color" name="background_light" id="0x0106000f" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="tertiary_text_dark" id="0x01060010" />
+ <!-- {@deprecated Use a text color from your theme instead.} -->
<public type="color" name="tertiary_text_light" id="0x01060011" />
<public type="array" name="emailAddressTypes" id="0x01070000" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cb8d629..cbd7b4d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2732,6 +2732,10 @@
<java-symbol type="string" name="status_bar_alarm_clock" />
<java-symbol type="string" name="status_bar_secure" />
<java-symbol type="string" name="status_bar_clock" />
+ <java-symbol type="string" name="status_bar_airplane" />
+ <java-symbol type="string" name="status_bar_mobile" />
+ <java-symbol type="string" name="status_bar_ethernet" />
+ <java-symbol type="string" name="status_bar_vpn" />
<!-- Locale picker -->
<java-symbol type="id" name="locale_search_menu" />
diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java
index 82af662..20b298d 100644
--- a/core/tests/coretests/src/android/os/MemoryFileTest.java
+++ b/core/tests/coretests/src/android/os/MemoryFileTest.java
@@ -23,6 +23,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -110,7 +111,7 @@
try {
os.write(new byte[] { -1, -1 });
fail();
- } catch (IndexOutOfBoundsException expected) {
+ } catch (IndexOutOfBoundsException | BufferOverflowException expected) {
}
byte[] copy = new byte[file.length()];
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 4b9465d..dfc99f6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -267,6 +267,7 @@
Settings.Global.LOW_POWER_MODE,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
Settings.Global.LOW_POWER_MODE_STICKY,
+ Settings.Global.LOW_POWER_MODE_SUGGESTION_PARAMS,
Settings.Global.LTE_SERVICE_FORCED,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 5261c04..00dc22e 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -855,7 +855,8 @@
*/
@java.lang.Deprecated
public ImageDecoder setResize(int width, int height) {
- return this.setTargetSize(width, height);
+ this.setTargetSize(width, height);
+ return this;
}
/**
@@ -873,9 +874,8 @@
*
* @param width must be greater than 0.
* @param height must be greater than 0.
- * @return this object for chaining.
*/
- public ImageDecoder setTargetSize(int width, int height) {
+ public void setTargetSize(int width, int height) {
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Dimensions must be positive! "
+ "provided (" + width + ", " + height + ")");
@@ -883,7 +883,6 @@
mDesiredWidth = width;
mDesiredHeight = height;
- return this;
}
/** @removed
@@ -891,7 +890,8 @@
*/
@java.lang.Deprecated
public ImageDecoder setResize(int sampleSize) {
- return this.setTargetSampleSize(sampleSize);
+ this.setTargetSampleSize(sampleSize);
+ return this;
}
private int getTargetDimension(int original, int sampleSize, int computed) {
@@ -941,13 +941,12 @@
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
* @param sampleSize Sampling rate of the encoded image.
- * @return this object for chaining.
*/
- public ImageDecoder setTargetSampleSize(int sampleSize) {
+ public void setTargetSampleSize(int sampleSize) {
Size size = this.getSampledSize(sampleSize);
int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth());
int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight());
- return this.setTargetSize(targetWidth, targetHeight);
+ this.setTargetSize(targetWidth, targetHeight);
}
private boolean requestedResize() {
@@ -1006,14 +1005,12 @@
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
* @param allocator Type of allocator to use.
- * @return this object for chaining.
*/
- public ImageDecoder setAllocator(@Allocator int allocator) {
+ public void setAllocator(@Allocator int allocator) {
if (allocator < ALLOCATOR_DEFAULT || allocator > ALLOCATOR_HARDWARE) {
throw new IllegalArgumentException("invalid allocator " + allocator);
}
mAllocator = allocator;
- return this;
}
/**
@@ -1039,12 +1036,9 @@
*
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
- *
- * @return this object for chaining.
*/
- public ImageDecoder setUnpremultipliedRequired(boolean unpremultipliedRequired) {
+ public void setUnpremultipliedRequired(boolean unpremultipliedRequired) {
mUnpremultipliedRequired = unpremultipliedRequired;
- return this;
}
/** @removed
@@ -1052,7 +1046,8 @@
*/
@java.lang.Deprecated
public ImageDecoder setRequireUnpremultiplied(boolean unpremultipliedRequired) {
- return this.setUnpremultipliedRequired(unpremultipliedRequired);
+ this.setUnpremultipliedRequired(unpremultipliedRequired);
+ return this;
}
/**
@@ -1086,11 +1081,9 @@
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
- * @return this object for chaining.
*/
- public ImageDecoder setPostProcessor(@Nullable PostProcessor p) {
+ public void setPostProcessor(@Nullable PostProcessor p) {
mPostProcessor = p;
- return this;
}
/**
@@ -1110,11 +1103,9 @@
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
- * @return this object for chaining.
*/
- public ImageDecoder setOnPartialImageListener(@Nullable OnPartialImageListener l) {
+ public void setOnPartialImageListener(@Nullable OnPartialImageListener l) {
mOnPartialImageListener = l;
- return this;
}
/**
@@ -1140,11 +1131,9 @@
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
- * @return this object for chaining.
*/
- public ImageDecoder setCrop(@Nullable Rect subset) {
+ public void setCrop(@Nullable Rect subset) {
mCropRect = subset;
- return this;
}
/**
@@ -1164,13 +1153,10 @@
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
- * @return this object for chaining.
- *
* @hide
*/
- public ImageDecoder setOutPaddingRect(@NonNull Rect outPadding) {
+ public void setOutPaddingRect(@NonNull Rect outPadding) {
mOutPaddingRect = outPadding;
- return this;
}
/**
@@ -1191,12 +1177,9 @@
*
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
- *
- * @return this object for chaining.
*/
- public ImageDecoder setMutableRequired(boolean mutable) {
+ public void setMutableRequired(boolean mutable) {
mMutable = mutable;
- return this;
}
/** @removed
@@ -1204,7 +1187,8 @@
*/
@java.lang.Deprecated
public ImageDecoder setMutable(boolean mutable) {
- return this.setMutableRequired(mutable);
+ this.setMutableRequired(mutable);
+ return this;
}
/**
@@ -1236,12 +1220,9 @@
*
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
- *
- * @return this object for chaining.
*/
- public ImageDecoder setConserveMemory(boolean conserveMemory) {
+ public void setConserveMemory(boolean conserveMemory) {
mConserveMemory = conserveMemory;
- return this;
}
/**
@@ -1269,12 +1250,9 @@
*
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
- *
- * @return this object for chaining.
*/
- public ImageDecoder setDecodeAsAlphaMaskEnabled(boolean enabled) {
+ public void setDecodeAsAlphaMaskEnabled(boolean enabled) {
mDecodeAsAlphaMask = enabled;
- return this;
}
/** @removed
@@ -1282,7 +1260,8 @@
*/
@java.lang.Deprecated
public ImageDecoder setDecodeAsAlphaMask(boolean enabled) {
- return this.setDecodeAsAlphaMaskEnabled(enabled);
+ this.setDecodeAsAlphaMaskEnabled(enabled);
+ return this;
}
/** @removed
@@ -1290,7 +1269,8 @@
*/
@java.lang.Deprecated
public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
- return this.setDecodeAsAlphaMask(asAlphaMask);
+ this.setDecodeAsAlphaMask(asAlphaMask);
+ return this;
}
/**
@@ -1350,9 +1330,8 @@
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*/
- public ImageDecoder setTargetColorSpace(ColorSpace colorSpace) {
+ public void setTargetColorSpace(ColorSpace colorSpace) {
mDesiredColorSpace = colorSpace;
- return this;
}
@Override
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 1e2ebf8..fe05c13 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,6 +16,7 @@
package android.security;
+import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
@@ -279,7 +280,7 @@
/**
* Attempt to lock the keystore for {@code user}.
*
- * @param user Android user to lock.
+ * @param userId Android user to lock.
* @return whether {@code user}'s keystore was locked.
*/
public boolean lock(int userId) {
@@ -300,7 +301,7 @@
* This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
* created.
*
- * @param user Android user ID to operate on
+ * @param userId Android user ID to operate on
* @param password user's keystore password. Should be the most recent value passed to
* {@link #onUserPasswordChanged} for the user.
*
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 4b9f3c80..c342acd 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -266,6 +266,7 @@
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mIsStrongBoxBacked;
private final boolean mUserConfirmationRequired;
+ private final boolean mUnlockedDeviceRequired;
/**
* @hide should be built with Builder
@@ -296,7 +297,8 @@
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
boolean isStrongBoxBacked,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ boolean unlockedDeviceRequired) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -345,6 +347,7 @@
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mIsStrongBoxBacked = isStrongBoxBacked;
mUserConfirmationRequired = userConfirmationRequired;
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -670,6 +673,15 @@
}
/**
+ * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+ *
+ * @see Builder#setUnlockedDeviceRequired(boolean)
+ */
+ public boolean isUnlockedDeviceRequired() {
+ return mUnlockedDeviceRequired;
+ }
+
+ /**
* @hide
*/
public long getBoundToSpecificSecureUserId() {
@@ -707,6 +719,7 @@
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mIsStrongBoxBacked = false;
private boolean mUserConfirmationRequired;
+ private boolean mUnlockedDeviceRequired = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -1275,6 +1288,18 @@
}
/**
+ * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+ * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+ * while the screen is locked will fail. A locked device requires a PIN, password,
+ * fingerprint, or other trusted factor to access.
+ */
+ @NonNull
+ public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
+ return this;
+ }
+
+ /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1305,7 +1330,8 @@
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mIsStrongBoxBacked,
- mUserConfirmationRequired);
+ mUserConfirmationRequired,
+ mUnlockedDeviceRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 95eeec7..22568ce 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -224,12 +224,13 @@
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
- private final boolean mTrustedUserPresenceRequred;
+ private final boolean mTrustedUserPresenceRequired;
private final boolean mUserAuthenticationValidWhileOnBody;
private final boolean mInvalidatedByBiometricEnrollment;
private final long mBoundToSecureUserId;
private final boolean mCriticalToDeviceEncryption;
private final boolean mUserConfirmationRequired;
+ private final boolean mUnlockedDeviceRequired;
private KeyProtection(
Date keyValidityStart,
@@ -243,12 +244,13 @@
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
- boolean trustedUserPresenceRequred,
+ boolean trustedUserPresenceRequired,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
long boundToSecureUserId,
boolean criticalToDeviceEncryption,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ boolean unlockedDeviceRequired) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -262,12 +264,13 @@
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
- mTrustedUserPresenceRequred = trustedUserPresenceRequred;
+ mTrustedUserPresenceRequired = trustedUserPresenceRequired;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mBoundToSecureUserId = boundToSecureUserId;
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
mUserConfirmationRequired = userConfirmationRequired;
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -444,7 +447,7 @@
* been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
*/
public boolean isTrustedUserPresenceRequired() {
- return mTrustedUserPresenceRequred;
+ return mTrustedUserPresenceRequired;
}
/**
@@ -505,6 +508,15 @@
}
/**
+ * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+ *
+ * @see Builder#setUnlockedDeviceRequired(boolean)
+ */
+ public boolean isUnlockedDeviceRequired() {
+ return mUnlockedDeviceRequired;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -524,6 +536,8 @@
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mUserConfirmationRequired;
+ private boolean mUnlockedDeviceRequired = false;
+
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
private boolean mCriticalToDeviceEncryption = false;
@@ -914,6 +928,18 @@
}
/**
+ * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+ * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+ * while the screen is locked will fail. A locked device requires a PIN, password,
+ * fingerprint, or other trusted factor to access.
+ */
+ @NonNull
+ public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -937,7 +963,8 @@
mInvalidatedByBiometricEnrollment,
mBoundToSecureUserId,
mCriticalToDeviceEncryption,
- mUserConfirmationRequired);
+ mUserConfirmationRequired,
+ mUnlockedDeviceRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 0ef08f2..14a9970 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -16,9 +16,8 @@
package android.security.keystore;
-import android.util.Log;
+import android.app.ActivityManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
@@ -101,8 +100,8 @@
* state (e.g., secure lock screen not set up) for generating or importing keys that
* require user authentication.
*/
- public static void addUserAuthArgs(KeymasterArguments args,
- UserAuthArgs spec) {
+ public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) {
+
if (spec.isUserConfirmationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
}
@@ -111,6 +110,10 @@
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
}
+ if (spec.isUnlockedDeviceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+ }
+
if (!spec.isUserAuthenticationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
index 1949592..ad18ff8 100644
--- a/keystore/java/android/security/keystore/UserAuthArgs.java
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -33,5 +33,6 @@
boolean isUserConfirmationRequired();
long getBoundToSpecificSecureUserId();
boolean isTrustedUserPresenceRequired();
+ boolean isUnlockedDeviceRequired();
}
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 2fa56f6..6700748 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -83,10 +83,12 @@
int maxTries = 3;
while (valueSize > mObservedBlobValueSize && maxTries > 0) {
mObservedBlobValueSize = std::min(valueSize, maxValueSize);
- valueBuffer = realloc(valueBuffer, mObservedBlobValueSize);
- if (!valueBuffer) {
+ void *newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize);
+ if (!newValueBuffer) {
+ free(valueBuffer);
return nullptr;
}
+ valueBuffer = newValueBuffer;
valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
maxTries--;
}
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 86dfc9c..ca895fc 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -226,11 +226,10 @@
}
/**
- * @hide
* @return The "address" string of the device. This generally contains device-specific
* parameters.
*/
- public String getAddress() {
+ public @NonNull String getAddress() {
return mPort.address();
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e408a11..aeef215 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4596,8 +4596,7 @@
private static boolean checkTypes(AudioDevicePort port) {
return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
- AudioDeviceInfo.TYPE_UNKNOWN &&
- port.type() != AudioSystem.DEVICE_IN_BACK_MIC;
+ AudioDeviceInfo.TYPE_UNKNOWN;
}
/**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 8d62cac..5173743 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -705,7 +705,9 @@
public @interface KeyType {}
/**
- * Contains the opaque data an app uses to request keys from a license server
+ * Contains the opaque data an app uses to request keys from a license server.
+ * These request types may or may not be generated by a given plugin. Refer
+ * to plugin vendor documentation for more information.
*/
public static final class KeyRequest {
private byte[] mData;
@@ -730,8 +732,8 @@
public static final int REQUEST_TYPE_RELEASE = 2;
/**
- * Keys are already loaded. No license request is necessary, and no
- * key request data is returned.
+ * Keys are already loaded and are available for use. No license request is necessary, and
+ * no key request data is returned.
*/
public static final int REQUEST_TYPE_NONE = 3;
diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java
index 004efea..d6399a4 100644
--- a/media/java/android/media/MicrophoneInfo.java
+++ b/media/java/android/media/MicrophoneInfo.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.util.Pair;
import java.lang.annotation.Retention;
@@ -224,12 +225,11 @@
}
/**
- * @hide
* Returns The "address" string of the microphone that corresponds to the
* address returned by {@link AudioDeviceInfo#getAddress()}
* @return the address of the microphone
*/
- public String getAddress() {
+ public @NonNull String getAddress() {
return mAddress;
}
diff --git a/media/java/android/media/audiofx/DynamicsProcessing.java b/media/java/android/media/audiofx/DynamicsProcessing.java
index d09c9a8..4c17ae1 100644
--- a/media/java/android/media/audiofx/DynamicsProcessing.java
+++ b/media/java/android/media/audiofx/DynamicsProcessing.java
@@ -16,10 +16,11 @@
package android.media.audiofx;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
-import android.media.audiofx.DynamicsProcessing.Settings;
import android.util.Log;
import java.nio.ByteBuffer;
@@ -90,66 +91,18 @@
private final static String TAG = "DynamicsProcessing";
- /**
- * Config object used to initialize and change effect parameters at runtime.
- */
- private Config mConfig = null;
-
-
// These parameter constants must be synchronized with those in
// /system/media/audio_effects/include/audio_effects/effect_dynamicsprocessing.h
-
- private static final int PARAM_GET_CHANNEL_COUNT = 0x0;
- private static final int PARAM_EQ_BAND_COUNT = 0x1;
- private static final int PARAM_MBC_BAND_COUNT = 0x2;
- private static final int PARAM_INPUT_GAIN = 0x3;
- private static final int PARAM_PRE_EQ_ENABLED = 0x10;
- private static final int PARAM_PRE_EQ_BAND_ENABLED = 0x11;
- private static final int PARAM_PRE_EQ_BAND_FREQUENCY = 0x12;
- private static final int PARAM_PRE_EQ_BAND_GAIN = 0x13;
- private static final int PARAM_EQ_FREQUENCY_RANGE = 0x22;
- private static final int PARAM_EQ_GAIN_RANGE = 0x23;
- private static final int PARAM_MBC_ENABLED = 0x30;
- private static final int PARAM_MBC_BAND_ENABLED = 0x31;
- private static final int PARAM_MBC_BAND_FREQUENCY = 0x32;
- private static final int PARAM_MBC_BAND_ATTACK_TIME = 0x33;
- private static final int PARAM_MBC_BAND_RELEASE_TIME = 0x34;
- private static final int PARAM_MBC_BAND_RATIO = 0x35;
- private static final int PARAM_MBC_BAND_THRESHOLD = 0x36;
- private static final int PARAM_MBC_BAND_KNEE_WIDTH = 0x37;
- private static final int PARAM_MBC_BAND_NOISE_GATE_THRESHOLD = 0x38;
- private static final int PARAM_MBC_BAND_EXPANDER_RATIO = 0x39;
- private static final int PARAM_MBC_BAND_GAIN_PRE = 0x3A;
- private static final int PARAM_MBC_BAND_GAIN_POST = 0x3B;
- private static final int PARAM_MBC_FREQUENCY_RANGE = 0x42;
- private static final int PARAM_MBC_ATTACK_TIME_RANGE = 0x43;
- private static final int PARAM_MBC_RELEASE_TIME_RANGE = 0x44;
- private static final int PARAM_MBC_RATIO_RANGE = 0x45;
- private static final int PARAM_MBC_THRESHOLD_RANGE = 0x46;
- private static final int PARAM_MBC_KNEE_WIDTH_RANGE = 0x47;
- private static final int PARAM_MBC_NOISE_GATE_THRESHOLD_RANGE = 0x48;
- private static final int PARAM_MBC_EXPANDER_RATIO_RANGE = 0x49;
- private static final int PARAM_MBC_GAIN_RANGE = 0x4A;
- private static final int PARAM_POST_EQ_ENABLED = 0x50;
- private static final int PARAM_POST_EQ_BAND_ENABLED = 0x51;
- private static final int PARAM_POST_EQ_BAND_FREQUENCY = 0x52;
- private static final int PARAM_POST_EQ_BAND_GAIN = 0x53;
- private static final int PARAM_LIMITER_ENABLED = 0x60;
- private static final int PARAM_LIMITER_LINK_GROUP = 0x61;
- private static final int PARAM_LIMITER_ATTACK_TIME = 0x62;
- private static final int PARAM_LIMITER_RELEASE_TIME = 0x63;
- private static final int PARAM_LIMITER_RATIO = 0x64;
- private static final int PARAM_LIMITER_THRESHOLD = 0x65;
- private static final int PARAM_LIMITER_GAIN_POST = 0x66;
- private static final int PARAM_LIMITER_ATTACK_TIME_RANGE = 0x72;
- private static final int PARAM_LIMITER_RELEASE_TIME_RANGE = 0x73;
- private static final int PARAM_LIMITER_RATIO_RANGE = 0x74;
- private static final int PARAM_LIMITER_THRESHOLD_RANGE = 0x75;
- private static final int PARAM_LIMITER_GAIN_RANGE = 0x76;
- private static final int PARAM_VARIANT = 0x100;
- private static final int PARAM_VARIANT_DESCRIPTION = 0x101;
- private static final int PARAM_VARIANT_COUNT = 0x102;
- private static final int PARAM_SET_ENGINE_ARCHITECTURE = 0x200;
+ private static final int PARAM_GET_CHANNEL_COUNT = 0x10;
+ private static final int PARAM_INPUT_GAIN = 0x20;
+ private static final int PARAM_ENGINE_ARCHITECTURE = 0x30;
+ private static final int PARAM_PRE_EQ = 0x40;
+ private static final int PARAM_PRE_EQ_BAND = 0x45;
+ private static final int PARAM_MBC = 0x50;
+ private static final int PARAM_MBC_BAND = 0x55;
+ private static final int PARAM_POST_EQ = 0x60;
+ private static final int PARAM_POST_EQ_BAND = 0x65;
+ private static final int PARAM_LIMITER = 0x70;
/**
* Index of variant that favors frequency resolution. Frequency domain based implementation.
@@ -226,12 +179,13 @@
* Config object that suits your needs. A null cfg parameter will create and use a default
* configuration for the effect
*/
- public DynamicsProcessing(int priority, int audioSession, Config cfg) {
+ public DynamicsProcessing(int priority, int audioSession, @Nullable Config cfg) {
super(EFFECT_TYPE_DYNAMICS_PROCESSING, EFFECT_TYPE_NULL, priority, audioSession);
if (audioSession == 0) {
Log.w(TAG, "WARNING: attaching a DynamicsProcessing to global output mix is"
+ "deprecated!");
}
+ final Config config;
mChannelCount = getChannelCount();
if (cfg == null) {
//create a default configuration and effect, with the number of channels this effect has
@@ -239,21 +193,33 @@
new DynamicsProcessing.Config.Builder(
CONFIG_DEFAULT_VARIANT,
mChannelCount,
- true /*use preEQ*/, 6 /*pre eq bands*/,
- true /*use mbc*/, 6 /*mbc bands*/,
- true /*use postEQ*/, 6 /*postEq bands*/,
- true /*use Limiter*/);
- mConfig = builder.build();
+ CONFIG_DEFAULT_USE_PREEQ,
+ CONFIG_DEFAULT_PREEQ_BANDS,
+ CONFIG_DEFAULT_USE_MBC,
+ CONFIG_DEFAULT_MBC_BANDS,
+ CONFIG_DEFAULT_USE_POSTEQ,
+ CONFIG_DEFAULT_POSTEQ_BANDS,
+ CONFIG_DEFAULT_USE_LIMITER);
+ config = builder.build();
} else {
- //validate channels are ok. decide what to do: replicate channels if more, or fail, or
- mConfig = new DynamicsProcessing.Config(mChannelCount, cfg);
+ //validate channels are ok. decide what to do: replicate channels if more
+ config = new DynamicsProcessing.Config(mChannelCount, cfg);
}
- setEngineArchitecture(mConfig.getVariant(),
- mConfig.isPreEqInUse(), mConfig.getPreEqBandCount(),
- mConfig.isMbcInUse(), mConfig.getMbcBandCount(),
- mConfig.isPostEqInUse(), mConfig.getPostEqBandCount(),
- mConfig.isLimiterInUse());
+ //configure engine
+ setEngineArchitecture(config.getVariant(),
+ config.getPreferredFrameDuration(),
+ config.isPreEqInUse(),
+ config.getPreEqBandCount(),
+ config.isMbcInUse(),
+ config.getMbcBandCount(),
+ config.isPostEqInUse(),
+ config.getPostEqBandCount(),
+ config.isLimiterInUse());
+ //update all the parameters
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ updateEngineChannelByChannelIndex(ch, config.getChannelByChannelIndex(ch));
+ }
}
/**
@@ -261,11 +227,51 @@
* @return Config Current Config object used to setup this DynamicsProcessing effect.
*/
public Config getConfig() {
- return mConfig;
+ //Query engine architecture to create config object
+ Number[] params = { PARAM_ENGINE_ARCHITECTURE };
+ Number[] values = { 0 /*0 variant */,
+ 0.0f /* 1 preferredFrameDuration */,
+ 0 /*2 preEqInUse */,
+ 0 /*3 preEqBandCount */,
+ 0 /*4 mbcInUse */,
+ 0 /*5 mbcBandCount*/,
+ 0 /*6 postEqInUse */,
+ 0 /*7 postEqBandCount */,
+ 0 /*8 limiterInUse */};
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
+ getParameter(paramBytes, valueBytes);
+ byteArrayToNumberArray(valueBytes, values);
+ DynamicsProcessing.Config.Builder builder =
+ new DynamicsProcessing.Config.Builder(
+ values[0].intValue(),
+ mChannelCount,
+ values[2].intValue() > 0 /*use preEQ*/,
+ values[3].intValue() /*pre eq bands*/,
+ values[4].intValue() > 0 /*use mbc*/,
+ values[5].intValue() /*mbc bands*/,
+ values[6].intValue() > 0 /*use postEQ*/,
+ values[7].intValue()/*postEq bands*/,
+ values[8].intValue() > 0 /*use Limiter*/).
+ setPreferredFrameDuration(values[1].floatValue());
+ Config config = builder.build();
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ Channel channel = queryEngineByChannelIndex(ch);
+ config.setChannelTo(ch, channel);
+ }
+ return config;
}
- private static final int CONFIG_DEFAULT_VARIANT = 0; //favor frequency
+ private static final int CONFIG_DEFAULT_VARIANT = VARIANT_FAVOR_FREQUENCY_RESOLUTION;
+ private static final boolean CONFIG_DEFAULT_USE_PREEQ = true;
+ private static final int CONFIG_DEFAULT_PREEQ_BANDS = 6;
+ private static final boolean CONFIG_DEFAULT_USE_MBC = true;
+ private static final int CONFIG_DEFAULT_MBC_BANDS = 6;
+ private static final boolean CONFIG_DEFAULT_USE_POSTEQ = true;
+ private static final int CONFIG_DEFAULT_POSTEQ_BANDS = 6;
+ private static final boolean CONFIG_DEFAULT_USE_LIMITER = true;
+
private static final float CHANNEL_DEFAULT_INPUT_GAIN = 0; // dB
private static final float CONFIG_PREFERRED_FRAME_DURATION_MS = 10.0f; //milliseconds
@@ -1276,7 +1282,7 @@
mChannel = new Channel[mChannelCount];
//check if channelconfig is null or has less channels than channel count.
//options: fill the missing with default options.
- // or fail?
+ // or fail?
for (int ch = 0; ch < mChannelCount; ch++) {
if (ch < channel.length) {
mChannel[ch] = new Channel(channel[ch]); //copy create
@@ -1331,7 +1337,7 @@
* Class constructor for Config
* @param cfg Configuration object copy constructor
*/
- public Config(Config cfg) {
+ public Config(@NonNull Config cfg) {
this(cfg.mChannelCount, cfg);
}
@@ -1763,138 +1769,115 @@
}
//=== CHANNEL
public Channel getChannelByChannelIndex(int channelIndex) {
- return mConfig.getChannelByChannelIndex(channelIndex);
+ return queryEngineByChannelIndex(channelIndex);
}
public void setChannelTo(int channelIndex, Channel channel) {
- mConfig.setChannelTo(channelIndex, channel);
+ updateEngineChannelByChannelIndex(channelIndex, channel);
}
public void setAllChannelsTo(Channel channel) {
- mConfig.setAllChannelsTo(channel);
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setChannelTo(ch, channel);
+ }
}
//=== channel params
public float getInputGainByChannelIndex(int channelIndex) {
- //TODO: return info from engine instead of cached config
- return mConfig.getInputGainByChannelIndex(channelIndex);
+ return getTwoFloat(PARAM_INPUT_GAIN, channelIndex);
}
public void setInputGainbyChannel(int channelIndex, float inputGain) {
- mConfig.setInputGainByChannelIndex(channelIndex, inputGain);
- //TODO: communicate change to engine
+ setTwoFloat(PARAM_INPUT_GAIN, channelIndex, inputGain);
}
public void setInputGainAllChannelsTo(float inputGain) {
- mConfig.setInputGainAllChannelsTo(inputGain);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setInputGainbyChannel(ch, inputGain);
+ }
}
//=== PreEQ
public Eq getPreEqByChannelIndex(int channelIndex) {
- //TODO: return info from engine instead of cached config
- return mConfig.getPreEqByChannelIndex(channelIndex);
+ return queryEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex);
}
-
public void setPreEqByChannelIndex(int channelIndex, Eq preEq) {
- mConfig.setPreEqByChannelIndex(channelIndex, preEq);
- //TODO: communicate change to engine
+ updateEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex, preEq);
}
-
public void setPreEqAllChannelsTo(Eq preEq) {
- mConfig.setPreEqAllChannelsTo(preEq);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setPreEqByChannelIndex(ch, preEq);
+ }
}
-
public EqBand getPreEqBandByChannelIndex(int channelIndex, int band) {
- //TODO: return info from engine instead of cached config
- return mConfig.getPreEqBandByChannelIndex(channelIndex, band);
+ return queryEngineEqBandByChannelIndex(PARAM_PRE_EQ_BAND, channelIndex, band);
}
-
public void setPreEqBandByChannelIndex(int channelIndex, int band, EqBand preEqBand) {
- mConfig.setPreEqBandByChannelIndex(channelIndex, band, preEqBand);
- //TODO: communicate change to engine
+ updateEngineEqBandByChannelIndex(PARAM_PRE_EQ_BAND, channelIndex, band, preEqBand);
}
-
public void setPreEqBandAllChannelsTo(int band, EqBand preEqBand) {
- mConfig.setPreEqBandAllChannelsTo(band, preEqBand);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setPreEqBandByChannelIndex(ch, band, preEqBand);
+ }
}
//=== MBC
public Mbc getMbcByChannelIndex(int channelIndex) {
- //TODO: return info from engine instead of cached config
- return mConfig.getMbcByChannelIndex(channelIndex);
+ return queryEngineMbcByChannelIndex(channelIndex);
}
-
public void setMbcByChannelIndex(int channelIndex, Mbc mbc) {
- mConfig.setMbcByChannelIndex(channelIndex, mbc);
- //TODO: communicate change to engine
+ updateEngineMbcByChannelIndex(channelIndex, mbc);
}
-
public void setMbcAllChannelsTo(Mbc mbc) {
- mConfig.setMbcAllChannelsTo(mbc);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setMbcByChannelIndex(ch, mbc);
+ }
}
-
public MbcBand getMbcBandByChannelIndex(int channelIndex, int band) {
- //TODO: return info from engine instead of cached config
- return mConfig.getMbcBandByChannelIndex(channelIndex, band);
+ return queryEngineMbcBandByChannelIndex(channelIndex, band);
}
-
public void setMbcBandByChannelIndex(int channelIndex, int band, MbcBand mbcBand) {
- mConfig.setMbcBandByChannelIndex(channelIndex, band, mbcBand);
- //TODO: communicate change to engine
+ updateEngineMbcBandByChannelIndex(channelIndex, band, mbcBand);
}
-
public void setMbcBandAllChannelsTo(int band, MbcBand mbcBand) {
- mConfig.setMbcBandAllChannelsTo(band, mbcBand);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setMbcBandByChannelIndex(ch, band, mbcBand);
+ }
}
//== PostEq
public Eq getPostEqByChannelIndex(int channelIndex) {
- //TODO: return info from engine instead of cached config
- return mConfig.getPostEqByChannelIndex(channelIndex);
+ return queryEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex);
}
-
public void setPostEqByChannelIndex(int channelIndex, Eq postEq) {
- mConfig.setPostEqByChannelIndex(channelIndex, postEq);
- //TODO: communicate change to engine
+ updateEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex, postEq);
}
-
public void setPostEqAllChannelsTo(Eq postEq) {
- mConfig.setPostEqAllChannelsTo(postEq);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setPostEqByChannelIndex(ch, postEq);
+ }
}
-
public EqBand getPostEqBandByChannelIndex(int channelIndex, int band) {
- //TODO: return info from engine instead of cached config
- return mConfig.getPostEqBandByChannelIndex(channelIndex, band);
+ return queryEngineEqBandByChannelIndex(PARAM_POST_EQ_BAND, channelIndex, band);
}
-
public void setPostEqBandByChannelIndex(int channelIndex, int band, EqBand postEqBand) {
- mConfig.setPostEqBandByChannelIndex(channelIndex, band, postEqBand);
- //TODO: communicate change to engine
+ updateEngineEqBandByChannelIndex(PARAM_POST_EQ_BAND, channelIndex, band, postEqBand);
}
-
public void setPostEqBandAllChannelsTo(int band, EqBand postEqBand) {
- mConfig.setPostEqBandAllChannelsTo(band, postEqBand);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setPostEqBandByChannelIndex(ch, band, postEqBand);
+ }
}
//==== Limiter
public Limiter getLimiterByChannelIndex(int channelIndex) {
- //TODO: return info from engine instead of cached config
- return mConfig.getLimiterByChannelIndex(channelIndex);
+ return queryEngineLimiterByChannelIndex(channelIndex);
}
-
public void setLimiterByChannelIndex(int channelIndex, Limiter limiter) {
- mConfig.setLimiterByChannelIndex(channelIndex, limiter);
- //TODO: communicate change to engine
+ updateEngineLimiterByChannelIndex(channelIndex, limiter);
}
-
public void setLimiterAllChannelsTo(Limiter limiter) {
- mConfig.setLimiterAllChannelsTo(limiter);
- //TODO: communicate change to engine
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ setLimiterByChannelIndex(ch, limiter);
+ }
}
/**
@@ -1905,165 +1888,327 @@
return getOneInt(PARAM_GET_CHANNEL_COUNT);
}
- private void setEngineArchitecture(int variant, boolean preEqInUse, int preEqBandCount,
- boolean mbcInUse, int mbcBandCount, boolean postEqInUse, int postEqBandCount,
- boolean limiterInUse) {
- int[] values = { variant, (preEqInUse ? 1 : 0), preEqBandCount,
- (mbcInUse ? 1 : 0), mbcBandCount, (postEqInUse ? 1 : 0), postEqBandCount,
+ //=== Engine calls
+ private void setEngineArchitecture(int variant, float preferredFrameDuration,
+ boolean preEqInUse, int preEqBandCount, boolean mbcInUse, int mbcBandCount,
+ boolean postEqInUse, int postEqBandCount, boolean limiterInUse) {
+
+ Number[] params = { PARAM_ENGINE_ARCHITECTURE };
+ Number[] values = { variant /* variant */,
+ preferredFrameDuration,
+ (preEqInUse ? 1 : 0),
+ preEqBandCount,
+ (mbcInUse ? 1 : 0),
+ mbcBandCount,
+ (postEqInUse ? 1 : 0),
+ postEqBandCount,
(limiterInUse ? 1 : 0)};
- //TODO: enable later setIntArray(PARAM_SET_ENGINE_ARCHITECTURE, values);
+ setNumberArray(params, values);
+ }
+
+ private void updateEngineEqBandByChannelIndex(int param, int channelIndex, int bandIndex,
+ @NonNull EqBand eqBand) {
+ Number[] params = {param,
+ channelIndex,
+ bandIndex};
+ Number[] values = {(eqBand.isEnabled() ? 1 : 0),
+ eqBand.getCutoffFrequency(),
+ eqBand.getGain()};
+ setNumberArray(params, values);
+ }
+ private Eq queryEngineEqByChannelIndex(int param, int channelIndex) {
+
+ Number[] params = {param == PARAM_PRE_EQ ? PARAM_PRE_EQ : PARAM_POST_EQ,
+ channelIndex};
+ Number[] values = {0 /*0 in use */,
+ 0 /*1 enabled*/,
+ 0 /*2 band count */};
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
+ getParameter(paramBytes, valueBytes);
+ byteArrayToNumberArray(valueBytes, values);
+ int bandCount = values[2].intValue();
+ Eq eq = new Eq(values[0].intValue() > 0 /* in use */,
+ values[1].intValue() > 0 /* enabled */,
+ bandCount /*band count*/);
+ for (int b = 0; b < bandCount; b++) {
+ EqBand eqBand = queryEngineEqBandByChannelIndex(param == PARAM_PRE_EQ ?
+ PARAM_PRE_EQ_BAND : PARAM_POST_EQ_BAND, channelIndex, b);
+ eq.setBand(b, eqBand);
+ }
+ return eq;
+ }
+ private EqBand queryEngineEqBandByChannelIndex(int param, int channelIndex, int bandIndex) {
+ Number[] params = {param,
+ channelIndex,
+ bandIndex};
+ Number[] values = {0 /*0 enabled*/,
+ 0.0f /*1 cutoffFrequency */,
+ 0.0f /*2 gain */};
+
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
+ getParameter(paramBytes, valueBytes);
+
+ byteArrayToNumberArray(valueBytes, values);
+
+ return new EqBand(values[0].intValue() > 0 /* enabled */,
+ values[1].floatValue() /* cutoffFrequency */,
+ values[2].floatValue() /* gain*/);
+ }
+ private void updateEngineEqByChannelIndex(int param, int channelIndex, @NonNull Eq eq) {
+ int bandCount = eq.getBandCount();
+ Number[] params = {param,
+ channelIndex};
+ Number[] values = { (eq.isInUse() ? 1 : 0),
+ (eq.isEnabled() ? 1 : 0),
+ bandCount};
+ setNumberArray(params, values);
+ for (int b = 0; b < bandCount; b++) {
+ EqBand eqBand = eq.getBand(b);
+ updateEngineEqBandByChannelIndex(param == PARAM_PRE_EQ ?
+ PARAM_PRE_EQ_BAND : PARAM_POST_EQ_BAND, channelIndex, b, eqBand);
+ }
+ }
+
+ private Mbc queryEngineMbcByChannelIndex(int channelIndex) {
+ Number[] params = {PARAM_MBC,
+ channelIndex};
+ Number[] values = {0 /*0 in use */,
+ 0 /*1 enabled*/,
+ 0 /*2 band count */};
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
+ getParameter(paramBytes, valueBytes);
+ byteArrayToNumberArray(valueBytes, values);
+ int bandCount = values[2].intValue();
+ Mbc mbc = new Mbc(values[0].intValue() > 0 /* in use */,
+ values[1].intValue() > 0 /* enabled */,
+ bandCount /*band count*/);
+ for (int b = 0; b < bandCount; b++) {
+ MbcBand mbcBand = queryEngineMbcBandByChannelIndex(channelIndex, b);
+ mbc.setBand(b, mbcBand);
+ }
+ return mbc;
+ }
+ private MbcBand queryEngineMbcBandByChannelIndex(int channelIndex, int bandIndex) {
+ Number[] params = {PARAM_MBC_BAND,
+ channelIndex,
+ bandIndex};
+ Number[] values = {0 /*0 enabled */,
+ 0.0f /*1 cutoffFrequency */,
+ 0.0f /*2 AttackTime */,
+ 0.0f /*3 ReleaseTime */,
+ 0.0f /*4 Ratio */,
+ 0.0f /*5 Threshold */,
+ 0.0f /*6 KneeWidth */,
+ 0.0f /*7 NoiseGateThreshold */,
+ 0.0f /*8 ExpanderRatio */,
+ 0.0f /*9 PreGain */,
+ 0.0f /*10 PostGain*/};
+
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
+ getParameter(paramBytes, valueBytes);
+
+ byteArrayToNumberArray(valueBytes, values);
+
+ return new MbcBand(values[0].intValue() > 0 /* enabled */,
+ values[1].floatValue() /* cutoffFrequency */,
+ values[2].floatValue()/*2 AttackTime */,
+ values[3].floatValue()/*3 ReleaseTime */,
+ values[4].floatValue()/*4 Ratio */,
+ values[5].floatValue()/*5 Threshold */,
+ values[6].floatValue()/*6 KneeWidth */,
+ values[7].floatValue()/*7 NoiseGateThreshold */,
+ values[8].floatValue()/*8 ExpanderRatio */,
+ values[9].floatValue()/*9 PreGain */,
+ values[10].floatValue()/*10 PostGain*/);
+ }
+ private void updateEngineMbcBandByChannelIndex(int channelIndex, int bandIndex,
+ @NonNull MbcBand mbcBand) {
+ Number[] params = { PARAM_MBC_BAND,
+ channelIndex,
+ bandIndex};
+ Number[] values = {(mbcBand.isEnabled() ? 1 : 0),
+ mbcBand.getCutoffFrequency(),
+ mbcBand.getAttackTime(),
+ mbcBand.getReleaseTime(),
+ mbcBand.getRatio(),
+ mbcBand.getThreshold(),
+ mbcBand.getKneeWidth(),
+ mbcBand.getNoiseGateThreshold(),
+ mbcBand.getExpanderRatio(),
+ mbcBand.getPreGain(),
+ mbcBand.getPostGain()};
+ setNumberArray(params, values);
+ }
+
+ private void updateEngineMbcByChannelIndex(int channelIndex, @NonNull Mbc mbc) {
+ int bandCount = mbc.getBandCount();
+ Number[] params = { PARAM_MBC,
+ channelIndex};
+ Number[] values = {(mbc.isInUse() ? 1 : 0),
+ (mbc.isEnabled() ? 1 : 0),
+ bandCount};
+ setNumberArray(params, values);
+ for (int b = 0; b < bandCount; b++) {
+ MbcBand mbcBand = mbc.getBand(b);
+ updateEngineMbcBandByChannelIndex(channelIndex, b, mbcBand);
+ }
+ }
+
+ private void updateEngineLimiterByChannelIndex(int channelIndex, @NonNull Limiter limiter) {
+ Number[] params = { PARAM_LIMITER,
+ channelIndex};
+ Number[] values = {(limiter.isInUse() ? 1 : 0),
+ (limiter.isEnabled() ? 1 : 0),
+ limiter.getLinkGroup(),
+ limiter.getAttackTime(),
+ limiter.getReleaseTime(),
+ limiter.getRatio(),
+ limiter.getThreshold(),
+ limiter.getPostGain()};
+ setNumberArray(params, values);
+ }
+
+ private Limiter queryEngineLimiterByChannelIndex(int channelIndex) {
+ Number[] params = {PARAM_LIMITER,
+ channelIndex};
+ Number[] values = {0 /*0 in use (int)*/,
+ 0 /*1 enabled (int)*/,
+ 0 /*2 link group (int)*/,
+ 0.0f /*3 attack time (float)*/,
+ 0.0f /*4 release time (float)*/,
+ 0.0f /*5 ratio (float)*/,
+ 0.0f /*6 threshold (float)*/,
+ 0.0f /*7 post gain(float)*/};
+
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
+ getParameter(paramBytes, valueBytes);
+ byteArrayToNumberArray(valueBytes, values);
+
+ return new Limiter(values[0].intValue() > 0 /*in use*/,
+ values[1].intValue() > 0 /*enabled*/,
+ values[2].intValue() /*linkGroup*/,
+ values[3].floatValue() /*attackTime*/,
+ values[4].floatValue() /*releaseTime*/,
+ values[5].floatValue() /*ratio*/,
+ values[6].floatValue() /*threshold*/,
+ values[7].floatValue() /*postGain*/);
+ }
+
+ private Channel queryEngineByChannelIndex(int channelIndex) {
+ float inputGain = getTwoFloat(PARAM_INPUT_GAIN, channelIndex);
+ Eq preEq = queryEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex);
+ Mbc mbc = queryEngineMbcByChannelIndex(channelIndex);
+ Eq postEq = queryEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex);
+ Limiter limiter = queryEngineLimiterByChannelIndex(channelIndex);
+
+ Channel channel = new Channel(inputGain,
+ preEq.isInUse(), preEq.getBandCount(),
+ mbc.isInUse(), mbc.getBandCount(),
+ postEq.isInUse(), postEq.getBandCount(),
+ limiter.isInUse());
+ channel.setInputGain(inputGain);
+ channel.setPreEq(preEq);
+ channel.setMbc(mbc);
+ channel.setPostEq(postEq);
+ channel.setLimiter(limiter);
+ return channel;
+ }
+
+ private void updateEngineChannelByChannelIndex(int channelIndex, @NonNull Channel channel) {
+ //send things with as few calls as possible
+ setTwoFloat(PARAM_INPUT_GAIN, channelIndex, channel.getInputGain());
+ Eq preEq = channel.getPreEq();
+ updateEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex, preEq);
+ Mbc mbc = channel.getMbc();
+ updateEngineMbcByChannelIndex(channelIndex, mbc);
+ Eq postEq = channel.getPostEq();
+ updateEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex, postEq);
+ Limiter limiter = channel.getLimiter();
+ updateEngineLimiterByChannelIndex(channelIndex, limiter);
}
//****** convenience methods:
//
- private int getOneInt(int paramGet) {
- int[] param = new int[1];
- int[] result = new int[1];
+ private int getOneInt(int param) {
+ final int[] params = { param };
+ final int[] result = new int[1];
- param[0] = paramGet;
- checkStatus(getParameter(param, result));
+ checkStatus(getParameter(params, result));
return result[0];
}
- private int getTwoInt(int paramGet, int paramA) {
- int[] param = new int[2];
- int[] result = new int[1];
+ private void setTwoFloat(int param, int paramA, float valueSet) {
+ final int[] params = { param, paramA };
+ final byte[] value;
- param[0] = paramGet;
- param[1] = paramA;
- checkStatus(getParameter(param, result));
- return result[0];
- }
-
- private int getThreeInt(int paramGet, int paramA, int paramB) {
- //have to use bytearrays, with more than 2 parameters.
- byte[] paramBytes = concatArrays(intToByteArray(paramGet),
- intToByteArray(paramA),
- intToByteArray(paramB));
- byte[] resultBytes = new byte[4]; //single int
-
- checkStatus(getParameter(paramBytes, resultBytes));
-
- return byteArrayToInt(resultBytes);
- }
-
- private void setOneInt(int paramSet, int valueSet) {
- int[] param = new int[1];
- int[] value = new int[1];
-
- param[0] = paramSet;
- value[0] = valueSet;
- checkStatus(setParameter(param, value));
- }
-
- private void setTwoInt(int paramSet, int paramA, int valueSet) {
- int[] param = new int[2];
- int[] value = new int[1];
-
- param[0] = paramSet;
- param[1] = paramA;
- value[0] = valueSet;
- checkStatus(setParameter(param, value));
- }
-
- private void setThreeInt(int paramSet, int paramA, int paramB, int valueSet) {
- //have to use bytearrays, with more than 2 parameters.
- byte[] paramBytes = concatArrays(intToByteArray(paramSet),
- intToByteArray(paramA),
- intToByteArray(paramB));
- byte[] valueBytes = intToByteArray(valueSet);
-
- checkStatus(setParameter(paramBytes, valueBytes));
- }
-
- private void setOneFloat(int paramSet, float valueSet) {
- int[] param = new int[1];
- byte[] value;
-
- param[0] = paramSet;
value = floatToByteArray(valueSet);
- checkStatus(setParameter(param, value));
+ checkStatus(setParameter(params, value));
}
- private void setTwoFloat(int paramSet, int paramA, float valueSet) {
- int[] param = new int[2];
- byte[] value;
-
- param[0] = paramSet;
- param[1] = paramA;
- value = floatToByteArray(valueSet);
- checkStatus(setParameter(param, value));
- }
-
- private void setThreeFloat(int paramSet, int paramA, int paramB, float valueSet) {
- //have to use bytearrays, with more than 2 parameters.
- byte[] paramBytes = concatArrays(intToByteArray(paramSet),
- intToByteArray(paramA),
- intToByteArray(paramB));
- byte[] valueBytes = floatToByteArray(valueSet);
-
- checkStatus(setParameter(paramBytes, valueBytes));
- }
- private byte[] intArrayToByteArray(int[] values) {
- int expectedBytes = values.length * 4;
+ private byte[] numberArrayToByteArray(Number[] values) {
+ int expectedBytes = 0;
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] instanceof Integer) {
+ expectedBytes += Integer.BYTES;
+ } else if (values[i] instanceof Float) {
+ expectedBytes += Float.BYTES;
+ } else {
+ throw new IllegalArgumentException("unknown value type " +
+ values[i].getClass());
+ }
+ }
ByteBuffer converter = ByteBuffer.allocate(expectedBytes);
converter.order(ByteOrder.nativeOrder());
- for (int k = 0; k < values.length; k++) {
- converter.putFloat(values[k]);
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] instanceof Integer) {
+ converter.putInt(values[i].intValue());
+ } else if (values[i] instanceof Float) {
+ converter.putFloat(values[i].floatValue());
+ }
}
return converter.array();
}
- private void setIntArray(int paramSet, int[] paramArray) {
- //have to use bytearrays, with more than 2 parameters.
- byte[] paramBytes = intToByteArray(paramSet);
- byte[] valueBytes = intArrayToByteArray(paramArray);
+ private void byteArrayToNumberArray(byte[] valuesIn, Number[] valuesOut) {
+ int inIndex = 0;
+ int outIndex = 0;
+ while (inIndex < valuesIn.length && outIndex < valuesOut.length) {
+ if (valuesOut[outIndex] instanceof Integer) {
+ valuesOut[outIndex++] = byteArrayToInt(valuesIn, inIndex);
+ inIndex += Integer.BYTES;
+ } else if (valuesOut[outIndex] instanceof Float) {
+ valuesOut[outIndex++] = byteArrayToFloat(valuesIn, inIndex);
+ inIndex += Float.BYTES;
+ } else {
+ throw new IllegalArgumentException("can't convert " +
+ valuesOut[outIndex].getClass());
+ }
+ }
+ if (outIndex != valuesOut.length) {
+ throw new IllegalArgumentException("only converted " + outIndex +
+ " values out of "+ valuesOut.length + " expected");
+ }
+ }
+
+ private void setNumberArray(Number[] params, Number[] values) {
+ byte[] paramBytes = numberArrayToByteArray(params);
+ byte[] valueBytes = numberArrayToByteArray(values);
checkStatus(setParameter(paramBytes, valueBytes));
}
- private float getOneFloat(int paramGet) {
- int[] param = new int[1];
- byte[] result = new byte[4];
+ private float getTwoFloat(int param, int paramA) {
+ final int[] params = { param, paramA };
+ final byte[] result = new byte[4];
- param[0] = paramGet;
- checkStatus(getParameter(param, result));
+ checkStatus(getParameter(params, result));
return byteArrayToFloat(result);
}
- private float getTwoFloat(int paramGet, int paramA) {
- int[] param = new int[2];
- byte[] result = new byte[4];
-
- param[0] = paramGet;
- param[1] = paramA;
- checkStatus(getParameter(param, result));
- return byteArrayToFloat(result);
- }
-
- private float getThreeFloat(int paramGet, int paramA, int paramB) {
- //have to use bytearrays, with more than 2 parameters.
- byte[] paramBytes = concatArrays(intToByteArray(paramGet),
- intToByteArray(paramA),
- intToByteArray(paramB));
- byte[] resultBytes = new byte[4]; //single float
-
- checkStatus(getParameter(paramBytes, resultBytes));
-
- return byteArrayToFloat(resultBytes);
- }
-
- private float[] getOneFloatArray(int paramGet, int expectedSize) {
- int[] param = new int[1];
- byte[] result = new byte[4 * expectedSize];
-
- param[0] = paramGet;
- checkStatus(getParameter(param, result));
- float[] returnArray = new float[expectedSize];
- for (int k = 0; k < expectedSize; k++) {
- returnArray[k] = byteArrayToFloat(result, 4 * k);
- }
- return returnArray;
- }
/**
* @hide
* The OnParameterChangeListener interface defines a method called by the DynamicsProcessing
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 82bc6af8..6368607 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -543,30 +543,30 @@
<!-- UI debug setting: Select Bluetooth AVRCP Version -->
<string name="bluetooth_select_avrcp_version_dialog_title">Select Bluetooth AVRCP Version</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection -->
<string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec -->
- <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Bluetooth Audio Codec</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection -->
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection</string>
- <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Sample Rate Selection -->
<string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec: Sample Rate -->
- <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Bluetooth Audio Codec:\u000ASample Rate</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection: Sample Rate -->
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection: Sample Rate</string>
- <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Bits Per Sample Selection -->
<string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec: Bits Per Sample -->
- <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Bluetooth Audio Codec:\u000ABits Per Sample</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection: Bits Per Sample -->
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection: Bits Per Sample</string>
- <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Channel Mode Selection -->
<string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec: Channel Mode -->
- <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Bluetooth Audio Codec:\u000AChannel Mode</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection: Channel Mode -->
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection: Channel Mode</string>
- <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
+ <!-- UI debug setting: Trigger Bluetooth Audio LDAC Playback Quality Selection -->
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Codec: Playback Quality</string>
<!-- UI debug setting: Select Bluetooth Audio LDAC Codec: LDAC Playback Quality -->
- <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Bluetooth Audio LDAC Codec:\u000APlayback Quality</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Trigger Bluetooth Audio LDAC Codec\u000ASelection: Playback Quality</string>
<!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
<string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 28833a3..835ff07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -22,8 +22,9 @@
import android.os.PowerManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
-import android.support.annotation.VisibleForTesting;
+import android.util.KeyValueListParser;
import android.util.Log;
+import android.util.Slog;
/**
* Utilities related to battery saver.
@@ -48,13 +49,35 @@
public static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION
= "PNW.autoSaverSuggestion";
- /**
- * We show the auto battery saver suggestion notification when the user manually enables
- * battery saver for the START_NTH time through the END_NTH time.
- * (We won't show it for END_NTH + 1 time and after.)
- */
- private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4;
- private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8;
+ private static class Parameters {
+ private final Context mContext;
+
+ /**
+ * We show the auto battery saver suggestion notification when the user manually enables
+ * battery saver for the START_NTH time through the END_NTH time.
+ * (We won't show it for END_NTH + 1 time and after.)
+ */
+ private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4;
+ private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8;
+
+ public final int startNth;
+ public final int endNth;
+
+ public Parameters(Context context) {
+ mContext = context;
+
+ final String newValue = Global.getString(mContext.getContentResolver(),
+ Global.LOW_POWER_MODE_SUGGESTION_PARAMS);
+ final KeyValueListParser parser = new KeyValueListParser(',');
+ try {
+ parser.setString(newValue);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad constants: " + newValue);
+ }
+ startNth = parser.getInt("start_nth", AUTO_SAVER_SUGGESTION_START_NTH);
+ endNth = parser.getInt("end_nth", AUTO_SAVER_SUGGESTION_END_NTH);
+ }
+ }
/**
* Enable / disable battery saver by user request.
@@ -85,8 +108,10 @@
Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1;
Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, count);
- if ((count >= AUTO_SAVER_SUGGESTION_START_NTH)
- && (count <= AUTO_SAVER_SUGGESTION_END_NTH)
+ final Parameters parameters = new Parameters(context);
+
+ if ((count >= parameters.startNth)
+ && (count <= parameters.endNth)
&& Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
&& Secure.getInt(cr,
Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index 53f7e44..ad300f4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -50,4 +50,6 @@
public abstract void onStateChanged(State state);
public abstract int getDetailY();
+
+ public void setExpansion(float expansion) {}
}
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background.xml b/packages/SystemUI/res/drawable/qs_customizer_background.xml
index 12d8016..e15a734 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_background.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_background.xml
@@ -14,6 +14,6 @@
limitations under the License.
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@color/qs_detail_transition" />
- <item android:drawable="?android:attr/colorPrimary" />
+ <item android:drawable="@drawable/qs_customizer_background_transition" />
+ <item android:drawable="@drawable/qs_customizer_background_primary" />
</transition>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
new file mode 100644
index 0000000..abe1429
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape>
+ <solid android:color="?android:attr/colorPrimary"/>
+ <corners android:radius="?android:attr/dialogCornerRadius" />
+ </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background_transition.xml b/packages/SystemUI/res/drawable/qs_customizer_background_transition.xml
new file mode 100644
index 0000000..ed8f61a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_customizer_background_transition.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape>
+ <solid android:color="@color/qs_detail_transition"/>
+ <corners android:radius="?android:attr/dialogCornerRadius" />
+ </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
new file mode 100644
index 0000000..557cae1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape>
+ <solid android:color="?android:attr/colorSecondary"/>
+ <corners
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius" />
+ </shape>
+</inset>
diff --git a/packages/SystemUI/res/layout/qs_customize_divider.xml b/packages/SystemUI/res/layout/qs_customize_divider.xml
index 71ad85b..51febc7 100644
--- a/packages/SystemUI/res/layout/qs_customize_divider.xml
+++ b/packages/SystemUI/res/layout/qs_customize_divider.xml
@@ -20,9 +20,8 @@
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center"
android:paddingTop="20dp"
- android:paddingStart="16dp"
- android:paddingEnd="8dp"
android:paddingBottom="13dp"
android:textAppearance="@android:style/TextAppearance.Material.Body2"
android:textColor="?android:attr/colorAccent"
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index b3b6a0c..506e6c8 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -22,7 +22,6 @@
android:layout_height="0dp"
android:elevation="4dp"
android:orientation="vertical"
- android:background="@drawable/qs_customizer_background"
android:gravity="center_horizontal">
</com.android.systemui.qs.customize.QSCustomizer>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 04d0e65..d70a37a 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -15,24 +15,44 @@
limitations under the License.
-->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
- <Toolbar
- android:id="@*android:id/action_bar"
+<merge xmlns:android="http://schemas.android.com/apk/res/android">->
+ <View
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="28dp"
- android:navigationContentDescription="@*android:string/action_bar_up_description"
- style="?android:attr/toolbarStyle" />
+ android:layout_height="@*android:dimen/quick_qs_offset_height"
+ android:background="@android:color/transparent" />
- <android.support.v7.widget.RecyclerView
- android:id="@android:id/list"
+ <com.android.keyguard.AlphaOptimizedLinearLayout
+ android:id="@+id/customize_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:scrollIndicators="top"
- android:scrollbars="vertical"
- android:importantForAccessibility="no" />
+ android:layout_marginLeft="@dimen/notification_side_paddings"
+ android:layout_marginRight="@dimen/notification_side_paddings"
+ android:orientation="vertical"
+ android:background="@drawable/qs_customizer_background">
+ <Toolbar
+ android:id="@*android:id/action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/qs_customizer_toolbar"
+ android:navigationContentDescription="@*android:string/action_bar_up_description"
+ style="?android:attr/toolbarStyle" />
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:paddingTop="28dp"
+ android:paddingLeft="@dimen/qs_tile_layout_margin_side"
+ android:paddingRight="@dimen/qs_tile_layout_margin_side"
+ android:paddingBottom="28dp"
+ android:clipToPadding="false"
+ android:scrollIndicators="top"
+ android:scrollbars="vertical"
+ android:scrollbarStyle="outsideOverlay"
+ android:importantForAccessibility="no" />
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
<View
android:id="@+id/nav_bar_background"
diff --git a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
index ff55f99..a2250b1 100644
--- a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
+++ b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
@@ -17,9 +17,8 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/qs_tile_height"
android:layout_width="match_parent"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:paddingTop="8dp"
+ android:layout_marginTop="@dimen/qs_tile_margin_top_bottom"
+ android:layout_marginBottom="@dimen/qs_tile_margin_top_bottom"
android:gravity="center" />
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index cd3271f..c03f25c 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -21,7 +21,7 @@
android:layout_marginTop="8dp"
android:layout_marginBottom="14dp"
android:layout_below="@id/quick_status_bar_system_icons"
- >
+ android:paddingEnd="@dimen/signal_cluster_battery_padding" >
<com.android.systemui.statusbar.phone.StatusIconContainer
android:id="@+id/statusIcons"
@@ -29,9 +29,4 @@
android:layout_height="match_parent"
android:layout_weight="1" />
- <include layout="@layout/signal_cluster_view"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/signal_cluster_margin_start" />
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
new file mode 100644
index 0000000..d607c8c
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.statusbar.StatusBarMobileView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/mobile_combo"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:id="@+id/inout_container"
+ android:layout_height="17dp"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical">
+ <ImageView
+ android:id="@+id/mobile_in"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_activity_down"
+ android:visibility="gone"
+ android:paddingEnd="2dp"
+ />
+ <ImageView
+ android:id="@+id/mobile_out"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_activity_up"
+ android:paddingEnd="2dp"
+ android:visibility="gone"
+ />
+ </FrameLayout>
+ <ImageView
+ android:id="@+id/mobile_type"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingEnd="1dp"
+ android:visibility="gone" />
+ <Space
+ android:id="@+id/mobile_roaming_space"
+ android:layout_height="match_parent"
+ android:layout_width="@dimen/roaming_icon_start_padding"
+ android:visibility="gone"
+ />
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical">
+ <com.android.systemui.statusbar.AnimatedImageView
+ android:id="@+id/mobile_signal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/mobile_roaming"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/stat_sys_roaming"
+ android:contentDescription="@string/data_connection_roaming"
+ android:visibility="gone" />
+ </FrameLayout>
+</com.android.systemui.statusbar.StatusBarMobileView>
+
diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group.xml b/packages/SystemUI/res/layout/status_bar_wifi_group.xml
new file mode 100644
index 0000000..08cef55
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_wifi_group.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.statusbar.StatusBarWifiView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/wifi_combo"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingStart="4dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <FrameLayout
+ android:id="@+id/inout_container"
+ android:layout_height="17dp"
+ android:layout_width="wrap_content"
+ android:gravity="center_vertical" >
+ <ImageView
+ android:id="@+id/wifi_in"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_activity_down"
+ android:visibility="gone"
+ android:paddingEnd="2dp"
+ />
+ <ImageView
+ android:id="@+id/wifi_out"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_activity_up"
+ android:paddingEnd="2dp"
+ android:visibility="gone"
+ />
+ </FrameLayout>
+ <FrameLayout
+ android:id="@+id/wifi_combo"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="center_vertical" >
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:theme="?attr/lightIconTheme"
+ android:id="@+id/wifi_signal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+ </FrameLayout>
+
+ <View
+ android:id="@+id/wifi_signal_spacer"
+ android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
+ android:layout_height="4dp"
+ android:visibility="gone" />
+
+ <!-- Looks like CarStatusBar uses this... -->
+ <ViewStub
+ android:id="@+id/connected_device_signals_stub"
+ android:layout="@layout/connected_device_signal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <View
+ android:id="@+id/wifi_airplane_spacer"
+ android:layout_width="@dimen/status_bar_airplane_spacer_width"
+ android:layout_height="4dp"
+ android:visibility="gone"
+ />
+</com.android.systemui.statusbar.StatusBarWifiView>
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 1fafb2f..258b82a 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -24,14 +24,10 @@
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
+ android:paddingEnd="4dp"
android:gravity="center_vertical"
android:orientation="horizontal"/>
- <include layout="@layout/signal_cluster_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/signal_cluster_margin_start"/>
-
<com.android.systemui.BatteryMeterView android:id="@+id/battery"
android:layout_height="match_parent"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0f07ca4..84ca657 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -317,8 +317,10 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_tile_height">106dp</dimen>
+ <dimen name="qs_tile_layout_margin_side">9dp</dimen>
<dimen name="qs_tile_margin_horizontal">18dp</dimen>
<dimen name="qs_tile_margin_vertical">24dp</dimen>
+ <dimen name="qs_tile_margin_top_bottom">12dp</dimen>
<dimen name="qs_tile_margin_top">18dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<!-- Width for the spacer, used between QS tiles. -->
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 5679dd2..6caed61 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -32,6 +32,8 @@
<dimen name="car_navigation_button_width">64dp</dimen>
<dimen name="car_navigation_bar_width">760dp</dimen>
+ <dimen name="car_left_navigation_bar_width">96dp</dimen>
+ <dimen name="car_right_navigation_bar_width">96dp</dimen>
<dimen name="car_page_indicator_dot_diameter">12dp</dimen>
<dimen name="car_page_indicator_margin_bottom">24dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e9b2be9..4074042 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1748,6 +1748,10 @@
<!-- Name of the headset in status bar [CHAR LIMIT=30] -->
<string name="headset">Headset</string>
+ <!-- Accessibility description for long click on a quick settings tile - this is used in the
+ context of the sentence "double tap and hold to _Open settings_" [CHAR LIMIT=NONE] -->
+ <string name="accessibility_long_click_tile">Open settings</string>
+
<!-- Accessibility description of headphones icon [CHAR LIMIT=NONE] -->
<string name="accessibility_status_bar_headphones">Headphones connected</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 2c0e95b..a61ce8c 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -29,30 +29,16 @@
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArraySet;
-import android.util.TimingsTraceLog;
import android.util.Log;
+import android.util.TimingsTraceLog;
-import com.android.systemui.globalactions.GlobalActionsComponent;
-import com.android.systemui.keyboard.KeyboardUI;
-import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.media.RingtonePlayer;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.power.PowerUI;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
-import com.android.systemui.usb.StorageNotification;
import com.android.systemui.util.NotificationChannels;
-import com.android.systemui.util.leak.GarbageMonitor;
-import com.android.systemui.volume.VolumeUI;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -99,6 +85,10 @@
mServices[i].onBootCompleted();
}
}
+
+ IntentFilter localeChangedFilter = new IntentFilter(
+ Intent.ACTION_LOCALE_CHANGED);
+ registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
}
}, filter);
} else {
@@ -249,4 +239,14 @@
public SystemUI[] getServices() {
return mServices;
}
+
+ private final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ // Update names of SystemUi notification channels
+ NotificationChannels.createAll(context);
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index f08219a..c409f73 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -52,6 +52,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.Duration;
import java.util.Arrays;
public class PowerUI extends SystemUI {
@@ -61,6 +62,8 @@
private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS;
private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3;
+ private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
+ private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
private final Handler mHandler = new Handler();
private final Receiver mReceiver = new Receiver();
@@ -69,7 +72,6 @@
private HardwarePropertiesManager mHardwarePropertiesManager;
private WarningsUI mWarnings;
private final Configuration mLastConfiguration = new Configuration();
- private int mBatteryLevel = 100;
private long mTimeRemaining = Long.MAX_VALUE;
private int mPlugType = 0;
private int mInvalidCharger = 0;
@@ -88,6 +90,7 @@
private long mNextLogTime;
private IThermalService mThermalService;
+ @VisibleForTesting int mBatteryLevel = 100;
@VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
// by using the same instance (method references are not guaranteed to be the same object
@@ -205,12 +208,6 @@
final boolean plugged = mPlugType != 0;
final boolean oldPlugged = oldPlugType != 0;
- // if we are now unplugged but we were previously plugged in we should allow the
- // time based trigger again.
- if (!plugged && plugged != oldPlugged) {
- mLowWarningShownThisChargeCycle = false;
- mSevereWarningShownThisChargeCycle = false;
- }
int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
int bucket = findBatteryLevelBucket(mBatteryLevel);
@@ -261,7 +258,8 @@
boolean isPowerSaver = mPowerManager.isPowerSaveMode();
// only play SFX when the dialog comes up or the bucket changes
final boolean playSound = bucket != oldBucket || oldPlugged;
- if (mEnhancedEstimates.isHybridNotificationEnabled()) {
+ final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
+ if (hybridEnabled) {
final Estimate estimate = mEnhancedEstimates.getEstimate();
// Turbo is not always booted once SysUI is running so we have ot make sure we actually
// get data back
@@ -270,6 +268,14 @@
mWarnings.updateEstimate(estimate);
mWarnings.updateThresholds(mEnhancedEstimates.getLowWarningThreshold(),
mEnhancedEstimates.getSevereWarningThreshold());
+
+ // if we are now over 45% battery & 6 hours remaining we can trigger hybrid
+ // notification again
+ if (mBatteryLevel >= CHARGE_CYCLE_PERCENT_RESET
+ && mTimeRemaining > SIX_HOURS_MILLIS) {
+ mLowWarningShownThisChargeCycle = false;
+ mSevereWarningShownThisChargeCycle = false;
+ }
}
}
@@ -277,13 +283,15 @@
mTimeRemaining, isPowerSaver, mBatteryStatus)) {
mWarnings.showLowBatteryWarning(playSound);
- // mark if we've already shown a warning this cycle. This will prevent the time based
- // trigger from spamming users since the time remaining can vary based on current
- // device usage.
- if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold()) {
- mSevereWarningShownThisChargeCycle = true;
- } else {
- mLowWarningShownThisChargeCycle = true;
+ // mark if we've already shown a warning this cycle. This will prevent the notification
+ // trigger from spamming users by only showing low/critical warnings once per cycle
+ if (hybridEnabled) {
+ if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
+ || mBatteryLevel < mLowBatteryReminderLevels[1]) {
+ mSevereWarningShownThisChargeCycle = true;
+ } else {
+ mLowWarningShownThisChargeCycle = true;
+ }
}
} else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
isPowerSaver)) {
@@ -295,12 +303,16 @@
@VisibleForTesting
boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
- int bucket, long timeRemaining, boolean isPowerSaver, int mBatteryStatus) {
+ int bucket, long timeRemaining, boolean isPowerSaver, int batteryStatus) {
+ if (mEnhancedEstimates.isHybridNotificationEnabled()) {
+ // triggering logic when enhanced estimate is available
+ return isEnhancedTrigger(plugged, timeRemaining, isPowerSaver, batteryStatus);
+ }
+ // legacy triggering logic
return !plugged
&& !isPowerSaver
- && (((bucket < oldBucket || oldPlugged) && bucket < 0)
- || isTimeBasedTrigger(timeRemaining))
- && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ && (((bucket < oldBucket || oldPlugged) && bucket < 0))
+ && batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
}
@VisibleForTesting
@@ -315,19 +327,23 @@
|| hybridWouldDismiss));
}
- private boolean isTimeBasedTrigger(long timeRemaining) {
- if (!mEnhancedEstimates.isHybridNotificationEnabled()) {
+ private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver,
+ int batteryStatus) {
+ if (plugged || isPowerSaver || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return false;
}
+ int warnLevel = mLowBatteryReminderLevels[0];
+ int critLevel = mLowBatteryReminderLevels[1];
- // Only show the time based warning once per charge cycle
- final boolean canShowWarning = timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
- && !mLowWarningShownThisChargeCycle;
+ // Only show the low warning once per charge cycle
+ final boolean canShowWarning = !mLowWarningShownThisChargeCycle
+ && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
+ || mBatteryLevel <= warnLevel);
- // Only show the severe time based warning once per charge cycle
- final boolean canShowSevereWarning =
- timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
- && !mSevereWarningShownThisChargeCycle;
+ // Only show the severe warning once per charge cycle
+ final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
+ && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
+ || mBatteryLevel <= critLevel);
return canShowWarning || canShowSevereWarning;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 8923952..c548cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -167,6 +167,13 @@
}
}
+ @Override
+ public void setExpansion(float expansion) {
+ for (TileRecord tr : mTiles) {
+ tr.tileView.setExpansion(expansion);
+ }
+ }
+
public void setPageListener(PageListener listener) {
mPageListener = listener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 29f3c43..018a635 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -291,6 +291,7 @@
mHeader.setExpansion(mKeyguardShowing, expansion, panelTranslationY);
mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
mQSPanel.getQsTileRevealController().setExpansion(expansion);
+ mQSPanel.getTileLayout().setExpansion(expansion);
mQSPanel.setTranslationY(translationScaleY * heightDiff);
mQSDetail.setFullyExpanded(fullyExpanded);
@@ -359,7 +360,6 @@
// The customize state changed, so our height changed.
mContainer.updateExpansion();
mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
- mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
// Let the panel know the position changed and it needs to update where notifications
// and whatnot are.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 61e3065..6368a6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -616,5 +616,7 @@
boolean updateResources();
void setListening(boolean listening);
+
+ default void setExpansion(float expansion) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 0ac8b9c..df65d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -47,7 +47,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.R.id;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSDetail.Callback;
@@ -161,7 +160,6 @@
// Set light text on the header icons because they will always be on a black background
applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
- applyDarkness(id.signal_cluster, tintArea, intensity, colorForeground);
// Set the correct tint for the status icons so they contrast
mIconManager.setTint(fillColor);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 1cb89c4..64e7a63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -23,6 +23,7 @@
protected int mCellHeight;
protected int mCellMarginHorizontal;
protected int mCellMarginVertical;
+ protected int mSidePadding;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private int mCellMarginTop;
@@ -80,6 +81,7 @@
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
+ mSidePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_layout_margin_side);
if (mColumns != columns) {
mColumns = columns;
requestLayout();
@@ -93,7 +95,7 @@
final int numTiles = mRecords.size();
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int numRows = (numTiles + mColumns - 1) / mColumns;
- mCellWidth = (width - (mCellMarginHorizontal * (mColumns + 1))) / mColumns;
+ mCellWidth = (width - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
// Measure each QS tile.
View previousView = this;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
index ec18376..31c455d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
@@ -44,7 +44,6 @@
float intensity = colorForeground == Color.WHITE ? 0f : 1f;
Rect tintArea = new Rect(0, 0, 0, 0);
- applyDarkness(R.id.signal_cluster, tintArea, intensity, colorForeground);
applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index a3d6c6c..4aa83d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
@@ -37,6 +38,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
@@ -81,10 +83,9 @@
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
- mClipper = new QSDetailClipper(this);
LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
-
+ mClipper = new QSDetailClipper(findViewById(R.id.customize_container));
mToolbar = findViewById(com.android.internal.R.id.action_bar);
TypedValue value = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
@@ -100,7 +101,10 @@
mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
mToolbar.setTitle(R.string.qs_edit);
-
+ int accentColor = Utils.getColorAttr(context, android.R.attr.colorAccent);
+ mToolbar.setTitleTextColor(accentColor);
+ mToolbar.getNavigationIcon().setTint(accentColor);
+ mToolbar.getOverflowIcon().setTint(accentColor);
mRecyclerView = findViewById(android.R.id.list);
mTileAdapter = new TileAdapter(getContext());
mTileQueryHelper = new TileQueryHelper(context, mTileAdapter);
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 943a176..6f664d7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -102,7 +102,9 @@
mTokenMap.remove(service.getToken());
mTiles.remove(tile.getComponent());
final String slot = tile.getComponent().getClassName();
- mMainHandler.post(() -> mHost.getIconController().removeIcon(slot));
+ // TileServices doesn't know how to add more than 1 icon per slot, so remove all
+ mMainHandler.post(() -> mHost.getIconController()
+ .removeAllIconsForSlot(slot));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index a9defc8..09d928f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -194,6 +194,7 @@
setClickable(state.state != Tile.STATE_UNAVAILABLE);
mIcon.setIcon(state);
setContentDescription(state.contentDescription);
+
mAccessibilityClass = state.expandedAccessibilityClassName;
if (state instanceof QSTile.BooleanState) {
boolean newState = ((BooleanState) state).value;
@@ -269,6 +270,10 @@
info.setText(label);
info.setChecked(b);
info.setCheckable(true);
+ info.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.getId(),
+ getResources().getString(R.string.accessibility_long_click_tile)));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 3cb4c71..d21b06f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -32,12 +32,10 @@
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
-
import java.util.Objects;
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
- private static final int DEFAULT_MAX_LINES = 2;
private static final boolean DUAL_TARGET_ALLOWED = false;
private View mDivider;
protected TextView mLabel;
@@ -87,22 +85,17 @@
mLabelContainer.setClipChildren(false);
mLabelContainer.setClipToPadding(false);
mLabel = mLabelContainer.findViewById(R.id.tile_label);
- mLabel.setSelected(true); // Allow marquee to work.
mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock);
mDivider = mLabelContainer.findViewById(R.id.underline);
mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator);
mExpandSpace = mLabelContainer.findViewById(R.id.expand_space);
mSecondLine = mLabelContainer.findViewById(R.id.app_label);
mSecondLine.setAlpha(.6f);
- mSecondLine.setSelected(true); // Allow marquee to work.
addView(mLabelContainer);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mLabel.getMaxLines() != DEFAULT_MAX_LINES) {
- mLabel.setMaxLines(DEFAULT_MAX_LINES);
- }
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Remeasure view if the secondary label text will be cut off.
@@ -114,6 +107,15 @@
}
@Override
+ public void setExpansion(float expansion) {
+ // Start the marquee when fully expanded and stop when fully collapsed. Leave as is for
+ // other expansion ratios since there is no way way to pause the marquee.
+ boolean selected = expansion == 1f ? true : expansion == 0f ? false : mLabel.isSelected();
+ mLabel.setSelected(selected);
+ mSecondLine.setSelected(selected);
+ }
+
+ @Override
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
if (!Objects.equals(mLabel.getText(), state.label) || mState != state.state) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 674ccd8..0f85c5b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -492,6 +492,13 @@
}
}
mDraggingInRecentsCurrentUser = currentUser;
+
+ if (mOverviewProxyService.getProxy() != null) {
+ // The overview service is handling split screen, so just skip the wait for the
+ // first draw and notify the divider to start animating now
+ EventBus.getDefault().post(new RecentsDrawnEvent());
+ }
+
return true;
} else {
EventBus.getDefault().send(new ShowUserToastEvent(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 03b263d..3ece2f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
@@ -25,7 +24,10 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
+import android.app.NotificationChannel;
import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Path;
@@ -39,6 +41,7 @@
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Log;
import android.util.MathUtils;
import android.util.Property;
import android.view.KeyEvent;
@@ -90,12 +93,17 @@
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
+/**
+ * View representing a notification item - this can be either the individual child notification or
+ * the group summary (which contains 1 or more child notifications).
+ */
public class ExpandableNotificationRow extends ActivatableNotificationView
implements PluginListener<NotificationMenuRowPlugin> {
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
private static final int MENU_VIEW_INDEX = 0;
+ private static final String TAG = "ExpandableNotifRow";
public interface LayoutListener {
public void onLayout();
@@ -166,6 +174,8 @@
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
+ private PackageManager mCachedPackageManager;
+ private PackageInfo mCachedPackageInfo;
private String mAppName;
private boolean mIsHeadsUp;
private boolean mLastChronometerRunning = true;
@@ -372,6 +382,53 @@
mEntry = entry;
mStatusBarNotification = entry.notification;
mNotificationInflater.inflateNotificationViews();
+
+ perhapsCachePackageInfo();
+ }
+
+ /**
+ * Caches the package manager and info objects which are expensive to obtain.
+ */
+ private void perhapsCachePackageInfo() {
+ if (mCachedPackageInfo == null) {
+ mCachedPackageManager = StatusBar.getPackageManagerForUser(
+ mContext, mStatusBarNotification.getUser().getIdentifier());
+ try {
+ mCachedPackageInfo = mCachedPackageManager.getPackageInfo(
+ mStatusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "perhapsCachePackageInfo: Could not find package info");
+ }
+ }
+ }
+
+ /**
+ * Returns whether this row is considered non-blockable (e.g. it's a non-blockable system notif,
+ * covers multiple channels, or is in a whitelist).
+ */
+ public boolean getIsNonblockable() {
+ boolean isNonblockable;
+
+ isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
+ .isNonblockablePackage(mStatusBarNotification.getPackageName());
+
+ // Only bother with going through the children if the row is still blockable based on the
+ // number of unique channels.
+ if (!isNonblockable) {
+ isNonblockable = getNumUniqueChannels() > 1;
+ }
+
+ // Only bother with IPC if the package is still blockable.
+ if (!isNonblockable && mCachedPackageManager != null && mCachedPackageInfo != null) {
+ if (com.android.settingslib.Utils.isSystemPackage(
+ mContext.getResources(), mCachedPackageManager, mCachedPackageInfo)) {
+ if (mEntry.channel != null
+ && !mEntry.channel.isBlockableSystem()) {
+ isNonblockable = true;
+ }
+ }
+ }
+ return isNonblockable;
}
public void onNotificationUpdated() {
@@ -2019,6 +2076,32 @@
updateChildrenVisibility();
applyChildrenRoundness();
}
+ /**
+ * Returns the number of channels covered by the notification row (including its children if
+ * it's a summary notification).
+ */
+ public int getNumUniqueChannels() {
+ ArraySet<NotificationChannel> channels = new ArraySet<>();
+
+ channels.add(mEntry.channel);
+
+ // If this is a summary, then add in the children notification channels for the
+ // same user and pkg.
+ if (mIsSummaryWithChildren) {
+ final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
+ final int numChildren = childrenRows.size();
+ for (int i = 0; i < numChildren; i++) {
+ final ExpandableNotificationRow childRow = childrenRows.get(i);
+ final NotificationChannel childChannel = childRow.getEntry().channel;
+ final StatusBarNotification childSbn = childRow.getStatusBarNotification();
+ if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
+ childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
+ channels.add(childChannel);
+ }
+ }
+ }
+ return channels.size();
+ }
public void updateChildrenHeaderAppearance() {
if (mIsSummaryWithChildren) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NeutralGoodDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/NeutralGoodDrawable.java
new file mode 100644
index 0000000..cdb0514
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NeutralGoodDrawable.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.statusbar;
+
+import android.content.Context;
+import android.content.res.Resources.Theme;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+
+/**
+ * NeutralGoodDrawable implements a drawable that will load 2 underlying drawable resources, one
+ * with each the DualToneDarkTheme and DualToneLightTheme, choosing which one based on what
+ * DarkIconDispatcher tells us about darkness
+ */
+public class NeutralGoodDrawable extends LayerDrawable {
+
+ public static NeutralGoodDrawable create(Context context, int resId) {
+ int dualToneLightTheme = Utils.getThemeAttr(context, R.attr.lightIconTheme);
+ int dualToneDarkTheme = Utils.getThemeAttr(context, R.attr.darkIconTheme);
+ ContextThemeWrapper light = new ContextThemeWrapper(context, dualToneLightTheme);
+ ContextThemeWrapper dark = new ContextThemeWrapper(context, dualToneDarkTheme);
+
+ return create(light, dark, resId);
+ }
+
+ /**
+ * For the on-the-go young entrepreneurial who wants to cache contexts
+ * @param light - a context using the R.attr.lightIconTheme
+ * @param dark - a context using the R.attr.darkIconTheme
+ * @param resId - the resId for our drawable
+ */
+ public static NeutralGoodDrawable create(Context light, Context dark, int resId) {
+ return new NeutralGoodDrawable(
+ new Drawable[] {
+ light.getDrawable(resId).mutate(),
+ dark.getDrawable(resId).mutate() });
+ }
+
+ protected NeutralGoodDrawable(Drawable []drawables) {
+ super(drawables);
+
+ for (int i = 0; i < drawables.length; i++) {
+ setLayerGravity(i, Gravity.CENTER);
+ }
+
+ mutate();
+ setDarkIntensity(0);
+ }
+
+ public void setDarkIntensity(float intensity) {
+
+ getDrawable(0).setAlpha((int) ((1 - intensity) * 255f));
+ getDrawable(1).setAlpha((int) (intensity * 255f));
+
+ invalidateSelf();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
index c9c1bc6..20e5f86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
@@ -17,11 +17,19 @@
package com.android.systemui.statusbar;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
@@ -37,6 +45,7 @@
private final Context mContext;
/** Row that the blocking helper will be shown in (via {@link NotificationGuts}. */
private ExpandableNotificationRow mBlockingHelperRow;
+ private Set<String> mNonBlockablePkgs;
/**
* Whether the notification shade/stack is expanded - used to determine blocking helper
@@ -46,6 +55,9 @@
public NotificationBlockingHelperManager(Context context) {
mContext = context;
+ mNonBlockablePkgs = new HashSet<>();
+ Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_nonBlockableNotificationPackages));
}
/**
@@ -59,15 +71,14 @@
*/
boolean perhapsShowBlockingHelper(
ExpandableNotificationRow row, NotificationMenuRowPlugin menuRow) {
- int numChildren = row.getNumberOfNotificationChildren();
-
// We only show the blocking helper if:
- // - The dismissed row is a valid group (>1 or 0 children) or the only child in the group
+ // - User sentiment is negative (DEBUG flag can bypass)
// - The notification shade is fully expanded (guarantees we're not touching a HUN).
- // - User sentiment is negative
- if (DEBUG
- || row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE
+ // - The row is blockable (i.e. not non-blockable)
+ // - The dismissed row is a valid group (>1 or 0 children) or the only child in the group
+ if ((row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE || DEBUG)
&& mIsShadeExpanded
+ && !row.getIsNonblockable()
&& (!row.isChildInGroup() || row.isOnlyChildInGroup())) {
// Dismiss any current blocking helper before continuing forward (only one can be shown
// at a given time).
@@ -125,6 +136,13 @@
mIsShadeExpanded = expandedHeight > 0.0f;
}
+ /**
+ * Returns whether the given package name is in the list of non-blockable packages.
+ */
+ public boolean isNonblockablePackage(String packageName) {
+ return mNonBlockablePkgs.contains(packageName);
+ }
+
@VisibleForTesting
boolean isBlockingHelperRowNull() {
return mBlockingHelperRow == null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index 75204d9..dff5f38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -65,7 +65,6 @@
private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
- private final Set<String> mNonBlockablePkgs;
private final Context mContext;
private final AccessibilityManager mAccessibilityManager;
@@ -87,10 +86,6 @@
mContext = context;
Resources res = context.getResources();
- mNonBlockablePkgs = new HashSet<>();
- Collections.addAll(mNonBlockablePkgs, res.getStringArray(
- com.android.internal.R.array.config_nonBlockableNotificationPackages));
-
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
@@ -279,12 +274,12 @@
iNotificationManager,
packageName,
row.getEntry().channel,
- getNumNotificationChannels(row, packageName, userHandle),
+ row.getNumUniqueChannels(),
sbn,
mCheckSaveListener,
onSettingsClick,
onAppSettingsClick,
- mNonBlockablePkgs,
+ row.getIsNonblockable(),
isForBlockingHelper,
row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
} catch (RemoteException e) {
@@ -293,34 +288,6 @@
}
/**
- * @return the number of channels covered by the notification row (including its children if
- * it's a summary notification).
- */
- private int getNumNotificationChannels(
- ExpandableNotificationRow row, String packageName, UserHandle userHandle) {
- ArraySet<NotificationChannel> channels = new ArraySet<>();
-
- channels.add(row.getEntry().channel);
-
- // If this is a summary, then add in the children notification channels for the
- // same user and pkg.
- if (row.isSummaryWithChildren()) {
- final List<ExpandableNotificationRow> childrenRows = row.getNotificationChildren();
- final int numChildren = childrenRows.size();
- for (int i = 0; i < numChildren; i++) {
- final ExpandableNotificationRow childRow = childrenRows.get(i);
- final NotificationChannel childChannel = childRow.getEntry().channel;
- final StatusBarNotification childSbn = childRow.getStatusBarNotification();
- if (childSbn.getUser().equals(userHandle) &&
- childSbn.getPackageName().equals(packageName)) {
- channels.add(childChannel);
- }
- }
- }
- return channels.size();
- }
-
- /**
* Closes guts or notification menus that might be visible and saves any changes.
*
* @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 82ad74e..a93be00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -31,7 +31,6 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
@@ -49,13 +48,11 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import java.util.List;
-import java.util.Set;
/**
* The guts of a notification revealed when performing a long press.
@@ -74,7 +71,7 @@
private int mStartingUserImportance;
private int mChosenImportance;
private boolean mIsSingleDefaultChannel;
- private boolean mNonblockable;
+ private boolean mIsNonblockable;
private StatusBarNotification mSbn;
private AnimatorSet mExpandAnimation;
private boolean mIsForeground;
@@ -128,10 +125,10 @@
final CheckSaveListener checkSaveListener,
final OnSettingsClickListener onSettingsClick,
final OnAppSettingsClickListener onAppSettingsClick,
- final Set<String> nonBlockablePkgs)
+ boolean isNonblockable)
throws RemoteException {
bindNotification(pm, iNotificationManager, pkg, notificationChannel, numChannels, sbn,
- checkSaveListener, onSettingsClick, onAppSettingsClick, nonBlockablePkgs,
+ checkSaveListener, onSettingsClick, onAppSettingsClick, isNonblockable,
false /* isBlockingHelper */,
false /* isUserSentimentNegative */);
}
@@ -146,7 +143,7 @@
CheckSaveListener checkSaveListener,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
- Set<String> nonBlockablePkgs,
+ boolean isNonblockable,
boolean isForBlockingHelper,
boolean isUserSentimentNegative)
throws RemoteException {
@@ -162,6 +159,7 @@
mSingleNotificationChannel = notificationChannel;
mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
mNegativeUserSentiment = isUserSentimentNegative;
+ mIsNonblockable = isNonblockable;
mIsForeground =
(mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
mIsForBlockingHelper = isForBlockingHelper;
@@ -179,22 +177,6 @@
&& numTotalChannels == 1;
}
- try {
- final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
- if (Utils.isSystemPackage(getResources(), pm, pkgInfo)) {
- if (mSingleNotificationChannel != null
- && !mSingleNotificationChannel.isBlockableSystem()) {
- mNonblockable = true;
- }
- }
- } catch (PackageManager.NameNotFoundException e) {
- // unlikely.
- }
- if (nonBlockablePkgs != null) {
- mNonblockable |= nonBlockablePkgs.contains(pkg);
- }
- mNonblockable |= (mNumNotificationChannels > 1);
-
bindHeader();
bindPrompt();
bindButtons();
@@ -261,7 +243,7 @@
private void bindPrompt() {
final TextView blockPrompt = findViewById(R.id.block_prompt);
bindName();
- if (mNonblockable) {
+ if (mIsNonblockable) {
blockPrompt.setText(R.string.notification_unblockable_desc);
} else {
if (mNegativeUserSentiment) {
@@ -288,7 +270,7 @@
}
private void saveImportance() {
- if (mNonblockable) {
+ if (mIsNonblockable) {
return;
}
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
@@ -314,7 +296,7 @@
keep.setOnClickListener(mOnKeepShowing);
minimize.setOnClickListener(mOnStopMinNotifications);
- if (mNonblockable) {
+ if (mIsNonblockable) {
keep.setText(R.string.notification_done);
block.setVisibility(GONE);
minimize.setVisibility(GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java
new file mode 100644
index 0000000..56f78f4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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.statusbar;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Holds an array of {@link com.android.internal.statusbar.StatusBarIcon}s and draws them
+ * in a linear layout
+ */
+public class StatusBarIconContainer {
+ private final List<StatusBarIcon> mIcons = new ArrayList<>();
+
+ public StatusBarIconContainer(List<StatusBarIcon> icons) {
+ mIcons.addAll(icons);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 603902a..bd6bd12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -23,6 +25,7 @@
import android.app.Notification;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -56,7 +59,7 @@
import java.text.NumberFormat;
import java.util.Arrays;
-public class StatusBarIconView extends AnimatedImageView {
+public class StatusBarIconView extends AnimatedImageView implements StatusIconDisplayable {
public static final int NO_COLOR = 0;
/**
@@ -867,6 +870,21 @@
mOnDismissListener = onDismissListener;
}
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ setImageTintList(ColorStateList.valueOf(getTint(area, this, tint)));
+ }
+
+ @Override
+ public boolean isIconVisible() {
+ return mIcon != null && mIcon.visible;
+ }
+
+ @Override
+ public boolean isIconBlocked() {
+ return mBlocked;
+ }
+
public interface OnVisibilityChangedListener {
void onVisibilityChanged(int newVisibility);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
new file mode 100644
index 0000000..b7620f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.AlphaOptimizedLinearLayout;
+import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+
+public class StatusBarMobileView extends AlphaOptimizedLinearLayout implements DarkReceiver,
+ StatusIconDisplayable {
+ private static final String TAG = "StatusBarMobileView";
+
+ private String mSlot;
+ private MobileIconState mState;
+ private SignalDrawable mMobileDrawable;
+ private View mInoutContainer;
+ private ImageView mIn;
+ private ImageView mOut;
+ private ImageView mMobile, mMobileType, mMobileRoaming;
+ private View mMobileRoamingSpace;
+
+ public static StatusBarMobileView fromContext(Context context) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+
+ return (StatusBarMobileView)
+ inflater.inflate(R.layout.status_bar_mobile_signal_group, null);
+ }
+
+ public StatusBarMobileView(Context context) {
+ super(context);
+ }
+
+ public StatusBarMobileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ init();
+ }
+
+ private void init() {
+ mMobile = findViewById(R.id.mobile_signal);
+ mMobileType = findViewById(R.id.mobile_type);
+ mMobileRoaming = findViewById(R.id.mobile_roaming);
+ mMobileRoamingSpace = findViewById(R.id.mobile_roaming_space);
+ mIn = findViewById(R.id.mobile_in);
+ mOut = findViewById(R.id.mobile_out);
+ mInoutContainer = findViewById(R.id.inout_container);
+
+ mMobileDrawable = new SignalDrawable(getContext());
+ mMobile.setImageDrawable(mMobileDrawable);
+ }
+
+ public void applyMobileState(MobileIconState state) {
+ if (state == null) {
+ setVisibility(View.GONE);
+ mState = null;
+ return;
+ }
+
+ if (mState == null) {
+ mState = state;
+ initViewState();
+ return;
+ }
+
+ if (!mState.equals(state)) {
+ updateState(state);
+ }
+ }
+
+ private void initViewState() {
+ setContentDescription(mState.contentDescription);
+ if (!mState.visible) {
+ setVisibility(View.GONE);
+ } else {
+ setVisibility(View.VISIBLE);
+ }
+ mMobileDrawable.setLevel(mState.strengthId);
+ if (mState.typeId > 0) {
+ mMobileType.setContentDescription(mState.typeContentDescription);
+ mMobileType.setImageResource(mState.typeId);
+ mMobileType.setVisibility(View.VISIBLE);
+ } else {
+ mMobileType.setVisibility(View.GONE);
+ }
+
+ mMobileRoaming.setVisibility(mState.roaming ? View.VISIBLE : View.GONE);
+ mMobileRoamingSpace.setVisibility(mState.roaming ? View.VISIBLE : View.GONE);
+ mIn.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
+ mOut.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
+ mInoutContainer.setVisibility((mState.activityIn || mState.activityOut)
+ ? View.VISIBLE : View.GONE);
+ }
+
+ private void updateState(MobileIconState state) {
+ setContentDescription(state.contentDescription);
+ if (mState.visible != state.visible) {
+ setVisibility(state.visible ? View.VISIBLE : View.GONE);
+ }
+ if (mState.strengthId != state.strengthId) {
+ mMobileDrawable.setLevel(state.strengthId);
+ }
+ if (mState.typeId != state.typeId && state.typeId != 0) {
+ mMobileType.setContentDescription(state.typeContentDescription);
+ mMobileType.setImageResource(state.typeId);
+ mMobileType.setVisibility(View.VISIBLE);
+ } else {
+ mMobileType.setVisibility(View.GONE);
+ }
+
+ mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
+ mMobileRoamingSpace.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
+ mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
+ mOut.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
+ mInoutContainer.setVisibility((state.activityIn || state.activityOut)
+ ? View.VISIBLE : View.GONE);
+
+ mState = state;
+ }
+
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ mMobileDrawable.setDarkIntensity(darkIntensity);
+ ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
+ mIn.setImageTintList(color);
+ mOut.setImageTintList(color);
+ mMobileType.setImageTintList(color);
+ mMobileRoaming.setImageTintList(color);
+ }
+
+ @Override
+ public String getSlot() {
+ return mSlot;
+ }
+
+ public void setSlot(String slot) {
+ mSlot = slot;
+ }
+
+ @Override
+ public void setStaticDrawableColor(int color) {
+ ColorStateList list = ColorStateList.valueOf(color);
+ float intensity = color == Color.WHITE ? 0 : 1;
+ mMobileDrawable.setDarkIntensity(intensity);
+
+ mIn.setImageTintList(list);
+ mOut.setImageTintList(list);
+ mMobileType.setImageTintList(list);
+ mMobileRoaming.setImageTintList(list);
+ }
+
+ @Override
+ public boolean isIconVisible() {
+ return mState.visible;
+ }
+
+ @VisibleForTesting
+ public MobileIconState getState() {
+ return mState;
+ }
+
+ @Override
+ public String toString() {
+ return "StatusBarMobileView(slot=" + mSlot + " state=" + mState + ")";
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
new file mode 100644
index 0000000..afd373e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.keyguard.AlphaOptimizedLinearLayout;
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+
+/**
+ * Start small: StatusBarWifiView will be able to layout from a WifiIconState
+ */
+public class StatusBarWifiView extends AlphaOptimizedLinearLayout implements DarkReceiver,
+ StatusIconDisplayable {
+ private static final String TAG = "StatusBarWifiView";
+
+ private ImageView mWifiIcon;
+ private ImageView mIn;
+ private ImageView mOut;
+ private View mInoutContainer;
+ private View mSignalSpacer;
+ private View mAirplaneSpacer;
+ private WifiIconState mState;
+ private String mSlot;
+ private float mDarkIntensity = 0;
+
+ private ContextThemeWrapper mDarkContext;
+ private ContextThemeWrapper mLightContext;
+
+ public static StatusBarWifiView fromContext(Context context) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ return (StatusBarWifiView) inflater.inflate(R.layout.status_bar_wifi_group, null);
+ }
+
+ public StatusBarWifiView(Context context) {
+ super(context);
+ }
+
+ public StatusBarWifiView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public StatusBarWifiView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public StatusBarWifiView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ init();
+ }
+
+ public void setSlot(String slot) {
+ mSlot = slot;
+ }
+
+ @Override
+ public void setStaticDrawableColor(int color) {
+ ColorStateList list = ColorStateList.valueOf(color);
+ mWifiIcon.setImageTintList(list);
+ mIn.setImageTintList(list);
+ mOut.setImageTintList(list);
+ }
+
+ @Override
+ public String getSlot() {
+ return mSlot;
+ }
+
+ @Override
+ public boolean isIconVisible() {
+ return mState != null && mState.visible;
+ }
+
+ private void init() {
+ int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme);
+ int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
+ mLightContext = new ContextThemeWrapper(mContext, dualToneLightTheme);
+ mDarkContext = new ContextThemeWrapper(mContext, dualToneDarkTheme);
+
+ mWifiIcon = findViewById(R.id.wifi_signal);
+ mIn = findViewById(R.id.wifi_in);
+ mOut = findViewById(R.id.wifi_out);
+ mSignalSpacer = findViewById(R.id.wifi_signal_spacer);
+ mAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer);
+ mInoutContainer = findViewById(R.id.inout_container);
+ }
+
+ public void applyWifiState(WifiIconState state) {
+ if (state == null) {
+ setVisibility(View.GONE);
+ mState = null;
+ return;
+ }
+
+ if (mState == null) {
+ mState = state;
+ initViewState();
+ }
+
+ if (!mState.equals(state)) {
+ updateState(state);
+ }
+ }
+
+ private void updateState(WifiIconState state) {
+ if (mState.resId != state.resId && state.resId >= 0) {
+ NeutralGoodDrawable drawable = NeutralGoodDrawable
+ .create(mLightContext, mDarkContext, state.resId);
+ drawable.setDarkIntensity(mDarkIntensity);
+ mWifiIcon.setImageDrawable(drawable);
+ }
+
+ mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
+ mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
+ mInoutContainer.setVisibility(
+ (state.activityIn || state.activityOut) ? View.VISIBLE : View.GONE);
+ mAirplaneSpacer.setVisibility(state.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
+ mSignalSpacer.setVisibility(state.signalSpacerVisible ? View.VISIBLE : View.GONE);
+ if (mState.visible != state.visible) {
+ setVisibility(state.visible ? View.VISIBLE : View.GONE);
+ }
+
+ mState = state;
+ }
+
+ private void initViewState() {
+ if (mState.resId >= 0) {
+ NeutralGoodDrawable drawable = NeutralGoodDrawable.create(
+ mLightContext, mDarkContext, mState.resId);
+ drawable.setDarkIntensity(mDarkIntensity);
+ mWifiIcon.setImageDrawable(drawable);
+ }
+
+ mIn.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
+ mOut.setVisibility(mState.activityOut ? View.VISIBLE : View.GONE);
+ mInoutContainer.setVisibility(
+ (mState.activityIn || mState.activityOut) ? View.VISIBLE : View.GONE);
+ mAirplaneSpacer.setVisibility(mState.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
+ mSignalSpacer.setVisibility(mState.signalSpacerVisible ? View.VISIBLE : View.GONE);
+ setVisibility(mState.visible ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ mDarkIntensity = darkIntensity;
+ Drawable d = mWifiIcon.getDrawable();
+ if (d instanceof NeutralGoodDrawable) {
+ ((NeutralGoodDrawable)d).setDarkIntensity(darkIntensity);
+ }
+ mIn.setImageTintList(ColorStateList.valueOf(getTint(area, this, tint)));
+ mOut.setImageTintList(ColorStateList.valueOf(getTint(area, this, tint)));
+ }
+
+
+ @Override
+ public String toString() {
+ return "StatusBarWifiView(slot=" + mSlot + " state=" + mState + ")";
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
new file mode 100644
index 0000000..ccab0d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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.statusbar;
+
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+
+public interface StatusIconDisplayable extends DarkReceiver {
+ String getSlot();
+ void setStaticDrawableColor(int color);
+ boolean isIconVisible();
+ default boolean isIconBlocked() {
+ return false;
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
index 2841136..b7d501e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -46,6 +46,12 @@
}
}
+ public void removeAll() {
+ mButtonsByCategory.clear();
+ mButtonsByPackage.clear();
+ mSelectedFacetButton = null;
+ }
+
/**
* This will unselect the currently selected CarFacetButton and determine which one should be
* selected next. It does this by reading the properties on the CarFacetButton and seeing if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index a95d0a4..3530e0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import java.io.FileDescriptor;
@@ -80,12 +81,16 @@
private boolean mShowRight;
private boolean mShowBottom;
private CarFacetButtonController mCarFacetButtonController;
+ private ActivityManagerWrapper mActivityManagerWrapper;
+ private DeviceProvisionedController mDeviceProvisionedController;
+ private boolean mDeviceIsProvisioned = true;
@Override
public void start() {
super.start();
mTaskStackListener = new TaskStackListenerImpl();
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+ mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
+ mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener);
mStackScroller.setScrollingEnabled(true);
@@ -96,12 +101,54 @@
Log.d(TAG, "Connecting to HVAC service");
Dependency.get(HvacController.class).connectToCarService();
}
+ mCarFacetButtonController = Dependency.get(CarFacetButtonController.class);
+ mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+ mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned();
+ if (!mDeviceIsProvisioned) {
+ mDeviceProvisionedController.addCallback(
+ new DeviceProvisionedController.DeviceProvisionedListener() {
+ @Override
+ public void onDeviceProvisionedChanged() {
+ mDeviceIsProvisioned =
+ mDeviceProvisionedController.isDeviceProvisioned();
+ restartNavBars();
+ }
+ });
+ }
}
+ /**
+ * Remove all content from navbars and rebuild them. Used to allow for different nav bars
+ * before and after the device is provisioned
+ */
+ private void restartNavBars() {
+ mCarFacetButtonController.removeAll();
+ if (ENABLE_HVAC_CONNECTION) {
+ Dependency.get(HvacController.class).removeAllComponents();
+ }
+ if (mNavigationBarWindow != null) {
+ mNavigationBarWindow.removeAllViews();
+ mNavigationBarView = null;
+ }
+
+ if (mLeftNavigationBarWindow != null) {
+ mLeftNavigationBarWindow.removeAllViews();
+ mLeftNavigationBarView = null;
+ }
+
+ if (mRightNavigationBarWindow != null) {
+ mRightNavigationBarWindow.removeAllViews();
+ mRightNavigationBarView = null;
+ }
+ buildNavBarContent();
+ }
+
+
@Override
public void destroy() {
mCarBatteryController.stopListening();
mConnectedDeviceSignalController.stopListening();
+ mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener);
if (mNavigationBarWindow != null) {
mWindowManager.removeViewImmediate(mNavigationBarWindow);
@@ -117,10 +164,10 @@
mWindowManager.removeViewImmediate(mRightNavigationBarWindow);
mRightNavigationBarView = null;
}
-
super.destroy();
}
+
@Override
protected void makeStatusBarView() {
super.makeStatusBarView();
@@ -167,129 +214,132 @@
@Override
protected void createNavigationBar() {
- mCarFacetButtonController = Dependency.get(CarFacetButtonController.class);
- if (mNavigationBarView != null) {
- return;
- }
-
mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
- if (mShowBottom) {
- buildBottomBar();
- }
-
- int widthForSides = mContext.getResources().getDimensionPixelSize(
- R.dimen.navigation_bar_height_car_mode);
-
-
mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
-
- if (mShowLeft) {
- buildLeft(widthForSides);
- }
-
mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+ buildNavBarWindows();
+ buildNavBarContent();
+ attachNavBarWindows();
+ }
+
+ private void buildNavBarContent() {
+ if (mShowBottom) {
+ buildBottomBar((mDeviceIsProvisioned) ? R.layout.car_navigation_bar :
+ R.layout.car_navigation_bar_unprovisioned);
+ }
+
+ if (mShowLeft) {
+ buildLeft((mDeviceIsProvisioned) ? R.layout.car_left_navigation_bar :
+ R.layout.car_left_navigation_bar_unprovisioned);
+ }
+
if (mShowRight) {
- buildRight(widthForSides);
+ buildRight((mDeviceIsProvisioned) ? R.layout.car_right_navigation_bar :
+ R.layout.car_right_navigation_bar_unprovisioned);
+ }
+ }
+
+ private void buildNavBarWindows() {
+ if (mShowBottom) {
+
+ mNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ }
+ if (mShowLeft) {
+ mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ }
+ if (mShowRight) {
+ mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
}
}
+ private void attachNavBarWindows() {
- private void buildBottomBar() {
+ if (mShowBottom) {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle("CarNavigationBar");
+ lp.windowAnimations = 0;
+ mWindowManager.addView(mNavigationBarWindow, lp);
+ }
+ if (mShowLeft) {
+ int width = mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_left_navigation_bar_width);
+ WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
+ width, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ leftlp.setTitle("LeftCarNavigationBar");
+ leftlp.windowAnimations = 0;
+ leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ leftlp.gravity = Gravity.LEFT;
+ mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
+ }
+ if (mShowRight) {
+ int width = mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_right_navigation_bar_width);
+ WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
+ width, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ rightlp.setTitle("RightCarNavigationBar");
+ rightlp.windowAnimations = 0;
+ rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ rightlp.gravity = Gravity.RIGHT;
+ mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+ }
+
+ }
+
+ private void buildBottomBar(int layout) {
// SystemUI requires that the navigation bar view have a parent. Since the regular
// StatusBar inflates navigation_bar_window as this parent view, use the same view for the
// CarNavigationBarView.
- mNavigationBarWindow = (ViewGroup) View.inflate(mContext,
- R.layout.navigation_bar_window, null);
- if (mNavigationBarWindow == null) {
- Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
- }
-
-
- View.inflate(mContext, R.layout.car_navigation_bar, mNavigationBarWindow);
+ View.inflate(mContext, layout, mNavigationBarWindow);
mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0);
if (mNavigationBarView == null) {
Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
throw new RuntimeException("Unable to build botom nav bar due to missing layout");
}
mNavigationBarView.setStatusBar(this);
-
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("CarNavigationBar");
- lp.windowAnimations = 0;
-
-
- mWindowManager.addView(mNavigationBarWindow, lp);
}
- private void buildLeft(int widthForSides) {
- mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
- R.layout.navigation_bar_window, null);
- if (mLeftNavigationBarWindow == null) {
- Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
- }
-
- View.inflate(mContext, R.layout.car_left_navigation_bar, mLeftNavigationBarWindow);
+ private void buildLeft(int layout) {
+ View.inflate(mContext, layout, mLeftNavigationBarWindow);
mLeftNavigationBarView = (CarNavigationBarView) mLeftNavigationBarWindow.getChildAt(0);
if (mLeftNavigationBarView == null) {
Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
throw new RuntimeException("Unable to build left nav bar due to missing layout");
}
mLeftNavigationBarView.setStatusBar(this);
-
- WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
- widthForSides, LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- leftlp.setTitle("LeftCarNavigationBar");
- leftlp.windowAnimations = 0;
- leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
- leftlp.gravity = Gravity.LEFT;
- mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
}
- private void buildRight(int widthForSides) {
- mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
- R.layout.navigation_bar_window, null);
- if (mRightNavigationBarWindow == null) {
- Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
- }
-
- View.inflate(mContext, R.layout.car_right_navigation_bar, mRightNavigationBarWindow);
+ private void buildRight(int layout) {
+ View.inflate(mContext, layout, mRightNavigationBarWindow);
mRightNavigationBarView = (CarNavigationBarView) mRightNavigationBarWindow.getChildAt(0);
if (mRightNavigationBarView == null) {
Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
throw new RuntimeException("Unable to build right nav bar due to missing layout");
}
- mRightNavigationBarView.setStatusBar(this);
-
- WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
- widthForSides, LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- rightlp.setTitle("RightCarNavigationBar");
- rightlp.windowAnimations = 0;
- rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
- rightlp.gravity = Gravity.RIGHT;
- mWindowManager.addView(mRightNavigationBarWindow, rightlp);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
index 23bf887..7d283d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
@@ -176,6 +176,14 @@
};
/**
+ * Removes all registered components. This is useful if you need to rebuild the UI since
+ * components self register.
+ */
+ public void removeAllComponents() {
+ mTempComponents.clear();
+ }
+
+ /**
* Key for storing {@link TemperatureView}s in a hash map
*/
private static class HvacKey {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index f42473d..75b31c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -17,8 +17,6 @@
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
-import static com.android.systemui.statusbar.phone.StatusBar.reinflateSignalCluster;
-
import android.annotation.Nullable;
import android.app.Fragment;
import android.app.StatusBarManager;
@@ -34,7 +32,6 @@
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.EncryptionHelper;
@@ -63,7 +60,6 @@
private int mDisabled1;
private StatusBar mStatusBarComponent;
private DarkIconManager mDarkIconManager;
- private SignalClusterView mSignalClusterView;
private View mOperatorNameFrame;
private SignalCallback mSignalCallback = new SignalCallback() {
@@ -99,9 +95,6 @@
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
- mSignalClusterView = mStatusBar.findViewById(R.id.signal_cluster);
- Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSignalClusterView);
- // Default to showing until we know otherwise.
showSystemIconArea(false);
initEmergencyCryptkeeperText();
initOperatorName();
@@ -128,7 +121,6 @@
@Override
public void onDestroyView() {
super.onDestroyView();
- Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSignalClusterView);
Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
if (mNetworkController.hasEmergencyCryptKeeperText()) {
mNetworkController.removeCallback(mSignalCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index 3f9ae80..80c4eb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -69,7 +69,7 @@
mReceivers.remove(object);
}
- public void applyDark(ImageView object) {
+ public void applyDark(DarkReceiver object) {
mReceivers.get(object).onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index edfd02b..48540b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -20,25 +20,33 @@
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.settingslib.Utils;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarMobileView;
+import com.android.systemui.statusbar.StatusBarWifiView;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.policy.LocationControllerImpl;
-import com.android.systemui.util.leak.LeakDetector;
+import java.util.ArrayList;
public class DemoStatusIcons extends StatusIconContainer implements DemoMode, DarkReceiver {
+ private static final String TAG = "DemoStatusIcons";
+
private final LinearLayout mStatusIcons;
+ private final ArrayList<StatusBarMobileView> mMobileViews = new ArrayList<>();
private final int mIconSize;
+ private StatusBarWifiView mWifiView;
private boolean mDemoMode;
private int mColor;
@@ -56,6 +64,7 @@
}
public void remove() {
+ mMobileViews.clear();
((ViewGroup) getParent()).removeView(this);
}
@@ -66,7 +75,7 @@
private void updateColors() {
for (int i = 0; i < getChildCount(); i++) {
- StatusBarIconView child = (StatusBarIconView) getChildAt(i);
+ StatusIconDisplayable child = (StatusIconDisplayable) getChildAt(i);
child.setStaticDrawableColor(mColor);
}
}
@@ -145,6 +154,7 @@
}
}
+ /// Can only be used to update non-signal related slots
private void updateSlot(String slot, String iconPkg, int iconId) {
if (!mDemoMode) return;
if (iconPkg == null) {
@@ -152,7 +162,11 @@
}
int removeIndex = -1;
for (int i = 0; i < getChildCount(); i++) {
- StatusBarIconView v = (StatusBarIconView) getChildAt(i);
+ View child = getChildAt(i);
+ if (!(child instanceof StatusBarIconView)) {
+ continue;
+ }
+ StatusBarIconView v = (StatusBarIconView) child;
if (slot.equals(v.getTag())) {
if (iconId == 0) {
removeIndex = i;
@@ -182,8 +196,101 @@
addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
}
+ public void addDemoWifiView(WifiIconState state) {
+ Log.d(TAG, "addDemoWifiView: ");
+ StatusBarWifiView view = StatusBarWifiView.fromContext(mContext);
+ view.setSlot(state.slot);
+
+ int viewIndex = getChildCount();
+ // If we have mobile views, put wifi before them
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof StatusBarMobileView) {
+ viewIndex = i;
+ break;
+ }
+ }
+
+ mWifiView = view;
+ mWifiView.applyWifiState(state);
+ mWifiView.setStaticDrawableColor(mColor);
+ addView(view, viewIndex);
+ }
+
+ public void updateWifiState(WifiIconState state) {
+ Log.d(TAG, "updateWifiState: ");
+ if (mWifiView == null) {
+ addDemoWifiView(state);
+ } else {
+ mWifiView.applyWifiState(state);
+ }
+ }
+
+ public void addMobileView(MobileIconState state) {
+ Log.d(TAG, "addMobileView: ");
+ StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
+
+ view.setSlot(state.slot);
+ view.applyMobileState(state);
+ view.setStaticDrawableColor(mColor);
+
+ // mobile always goes at the end
+ mMobileViews.add(view);
+ addView(view, getChildCount());
+ }
+
+ public void updateMobileState(MobileIconState state) {
+ Log.d(TAG, "updateMobileState: ");
+ // If the view for this subId exists already, use it
+ for (int i = 0; i < mMobileViews.size(); i++) {
+ StatusBarMobileView view = mMobileViews.get(i);
+ if (view.getState().subId == state.subId) {
+ view.applyMobileState(state);
+ return;
+ }
+ }
+
+ // Else we have to add it
+ addMobileView(state);
+ }
+
+ public void onRemoveIcon(StatusIconDisplayable view) {
+ if (view.getSlot().equals("wifi")) {
+ removeView(mWifiView);
+ mWifiView = null;
+ } else {
+ StatusBarMobileView mobileView = matchingMobileView(view);
+ if (mobileView != null) {
+ removeView(mobileView);
+ mMobileViews.remove(mobileView);
+ }
+ }
+ }
+
+ private StatusBarMobileView matchingMobileView(StatusIconDisplayable otherView) {
+ if (!(otherView instanceof StatusBarMobileView)) {
+ return null;
+ }
+
+ StatusBarMobileView v = (StatusBarMobileView) otherView;
+ for (StatusBarMobileView view : mMobileViews) {
+ if (view.getState().subId == v.getState().subId) {
+ return view;
+ }
+ }
+
+ return null;
+ }
+
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
setColor(DarkIconDispatcher.getTint(area, mStatusIcons, tint));
+
+ if (mWifiView != null) {
+ mWifiView.onDarkChanged(area, darkIntensity, tint);
+ }
+ for (StatusBarMobileView view : mMobileViews) {
+ view.onDarkChanged(area, darkIntensity, tint);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 994c0ab..b817809 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -207,7 +207,6 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
updateLayoutConsideringCutout();
- setSignalClusterLayoutWidth();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -296,17 +295,6 @@
return true;
}
- //TODO: Something is setting signal_cluster to MATCH_PARENT. Why?
- private void setSignalClusterLayoutWidth() {
- View signalCluster = findViewById(R.id.signal_cluster);
- if (signalCluster == null) {
- return;
- }
-
- LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) signalCluster.getLayoutParams();
- lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
- }
-
public void setListening(boolean listening) {
if (listening == mBatteryListening) {
return;
@@ -459,7 +447,6 @@
mIconManager.setTint(iconColor);
Rect tintArea = new Rect(0, 0, 0, 0);
- applyDarkness(R.id.signal_cluster, tintArea, intensity, iconColor);
applyDarkness(R.id.battery, tintArea, intensity, iconColor);
applyDarkness(R.id.clock, tintArea, intensity, iconColor);
// Reload user avatar
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 33c3ee9..3e7b0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -297,7 +297,7 @@
mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
mContext.getString(R.string.accessibility_location_active));
} else {
- mIconController.removeIcon(mSlotLocation);
+ mIconController.removeAllIconsForSlot(mSlotLocation);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index fb1addf..12bdfc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -32,7 +32,7 @@
private final PhoneStatusBarView mView;
private final float mIconAlphaWhenOpaque;
- private View mLeftSide, mStatusIcons, mSignalCluster, mBattery, mClock;
+ private View mLeftSide, mStatusIcons, mBattery, mClock;
private Animator mCurrentAnimation;
public PhoneStatusBarTransitions(PhoneStatusBarView view) {
@@ -45,7 +45,6 @@
public void init() {
mLeftSide = mView.findViewById(R.id.notification_icon_area);
mStatusIcons = mView.findViewById(R.id.statusIcons);
- mSignalCluster = mView.findViewById(R.id.signal_cluster);
mBattery = mView.findViewById(R.id.battery);
mClock = mView.findViewById(R.id.clock);
applyModeBackground(-1, getMode(), false /*animate*/);
@@ -90,7 +89,6 @@
anims.playTogether(
animateTransitionTo(mLeftSide, newAlpha),
animateTransitionTo(mStatusIcons, newAlpha),
- animateTransitionTo(mSignalCluster, newAlpha),
animateTransitionTo(mBattery, newAlphaBC),
animateTransitionTo(mClock, newAlphaBC)
);
@@ -102,7 +100,6 @@
} else {
mLeftSide.setAlpha(newAlpha);
mStatusIcons.setAlpha(newAlpha);
- mSignalCluster.setAlpha(newAlpha);
mBattery.setAlpha(newAlphaBC);
mClock.setAlpha(newAlphaBC);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index beeba83..750d2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -348,6 +348,7 @@
protected boolean mBouncerShowing;
private PhoneStatusBarPolicy mIconPolicy;
+ private StatusBarSignalPolicy mSignalPolicy;
private VolumeComponent mVolumeComponent;
private BrightnessMirrorController mBrightnessMirrorController;
@@ -747,6 +748,7 @@
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
+ mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
mUnlockMethodCache.addListener(this);
@@ -1131,7 +1133,6 @@
}
protected void reevaluateStyles() {
- inflateSignalClusters();
inflateFooterView();
updateFooter();
inflateEmptyShadeView();
@@ -1145,36 +1146,6 @@
}
}
- private void inflateSignalClusters() {
- if (mKeyguardStatusBar != null) reinflateSignalCluster(mKeyguardStatusBar);
- }
-
- public static SignalClusterView reinflateSignalCluster(View view) {
- Context context = view.getContext();
- SignalClusterView signalCluster = view.findViewById(R.id.signal_cluster);
- if (signalCluster != null) {
- ViewParent parent = signalCluster.getParent();
- if (parent instanceof ViewGroup) {
- ViewGroup viewParent = (ViewGroup) parent;
- int index = viewParent.indexOfChild(signalCluster);
- viewParent.removeView(signalCluster);
- SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(context)
- .inflate(R.layout.signal_cluster_view, viewParent, false);
- ViewGroup.MarginLayoutParams layoutParams =
- (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams();
- layoutParams.setMarginsRelative(
- context.getResources().getDimensionPixelSize(
- R.dimen.signal_cluster_margin_start),
- 0, 0, 0);
- newCluster.setLayoutParams(layoutParams);
- viewParent.addView(newCluster, index);
- return newCluster;
- }
- return signalCluster;
- }
- return null;
- }
-
private void inflateEmptyShadeView() {
if (mStackScroller == null) {
return;
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 956bebb..94e004b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -16,12 +16,16 @@
import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_NONE;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -33,19 +37,39 @@
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarMobileView;
+import com.android.systemui.statusbar.StatusBarWifiView;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.util.Utils.DisableStateTracker;
+import java.util.List;
public interface StatusBarIconController {
+ /**
+ * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon
+ * in that slot and not added as a sub slot.
+ */
+ public static final int TAG_PRIMARY = 0;
+
public void addIconGroup(IconManager iconManager);
public void removeIconGroup(IconManager iconManager);
public void setExternalIcon(String slot);
public void setIcon(String slot, int resourceId, CharSequence contentDescription);
public void setIcon(String slot, StatusBarIcon icon);
- public void setIconVisibility(String slotTty, boolean b);
- public void removeIcon(String slot);
+ public void setSignalIcon(String slot, WifiIconState state);
+ public void setMobileIcons(String slot, List<MobileIconState> states);
+ public void setIconVisibility(String slot, boolean b);
+ /**
+ * If you don't know what to pass for `tag`, either remove all icons for slot, or use
+ * TAG_PRIMARY to refer to the first icon at a given slot.
+ */
+ public void removeIcon(String slot, int tag);
+ public void removeAllIconsForSlot(String slot);
public static final String ICON_BLACKLIST = "icon_blacklist";
@@ -79,9 +103,9 @@
@Override
protected void onIconAdded(int index, String slot, boolean blocked,
- StatusBarIcon icon) {
- StatusBarIconView v = addIcon(index, slot, blocked, icon);
- mDarkIconDispatcher.addDarkReceiver(v);
+ StatusBarIconHolder holder) {
+ StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
+ mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
}
@Override
@@ -95,21 +119,21 @@
@Override
protected void destroy() {
for (int i = 0; i < mGroup.getChildCount(); i++) {
- mDarkIconDispatcher.removeDarkReceiver((ImageView) mGroup.getChildAt(i));
+ mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(i));
}
mGroup.removeAllViews();
}
@Override
protected void onRemoveIcon(int viewIndex) {
- mDarkIconDispatcher.removeDarkReceiver((ImageView) mGroup.getChildAt(viewIndex));
+ mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(viewIndex));
super.onRemoveIcon(viewIndex);
}
@Override
public void onSetIcon(int viewIndex, StatusBarIcon icon) {
super.onSetIcon(viewIndex, icon);
- mDarkIconDispatcher.applyDark((ImageView) mGroup.getChildAt(viewIndex));
+ mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex));
}
@Override
@@ -135,17 +159,18 @@
}
@Override
- protected void onIconAdded(int index, String slot, boolean blocked, StatusBarIcon icon) {
- StatusBarIconView v = addIcon(index, slot, blocked, icon);
- v.setStaticDrawableColor(mColor);
+ protected void onIconAdded(int index, String slot, boolean blocked,
+ StatusBarIconHolder holder) {
+ StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
+ view.setStaticDrawableColor(mColor);
}
public void setTint(int color) {
mColor = color;
for (int i = 0; i < mGroup.getChildCount(); i++) {
View child = mGroup.getChildAt(i);
- if (child instanceof StatusBarIconView) {
- StatusBarIconView icon = (StatusBarIconView) child;
+ if (child instanceof StatusIconDisplayable) {
+ StatusIconDisplayable icon = (StatusIconDisplayable) child;
icon.setStaticDrawableColor(mColor);
}
}
@@ -171,6 +196,7 @@
// Enables SystemUI demo mode to take effect in this group
protected boolean mDemoable = true;
+ private boolean mIsInDemoMode;
protected DemoStatusIcons mDemoStatusIcons;
public IconManager(ViewGroup group) {
@@ -205,10 +231,27 @@
}
protected void onIconAdded(int index, String slot, boolean blocked,
- StatusBarIcon icon) {
- addIcon(index, slot, blocked, icon);
+ StatusBarIconHolder holder) {
+ addHolder(index, slot, blocked, holder);
}
+ protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
+ StatusBarIconHolder holder) {
+ switch (holder.getType()) {
+ case TYPE_ICON:
+ return addIcon(index, slot, blocked, holder.getIcon());
+
+ case TYPE_WIFI:
+ return addSignalIcon(index, slot, holder.getWifiState());
+
+ case TYPE_MOBILE:
+ return addMobileIcon(index, slot, holder.getMobileState());
+ }
+
+ return null;
+ }
+
+ @VisibleForTesting
protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
StatusBarIcon icon) {
StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
@@ -218,10 +261,45 @@
}
@VisibleForTesting
- protected StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
+ protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
+ StatusBarWifiView view = onCreateStatusBarWifiView(slot);
+ view.applyWifiState(state);
+ mGroup.addView(view, index, onCreateLayoutParams());
+
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.addDemoWifiView(state);
+ }
+ return view;
+ }
+
+ @VisibleForTesting
+ protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
+ StatusBarMobileView view = onCreateStatusBarMobileView(slot);
+ view.applyMobileState(state);
+ mGroup.addView(view, index, onCreateLayoutParams());
+
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.addMobileView(state);
+ }
+ return view;
+ }
+
+ private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
return new StatusBarIconView(mContext, slot, null, blocked);
}
+ private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
+ StatusBarWifiView view = StatusBarWifiView.fromContext(mContext);
+ view.setSlot(slot);
+ return view;
+ }
+
+ private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
+ StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
+ view.setSlot(slot);
+ return view;
+ }
+
protected LinearLayout.LayoutParams onCreateLayoutParams() {
return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
}
@@ -256,6 +334,9 @@
}
protected void onRemoveIcon(int viewIndex) {
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex));
+ }
mGroup.removeViewAt(viewIndex);
}
@@ -264,17 +345,59 @@
view.set(icon);
}
+ public void onSetIconHolder(int viewIndex, StatusBarIconHolder holder) {
+ switch (holder.getType()) {
+ case TYPE_ICON:
+ onSetIcon(viewIndex, holder.getIcon());
+ return;
+ case TYPE_WIFI:
+ onSetSignalIcon(viewIndex, holder.getWifiState());
+ return;
+
+ case TYPE_MOBILE:
+ onSetMobileIcon(viewIndex, holder.getMobileState());
+ default:
+ break;
+ }
+ }
+
+ public void onSetSignalIcon(int viewIndex, WifiIconState state) {
+ StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex);
+ if (wifiView != null) {
+ wifiView.applyWifiState(state);
+ }
+
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.updateWifiState(state);
+ }
+ }
+
+ public void onSetMobileIcon(int viewIndex, MobileIconState state) {
+ StatusBarMobileView view = (StatusBarMobileView) mGroup.getChildAt(viewIndex);
+ if (view != null) {
+ view.applyMobileState(state);
+ }
+
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.updateMobileState(state);
+ }
+ }
+
@Override
public void dispatchDemoCommand(String command, Bundle args) {
if (!mDemoable) {
return;
}
- if (mDemoStatusIcons != null && command.equals(COMMAND_EXIT)) {
- mDemoStatusIcons.dispatchDemoCommand(command, args);
- exitDemoMode();
+ if (command.equals(COMMAND_EXIT)) {
+ if (mDemoStatusIcons != null) {
+ mDemoStatusIcons.dispatchDemoCommand(command, args);
+ exitDemoMode();
+ }
+ mIsInDemoMode = false;
} else {
if (mDemoStatusIcons == null) {
+ mIsInDemoMode = true;
mDemoStatusIcons = createDemoStatusIcons();
}
mDemoStatusIcons.dispatchDemoCommand(command, args);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 8f5e705..510af03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -16,13 +16,14 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.Dependency;
@@ -30,7 +31,9 @@
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.IconLogger;
@@ -40,8 +43,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
-import static com.android.systemui.statusbar.phone.CollapsedStatusBarFragment.STATUS_BAR_ICON_MANAGER_TAG;
+import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
/**
* Receives the callbacks from CommandQueue related to icons and tracks the state of
@@ -50,20 +54,25 @@
*/
public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable,
ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController {
+
private static final String TAG = "StatusBarIconController";
private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
private final ArraySet<String> mIconBlacklist = new ArraySet<>();
private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
+ // Points to light or dark context depending on the... context?
private Context mContext;
- private DemoStatusIcons mDemoStatusIcons;
- private IconManager mStatusBarIconManager;
+ private Context mLightContext;
+ private Context mDarkContext;
+
+ private boolean mIsDark = false;
public StatusBarIconControllerImpl(Context context) {
super(context.getResources().getStringArray(
com.android.internal.R.array.config_statusBarIcons));
Dependency.get(ConfigurationController.class).addCallback(this);
+
mContext = context;
loadDimens();
@@ -76,12 +85,16 @@
@Override
public void addIconGroup(IconManager group) {
mIconGroups.add(group);
- for (int i = 0; i < mIcons.size(); i++) {
- StatusBarIcon icon = mIcons.get(i);
- if (icon != null) {
- String slot = mSlots.get(i);
- boolean blocked = mIconBlacklist.contains(slot);
- group.onIconAdded(getViewIndex(getSlotIndex(slot)), slot, blocked, icon);
+ List<Slot> allSlots = getSlots();
+ for (int i = 0; i < allSlots.size(); i++) {
+ Slot slot = allSlots.get(i);
+ List<StatusBarIconHolder> holders = slot.getHolderList();
+ boolean blocked = mIconBlacklist.contains(slot.getName());
+
+ for (StatusBarIconHolder holder : holders) {
+ int tag = holder.getTag();
+ int viewIndex = getViewIndex(getSlotIndex(slot.getName()), holder.getTag());
+ group.onIconAdded(viewIndex, slot.getName(), blocked, holder);
}
}
}
@@ -99,104 +112,209 @@
}
mIconBlacklist.clear();
mIconBlacklist.addAll(StatusBarIconController.getIconBlacklist(newValue));
- ArrayList<StatusBarIcon> current = new ArrayList<>(mIcons);
- ArrayList<String> currentSlots = new ArrayList<>(mSlots);
+ ArrayList<Slot> currentSlots = getSlots();
+ ArrayMap<Slot, List<StatusBarIconHolder>> slotsToReAdd = new ArrayMap<>();
+
+ // This is a little hacky... Peel off all of the holders on all of the slots
+ // but keep them around so they can be re-added
+
// Remove all the icons.
- for (int i = current.size() - 1; i >= 0; i--) {
- removeIcon(currentSlots.get(i));
+ for (int i = currentSlots.size() - 1; i >= 0; i--) {
+ Slot s = currentSlots.get(i);
+ slotsToReAdd.put(s, s.getHolderList());
+ removeAllIconsForSlot(s.getName());
}
+
// Add them all back
- for (int i = 0; i < current.size(); i++) {
- setIcon(currentSlots.get(i), current.get(i));
+ for (int i = 0; i < currentSlots.size(); i++) {
+ Slot item = currentSlots.get(i);
+ List<StatusBarIconHolder> iconsForSlot = slotsToReAdd.get(item);
+ if (iconsForSlot == null) continue;
+ for (StatusBarIconHolder holder : iconsForSlot) {
+ setIcon(getSlotIndex(item.getName()), holder);
+ }
}
}
private void loadDimens() {
}
- private void addSystemIcon(int index, StatusBarIcon icon) {
- String slot = getSlot(index);
- int viewIndex = getViewIndex(index);
+ private void addSystemIcon(int index, StatusBarIconHolder holder) {
+ String slot = getSlotName(index);
+ int viewIndex = getViewIndex(index, holder.getTag());
boolean blocked = mIconBlacklist.contains(slot);
- mIconLogger.onIconVisibility(getSlot(index), icon.visible);
- mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, icon));
+ mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
+ mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
}
@Override
public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
int index = getSlotIndex(slot);
- StatusBarIcon icon = getIcon(index);
- if (icon == null) {
- icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
- Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription);
- setIcon(slot, icon);
+ StatusBarIconHolder holder = getIcon(index, 0);
+ if (holder == null) {
+ StatusBarIcon icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+ Icon.createWithResource(
+ mContext, resourceId), 0, 0, contentDescription);
+ holder = StatusBarIconHolder.fromIcon(icon);
+ setIcon(index, holder);
} else {
- icon.icon = Icon.createWithResource(mContext, resourceId);
- icon.contentDescription = contentDescription;
- handleSet(index, icon);
+ holder.getIcon().icon = Icon.createWithResource(mContext, resourceId);
+ holder.getIcon().contentDescription = contentDescription;
+ handleSet(index, holder);
+ }
+ }
+
+ /**
+ * Signal icons need to be handled differently, because they can be
+ * composite views
+ */
+ @Override
+ public void setSignalIcon(String slot, WifiIconState state) {
+
+ int index = getSlotIndex(slot);
+
+ if (state == null) {
+ removeIcon(index, 0);
+ return;
+ }
+
+ StatusBarIconHolder holder = getIcon(index, 0);
+ if (holder == null) {
+ holder = StatusBarIconHolder.fromWifiIconState(state);
+ setIcon(index, holder);
+ } else {
+ holder.setWifiState(state);
+ handleSet(index, holder);
+ }
+ }
+
+ /**
+ * Accept a list of MobileIconStates, which all live in the same slot(?!), and then are sorted
+ * by subId. Don't worry this definitely makes sense and works.
+ * @param slot da slot
+ * @param iconStates All of the mobile icon states
+ */
+ @Override
+ public void setMobileIcons(String slot, List<MobileIconState> iconStates) {
+ Slot mobileSlot = getSlot(slot);
+ int slotIndex = getSlotIndex(slot);
+
+ for (MobileIconState state : iconStates) {
+ StatusBarIconHolder holder = mobileSlot.getHolderForTag(state.subId);
+ if (holder == null) {
+ holder = StatusBarIconHolder.fromMobileIconState(state);
+ setIcon(slotIndex, holder);
+ } else {
+ holder.setMobileState(state);
+ handleSet(slotIndex, holder);
+ }
}
}
@Override
public void setExternalIcon(String slot) {
- int viewIndex = getViewIndex(getSlotIndex(slot));
+ int viewIndex = getViewIndex(getSlotIndex(slot), 0);
int height = mContext.getResources().getDimensionPixelSize(
R.dimen.status_bar_icon_drawing_size);
mIconGroups.forEach(l -> l.onIconExternal(viewIndex, height));
}
+ //TODO: remove this (used in command queue and for 3rd party tiles?)
@Override
public void setIcon(String slot, StatusBarIcon icon) {
setIcon(getSlotIndex(slot), icon);
}
+ /**
+ * For backwards compatibility, in the event that someone gives us a slot and a status bar icon
+ */
+ private void setIcon(int index, StatusBarIcon icon) {
+ if (icon == null) {
+ removeAllIconsForSlot(getSlotName(index));
+ return;
+ }
+
+ StatusBarIconHolder holder = StatusBarIconHolder.fromIcon(icon);
+ setIcon(index, holder);
+ }
+
@Override
- public void removeIcon(String slot) {
- int index = getSlotIndex(slot);
- removeIcon(index);
+ public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
+ boolean isNew = getIcon(index, holder.getTag()) == null;
+ super.setIcon(index, holder);
+
+ if (isNew) {
+ addSystemIcon(index, holder);
+ } else {
+ handleSet(index, holder);
+ }
}
public void setIconVisibility(String slot, boolean visibility) {
int index = getSlotIndex(slot);
- StatusBarIcon icon = getIcon(index);
- if (icon == null || icon.visible == visibility) {
+ StatusBarIconHolder holder = getIcon(index, 0);
+ if (holder == null || holder.isVisible() == visibility) {
return;
}
- icon.visible = visibility;
- handleSet(index, icon);
+
+ holder.setVisible(visibility);
+ handleSet(index, holder);
+ }
+
+ public void removeIcon(String slot) {
+ removeAllIconsForSlot(slot);
}
@Override
- public void removeIcon(int index) {
- if (getIcon(index) == null) {
+ public void removeIcon(String slot, int tag) {
+ removeIcon(getSlotIndex(slot), tag);
+ }
+
+ @Override
+ public void removeAllIconsForSlot(String slotName) {
+ Slot slot = getSlot(slotName);
+ if (!slot.hasIconsInSlot()) {
return;
}
- mIconLogger.onIconHidden(getSlot(index));
- super.removeIcon(index);
- int viewIndex = getViewIndex(index);
+
+ mIconLogger.onIconHidden(slotName);
+
+ int slotIndex = getSlotIndex(slotName);
+ List<StatusBarIconHolder> iconsToRemove = slot.getHolderList();
+ for (StatusBarIconHolder holder : iconsToRemove) {
+ int viewIndex = getViewIndex(slotIndex, holder.getTag());
+ slot.removeForTag(holder.getTag());
+ mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
+ }
+ }
+
+ @Override
+ public void removeIcon(int index, int tag) {
+ if (getIcon(index, tag) == null) {
+ return;
+ }
+ mIconLogger.onIconHidden(getSlotName(index));
+ super.removeIcon(index, tag);
+ int viewIndex = getViewIndex(index, 0);
mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
}
- @Override
- public void setIcon(int index, StatusBarIcon icon) {
- if (icon == null) {
- removeIcon(index);
- return;
- }
- boolean isNew = getIcon(index) == null;
- super.setIcon(index, icon);
- if (isNew) {
- addSystemIcon(index, icon);
- } else {
- handleSet(index, icon);
- }
+ private void handleSet(int index, StatusBarIconHolder holder) {
+ int viewIndex = getViewIndex(index, holder.getTag());
+ mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
+ mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
}
- private void handleSet(int index, StatusBarIcon icon) {
- int viewIndex = getViewIndex(index);
- mIconLogger.onIconVisibility(getSlot(index), icon.visible);
- mIconGroups.forEach(l -> l.onSetIcon(viewIndex, icon));
+ /**
+ * For mobile essentially (an array of holders in one slot)
+ */
+ private void handleSet(int slotIndex, List<StatusBarIconHolder> holders) {
+ for (StatusBarIconHolder holder : holders) {
+ int viewIndex = getViewIndex(slotIndex, holder.getTag());
+ mIconLogger.onIconVisibility(getSlotName(slotIndex), holder.isVisible());
+ mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
+ }
}
@Override
@@ -208,7 +326,7 @@
int N = group.getChildCount();
pw.println(" icon views: " + N);
for (int i = 0; i < N; i++) {
- StatusBarIconView ic = (StatusBarIconView) group.getChildAt(i);
+ StatusIconDisplayable ic = (StatusIconDisplayable) group.getChildAt(i);
pw.println(" [" + i + "] icon=" + ic);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
new file mode 100644
index 0000000..e854dd0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 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.statusbar.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+
+/**
+ * Wraps {@link com.android.internal.statusbar.StatusBarIcon} so we can still have a uniform list
+ */
+public class StatusBarIconHolder {
+ public static final int TYPE_ICON = 0;
+ public static final int TYPE_WIFI = 1;
+ public static final int TYPE_MOBILE = 2;
+
+ private StatusBarIcon mIcon;
+ private WifiIconState mWifiState;
+ private MobileIconState mMobileState;
+ private int mType = TYPE_ICON;
+ private int mTag = 0;
+ private boolean mVisible = true;
+
+ public static StatusBarIconHolder fromIcon(StatusBarIcon icon) {
+ StatusBarIconHolder wrapper = new StatusBarIconHolder();
+ wrapper.mIcon = icon;
+
+ return wrapper;
+ }
+
+ public static StatusBarIconHolder fromResId(Context context, int resId,
+ CharSequence contentDescription) {
+ StatusBarIconHolder holder = new StatusBarIconHolder();
+ holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),
+ Icon.createWithResource( context, resId), 0, 0, contentDescription);
+ return holder;
+ }
+
+ public static StatusBarIconHolder fromWifiIconState(WifiIconState state) {
+ StatusBarIconHolder holder = new StatusBarIconHolder();
+ holder.mWifiState = state;
+ holder.mType = TYPE_WIFI;
+ return holder;
+ }
+
+ public static StatusBarIconHolder fromMobileIconState(MobileIconState state) {
+ StatusBarIconHolder holder = new StatusBarIconHolder();
+ holder.mMobileState = state;
+ holder.mType = TYPE_MOBILE;
+ holder.mTag = state.subId;
+ return holder;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ @Nullable
+ public StatusBarIcon getIcon() {
+ return mIcon;
+ }
+
+ @Nullable
+ public WifiIconState getWifiState() {
+ return mWifiState;
+ }
+
+ public void setWifiState(WifiIconState state) {
+ mWifiState = state;
+ }
+
+ @Nullable
+ public MobileIconState getMobileState() {
+ return mMobileState;
+ }
+
+ public void setMobileState(MobileIconState state) {
+ mMobileState = state;
+ }
+
+ public boolean isVisible() {
+ switch (mType) {
+ case TYPE_ICON:
+ return mIcon.visible;
+ case TYPE_WIFI:
+ return mWifiState.visible;
+ case TYPE_MOBILE:
+ return mMobileState.visible;
+
+ default: return true;
+ }
+ }
+
+ public void setVisible(boolean visible) {
+ switch (mType) {
+ case TYPE_ICON:
+ mIcon.visible = visible;
+ break;
+
+ case TYPE_WIFI:
+ mWifiState.visible = visible;
+ break;
+
+ case TYPE_MOBILE:
+ mMobileState.visible = visible;
+ break;
+ }
+ }
+
+ public int getTag() {
+ return mTag;
+ }
+}
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 1aa3a43..c773170 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -16,64 +16,78 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
-
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
public class StatusBarIconList {
- protected ArrayList<String> mSlots = new ArrayList<>();
- protected ArrayList<StatusBarIcon> mIcons = new ArrayList<>();
+ private ArrayList<Slot> mSlots = new ArrayList<>();
public StatusBarIconList(String[] slots) {
final int N = slots.length;
for (int i=0; i < N; i++) {
- mSlots.add(slots[i]);
- mIcons.add(null);
+ mSlots.add(new Slot(slots[i], null));
}
}
public int getSlotIndex(String slot) {
final int N = mSlots.size();
for (int i=0; i<N; i++) {
- if (slot.equals(mSlots.get(i))) {
+ Slot item = mSlots.get(i);
+ if (item.getName().equals(slot)) {
return i;
}
}
// Auto insert new items at the beginning.
- mSlots.add(0, slot);
- mIcons.add(0, null);
+ mSlots.add(0, new Slot(slot, null));
return 0;
}
+ protected ArrayList<Slot> getSlots() {
+ return new ArrayList<>(mSlots);
+ }
+
+ protected Slot getSlot(String name) {
+ return mSlots.get(getSlotIndex(name));
+ }
+
public int size() {
return mSlots.size();
}
- public void setIcon(int index, StatusBarIcon icon) {
- mIcons.set(index, icon);
+ public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
+ mSlots.get(index).addHolder(holder);
}
- public void removeIcon(int index) {
- mIcons.set(index, null);
+ public void removeIcon(int index, int tag) {
+ mSlots.get(index).removeForTag(tag);
}
- public String getSlot(int index) {
- return mSlots.get(index);
+ public String getSlotName(int index) {
+ return mSlots.get(index).getName();
}
- public StatusBarIcon getIcon(int index) {
- return mIcons.get(index);
+ public StatusBarIconHolder getIcon(int index, int tag) {
+ return mSlots.get(index).getHolderForTag(tag);
}
- public int getViewIndex(int index) {
+ public int getViewIndex(int slotIndex, int tag) {
int count = 0;
- for (int i = 0; i < index; i++) {
- if (mIcons.get(i) != null) {
- count++;
+ for (int i = 0; i < slotIndex; i++) {
+ Slot item = mSlots.get(i);
+ if (item.hasIconsInSlot()) {
+ count += item.numberOfIcons();
}
}
- return count;
+
+ Slot viewItem = mSlots.get(slotIndex);
+ return count + viewItem.viewIndexOffsetForTag(tag);
}
public void dump(PrintWriter pw) {
@@ -81,7 +95,163 @@
final int N = mSlots.size();
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\n", i, mSlots.get(i).toString());
+ }
+ }
+
+ public static class Slot {
+ private final String mName;
+ private StatusBarIconHolder mHolder;
+ /**
+ * Only used if multiple icons are added to the same slot.
+ *
+ * If there are mSubSlots, then these are structured like:
+ * [ First item | (the rest) ]
+ *
+ * The tricky thing to keep in mind here is that the list [mHolder, mSubSlots] is ordered
+ * ascending, but for view logic we should go backwards through the list. I.e., the first
+ * element (mHolder) should be the highest index, because higher priority items go to the
+ * right of lower priority items
+ */
+ private ArrayList<StatusBarIconHolder> mSubSlots;
+
+ public Slot(String name, StatusBarIconHolder iconHolder) {
+ mName = name;
+ mHolder = iconHolder;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ @Nullable
+ public StatusBarIconHolder getHolderForTag(int tag) {
+ if (tag == TAG_PRIMARY) {
+ return mHolder;
+ }
+
+ if (mSubSlots != null) {
+ for (StatusBarIconHolder holder : mSubSlots) {
+ if (holder.getTag() == tag) {
+ return holder;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public void addHolder(StatusBarIconHolder holder) {
+ int tag = holder.getTag();
+ if (tag == TAG_PRIMARY) {
+ mHolder = holder;
+ } else {
+ setSubSlot(holder, tag);
+ }
+ }
+
+ public void removeForTag(int tag) {
+ if (tag == TAG_PRIMARY) {
+ mHolder = null;
+ } else {
+ int index = getIndexForTag(tag);
+ if (index != -1) {
+ mSubSlots.remove(index);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public void clear() {
+ mHolder = null;
+ if (mSubSlots != null) {
+ mSubSlots = null;
+ }
+ }
+
+ private void setSubSlot(StatusBarIconHolder holder, int tag) {
+ if (mSubSlots == null) {
+ mSubSlots = new ArrayList<>();
+ mSubSlots.add(holder);
+ return;
+ }
+
+ if (getIndexForTag(tag) != -1) {
+ // Holder exists for tag; no-op
+ return;
+ }
+
+ // These holders get added to the end. Confused yet?
+ mSubSlots.add(holder);
+ }
+
+ private int getIndexForTag(int tag) {
+ for (int i = 0; i < mSubSlots.size(); i++) {
+ StatusBarIconHolder h = mSubSlots.get(i);
+ if (h.getTag() == tag) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public boolean hasIconsInSlot() {
+ if (mHolder != null) return true;
+ if (mSubSlots == null) return false;
+
+ return mSubSlots.size() > 0;
+ }
+
+ public int numberOfIcons() {
+ int num = mHolder == null ? 0 : 1;
+ if (mSubSlots == null) return num;
+
+ return num + mSubSlots.size();
+ }
+
+ /**
+ * View index is backwards from regular index
+ * @param tag the tag of the holder being viewed
+ * @return (1 + mSubSlots.size() - indexOfTag)
+ */
+ public int viewIndexOffsetForTag(int tag) {
+ if (mSubSlots == null) {
+ return 0;
+ }
+
+ int subSlots = mSubSlots.size();
+ if (tag == TAG_PRIMARY) {
+ return subSlots;
+ }
+
+ return subSlots - getIndexForTag(tag) - 1;
+ }
+
+ public List<StatusBarIconHolder> getHolderList() {
+ ArrayList<StatusBarIconHolder> holders = new ArrayList<>();
+ if (mHolder != null) {
+ holders.add(mHolder);
+ }
+
+ if (mSubSlots != null) {
+ holders.addAll(mSubSlots);
+ }
+
+ return holders;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(%s) %s", mName, subSlotsString());
+ }
+
+ private String subSlotsString() {
+ if (mSubSlots == null) {
+ return "";
+ }
+
+ return "" + mSubSlots.size() + " subSlots";
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
new file mode 100644
index 0000000..c5a3a0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.telephony.SubscriptionInfo;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.ImageView;
+import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.tuner.TunerService.Tunable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,
+ SecurityController.SecurityControllerCallback, Tunable {
+ private static final String TAG = "StatusBarSignalPolicy";
+
+ private final String mSlotAirplane;
+ private final String mSlotMobile;
+ private final String mSlotWifi;
+ private final String mSlotEthernet;
+ private final String mSlotVpn;
+
+ private final Context mContext;
+ private final StatusBarIconController mIconController;
+ private final NetworkController mNetworkController;
+ private final SecurityController mSecurityController;
+ private final Handler mHandler = Handler.getMain();
+
+ private boolean mBlockAirplane;
+ private boolean mBlockMobile;
+ private boolean mBlockWifi;
+ private boolean mBlockEthernet;
+ private boolean mActivityEnabled;
+ private boolean mForceBlockWifi;
+
+ // Track as little state as possible, and only for padding purposes
+ private boolean mIsAirplaneMode = false;
+ private boolean mWifiVisible = false;
+
+ private ArrayList<MobileIconState> mMobileStates = new ArrayList<MobileIconState>();
+ private WifiIconState mWifiIconState = new WifiIconState();
+
+ public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
+ mContext = context;
+
+ mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
+ mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
+ mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi);
+ mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);
+ mSlotVpn = mContext.getString(com.android.internal.R.string.status_bar_vpn);
+
+ mIconController = iconController;
+ mNetworkController = Dependency.get(NetworkController.class);
+ mSecurityController = Dependency.get(SecurityController.class);
+
+ mNetworkController.addCallback(this);
+ mSecurityController.addCallback(this);
+ }
+
+ public void destroy() {
+ mNetworkController.removeCallback(this);
+ mSecurityController.removeCallback(this);
+ }
+
+ private void updateVpn() {
+ boolean vpnVisible = mSecurityController.isVpnEnabled();
+ int vpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
+
+ mIconController.setIcon(mSlotVpn, vpnIconId, null);
+ mIconController.setIconVisibility(mSlotVpn, vpnVisible);
+ }
+
+ private int currentVpnIconId(boolean isBranded) {
+ return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic;
+ }
+
+ private void updateActivityEnabled() {
+ mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
+ }
+
+ /**
+ * From SecurityController
+ */
+ @Override
+ public void onStateChanged() {
+ mHandler.post(this::updateVpn);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ return;
+ }
+ ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue);
+ boolean blockAirplane = blockList.contains(mSlotAirplane);
+ boolean blockMobile = blockList.contains(mSlotMobile);
+ boolean blockWifi = blockList.contains(mSlotWifi);
+ boolean blockEthernet = blockList.contains(mSlotEthernet);
+
+ if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile
+ || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) {
+ mBlockAirplane = blockAirplane;
+ mBlockMobile = blockMobile;
+ mBlockEthernet = blockEthernet;
+ mBlockWifi = blockWifi || mForceBlockWifi;
+ // Re-register to get new callbacks.
+ mNetworkController.removeCallback(this);
+ }
+ }
+
+ @Override
+ public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description, boolean isTransient,
+ String statusLabel) {
+
+ boolean visible = statusIcon.visible && !mBlockWifi;
+ boolean in = activityIn && mActivityEnabled && visible;
+ boolean out = activityOut && mActivityEnabled && visible;
+
+ mWifiIconState.visible = visible;
+ mWifiIconState.resId = statusIcon.icon;
+ mWifiIconState.activityIn = in;
+ mWifiIconState.activityOut = out;
+ mWifiIconState.slot = mSlotWifi;
+ mWifiIconState.airplaneSpacerVisible = mIsAirplaneMode;
+ mWifiIconState.contentDescription = statusIcon.contentDescription;
+
+ if (mWifiIconState.visible && mWifiIconState.resId > 0) {
+ mIconController.setSignalIcon(mSlotWifi, mWifiIconState.copy());
+ mIconController.setIconVisibility(mSlotWifi, true);
+ } else {
+ mIconController.setIconVisibility(mSlotWifi, false);
+ }
+ }
+
+ @Override
+ public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
+ int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
+ String description, boolean isWide, int subId, boolean roaming) {
+ MobileIconState state = getState(subId);
+ if (state == null) {
+ return;
+ }
+
+ state.visible = statusIcon.visible && !mBlockMobile;
+ state.strengthId = statusIcon.icon;
+ state.typeId = statusType;
+ state.contentDescription = statusIcon.contentDescription;
+ state.typeContentDescription = typeContentDescription;
+ state.roaming = roaming;
+ state.activityIn = activityIn && mActivityEnabled;
+ state.activityOut = activityOut && mActivityEnabled;
+
+ // Always send a copy to maintain value type semantics
+ mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
+ }
+
+ private MobileIconState getState(int subId) {
+ for (MobileIconState state : mMobileStates) {
+ if (state.subId == subId) {
+ return state;
+ }
+ }
+ Log.e(TAG, "Unexpected subscription " + subId);
+ return null;
+ }
+
+
+ /**
+ * It is expected that a call to setSubs will be immediately followed by setMobileDataIndicators
+ * so we don't have to update the icon manager at this point, just remove the old ones
+ * @param subs list of mobile subscriptions, displayed as mobile data indicators (max 8)
+ */
+ @Override
+ public void setSubs(List<SubscriptionInfo> subs) {
+ if (hasCorrectSubs(subs)) {
+ return;
+ }
+
+ mIconController.removeAllIconsForSlot(mSlotMobile);
+ mMobileStates.clear();
+ final int n = subs.size();
+ for (int i = 0; i < n; i++) {
+ mMobileStates.add(new MobileIconState(subs.get(i).getSubscriptionId()));
+ }
+ }
+
+ private boolean hasCorrectSubs(List<SubscriptionInfo> subs) {
+ final int N = subs.size();
+ if (N != mMobileStates.size()) {
+ return false;
+ }
+ for (int i = 0; i < N; i++) {
+ if (mMobileStates.get(i).subId != subs.get(i).getSubscriptionId()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void setNoSims(boolean show, boolean simDetected) {
+ // Noop yay!
+ }
+
+
+ @Override
+ public void setEthernetIndicators(IconState state) {
+ boolean visible = state.visible && !mBlockEthernet;
+ int resId = state.icon;
+ String description = state.contentDescription;
+
+ if (resId > 0) {
+ mIconController.setIcon(mSlotEthernet, resId, description);
+ mIconController.setIconVisibility(mSlotEthernet, true);
+ } else {
+ mIconController.setIconVisibility(mSlotEthernet, false);
+ }
+ }
+
+ @Override
+ public void setIsAirplaneMode(IconState icon) {
+ mIsAirplaneMode = icon.visible && !mBlockAirplane;
+ int resId = icon.icon;
+ String description = icon.contentDescription;
+
+ if (mIsAirplaneMode && resId > 0) {
+ mIconController.setIcon(mSlotAirplane, resId, description);
+ mIconController.setIconVisibility(mSlotAirplane, true);
+ } else {
+ mIconController.setIconVisibility(mSlotAirplane, false);
+ }
+ }
+
+ @Override
+ public void setMobileDataEnabled(boolean enabled) {
+ // Don't care.
+ }
+
+ private static abstract class SignalIconState {
+ public boolean visible;
+ public boolean activityOut;
+ public boolean activityIn;
+ public String slot;
+ public String contentDescription;
+
+ @Override
+ public boolean equals(Object o) {
+ // Skipping reference equality bc this should be more of a value type
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SignalIconState that = (SignalIconState) o;
+ return visible == that.visible &&
+ activityOut == that.activityOut &&
+ activityIn == that.activityIn &&
+ Objects.equals(contentDescription, that.contentDescription) &&
+ Objects.equals(slot, that.slot);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(visible, activityOut, slot);
+ }
+
+ protected void copyTo(SignalIconState other) {
+ other.visible = visible;
+ other.activityIn = activityIn;
+ other.activityOut = activityOut;
+ other.slot = slot;
+ other.contentDescription = contentDescription;
+ }
+ }
+
+ public static class WifiIconState extends SignalIconState{
+ public int resId;
+ public boolean airplaneSpacerVisible;
+ public boolean signalSpacerVisible;
+
+ @Override
+ public boolean equals(Object o) {
+ // Skipping reference equality bc this should be more of a value type
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ WifiIconState that = (WifiIconState) o;
+ return resId == that.resId &&
+ airplaneSpacerVisible == that.airplaneSpacerVisible &&
+ signalSpacerVisible == that.signalSpacerVisible;
+ }
+
+ public void copyTo(WifiIconState other) {
+ super.copyTo(other);
+ other.resId = resId;
+ other.airplaneSpacerVisible = airplaneSpacerVisible;
+ other.signalSpacerVisible = signalSpacerVisible;
+ }
+
+ public WifiIconState copy() {
+ WifiIconState newState = new WifiIconState();
+ copyTo(newState);
+ return newState;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(),
+ resId, airplaneSpacerVisible, signalSpacerVisible);
+ }
+
+ @Override public String toString() {
+ return "WifiIconState(resId=" + resId + ", visible=" + visible + ")";
+ }
+ }
+
+ /**
+ * A little different. This one delegates to SignalDrawable instead of a specific resId
+ */
+ public static class MobileIconState extends SignalIconState {
+ public int subId;
+ public int strengthId;
+ public int typeId;
+ public boolean roaming;
+ public boolean needsLeadingPadding;
+ public String typeContentDescription;
+
+ private MobileIconState(int subId) {
+ super();
+ this.subId = subId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ MobileIconState that = (MobileIconState) o;
+ return subId == that.subId &&
+ strengthId == that.strengthId &&
+ typeId == that.typeId &&
+ roaming == that.roaming &&
+ needsLeadingPadding == that.needsLeadingPadding &&
+ Objects.equals(typeContentDescription, that.typeContentDescription);
+ }
+
+ @Override
+ public int hashCode() {
+
+ return Objects
+ .hash(super.hashCode(), subId, strengthId, typeId, roaming, needsLeadingPadding,
+ typeContentDescription);
+ }
+
+ public void copyTo(MobileIconState other) {
+ super.copyTo(other);
+ other.subId = subId;
+ other.strengthId = strengthId;
+ other.typeId = typeId;
+ other.roaming = roaming;
+ other.needsLeadingPadding = needsLeadingPadding;
+ other.typeContentDescription = typeContentDescription;
+ }
+
+ private static List<MobileIconState> copyStates(List<MobileIconState> inStates) {
+ ArrayList<MobileIconState> outStates = new ArrayList<>();
+ for (MobileIconState state : inStates) {
+ MobileIconState copy = new MobileIconState(state.subId);
+ state.copyTo(copy);
+ outStates.add(copy);
+ }
+
+ return outStates;
+ }
+
+ @Override public String toString() {
+ return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
+ + roaming + ", visible=" + visible + ")";
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index dab28d6..255e10e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -18,13 +18,13 @@
import android.annotation.Nullable;
import android.content.Context;
-import android.util.ArrayMap;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.stack.ViewState;
/**
@@ -97,7 +97,7 @@
* Layout is happening from end -> start
*/
private void calculateIconTranslations() {
- float width = getWidth();
+ float width = getWidth() - getPaddingEnd();
float translationX = width;
float contentStart = getPaddingStart();
int childCount = getChildCount();
@@ -109,18 +109,22 @@
//TODO: Dots
for (int i = childCount - 1; i >= 0; i--) {
View child = getChildAt(i);
- if (!(child instanceof StatusBarIconView)) {
+ if (!(child instanceof StatusIconDisplayable)) {
+ if (DEBUG) Log.d(TAG, "skipping child (wrong type)");
continue;
}
+ StatusIconDisplayable iconView = (StatusIconDisplayable) child;
+
ViewState childState = getViewStateFromChild(child);
if (childState == null ) {
+ if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") no ViewState");
continue;
}
- // Rely on StatusBarIcon for truth about visibility
- if (!((StatusBarIconView) child).getStatusBarIcon().visible) {
+ if (!iconView.isIconVisible() || iconView.isIconBlocked()) {
childState.hidden = true;
+ if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") not visible");
continue;
}
@@ -175,8 +179,8 @@
vs.initFrom(child);
vs.alpha = 1.0f;
- if (child instanceof StatusBarIconView) {
- vs.hidden = !((StatusBarIconView)child).getStatusBarIcon().visible;
+ if (child instanceof StatusIconDisplayable) {
+ vs.hidden = !((StatusIconDisplayable)child).isIconVisible();
} else {
vs.hidden = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
index 58944c6..945ed76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
@@ -35,7 +35,7 @@
// Used to reapply darkness on an object, must have previously been added through
// addDarkReceiver.
- void applyDark(ImageView object);
+ void applyDark(DarkReceiver object);
int DEFAULT_ICON_TINT = Color.WHITE;
Rect sTmpRect = new Rect();
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 4533aa5..4c100cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -54,6 +54,7 @@
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.statusbar.policy.MobileSignalController.MobileState;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -848,6 +849,11 @@
subs.add(addSignalController(i, i));
}
mCallbackHandler.setSubs(subs);
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ int key = mMobileSignalControllers.keyAt(i);
+ MobileSignalController controller = mMobileSignalControllers.get(key);
+ controller.notifyListeners();
+ }
}
}
String nosim = args.getString("nosim");
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 1cbdfe8..7a9cdfd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -39,8 +39,7 @@
public static String BATTERY = "BAT";
public static String HINTS = "HNT";
- @VisibleForTesting
- static void createAll(Context context) {
+ public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
final NotificationChannel batteryChannel = new NotificationChannel(BATTERY,
context.getString(R.string.notification_channel_battery),
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index acdd0c7..6f71e55 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -603,7 +603,8 @@
if (row.defaultStream) {
return activeRow.stream == STREAM_RING
|| activeRow.stream == STREAM_ALARM
- || activeRow.stream == STREAM_VOICE_CALL;
+ || activeRow.stream == STREAM_VOICE_CALL
+ || activeRow.stream == STREAM_ACCESSIBILITY;
}
return false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 4b455ba..149f2de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -58,6 +58,7 @@
public static final int BELOW_WARNING_BUCKET = -1;
public static final long BELOW_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(2);
public static final long ABOVE_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(4);
+ private static final long ABOVE_CHARGE_CYCLE_THRESHOLD = Duration.ofHours(8).toMillis();
private HardwarePropertiesManager mHardProps;
private WarningsUI mMockWarnings;
private PowerUI mPowerUI;
@@ -198,6 +199,7 @@
when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+ mPowerUI.mBatteryLevel = 10;
mPowerUI.start();
// unplugged device that would show the non-hybrid notification and the hybrid
@@ -213,6 +215,7 @@
when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+ mPowerUI.mBatteryLevel = 10;
mPowerUI.start();
// unplugged device that would show the non-hybrid but not the hybrid
@@ -254,13 +257,14 @@
}
@Test
- public void testShouldShowLowBatteryWarning_deviceBatteryStatusUnkown_returnsNoShow() {
+ public void testShouldShowLowBatteryWarning_deviceBatteryStatusUnknown_returnsNoShow() {
when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
mPowerUI.start();
- // Unknown battery status device that would show the neither due
+ // Unknown battery status device that would show the neither due to the battery status being
+ // unknown
boolean shouldShow =
mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
@@ -295,6 +299,9 @@
mPowerUI.maybeShowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
ABOVE_WARNING_BUCKET);
+
+ // reduce battery level to handle time based trigger -> level trigger interactions
+ mPowerUI.mBatteryLevel = 10;
boolean shouldShow =
mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 23a3405..ab042d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -29,6 +31,7 @@
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
+import android.app.NotificationChannel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
@@ -50,6 +53,7 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.List;
import java.util.function.Consumer;
@SmallTest
@@ -274,4 +278,24 @@
mGroupRow.setBlockingHelperShowing(false);
assertFalse(mGroupRow.isBlockingHelperShowing());
}
+
+ @Test
+ public void testGetNumUniqueChildren_defaultChannel() {
+ assertEquals(1, mGroupRow.getNumUniqueChannels());
+ }
+
+ @Test
+ public void testGetNumUniqueChildren_multiChannel() {
+ List<ExpandableNotificationRow> childRows =
+ mGroupRow.getChildrenContainer().getNotificationChildren();
+ // Give each child a unique channel id/name.
+ int i = 0;
+ for (ExpandableNotificationRow childRow : childRows) {
+ childRow.getEntry().channel =
+ new NotificationChannel("id" + i, "dinnertime" + i, IMPORTANCE_DEFAULT);
+ i++;
+ }
+
+ assertEquals(3, mGroupRow.getNumUniqueChannels());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
index 64f34e0..78cceeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
@@ -87,7 +87,7 @@
@Test
public void testDismissCurrentBlockingHelper_withDetachedBlockingHelperRow() throws Exception {
- ExpandableNotificationRow row = spy(mHelper.createRow());
+ ExpandableNotificationRow row = spy(createBlockableRowSpy());
row.setBlockingHelperShowing(true);
when(row.isAttachedToWindow()).thenReturn(false);
mBlockingHelperManager.setBlockingHelperRowForTest(row);
@@ -100,7 +100,7 @@
@Test
public void testDismissCurrentBlockingHelper_withAttachedBlockingHelperRow() throws Exception {
- ExpandableNotificationRow row = spy(mHelper.createRow());
+ ExpandableNotificationRow row = spy(createBlockableRowSpy());
row.setBlockingHelperShowing(true);
when(row.isAttachedToWindow()).thenReturn(true);
mBlockingHelperManager.setBlockingHelperRowForTest(row);
@@ -113,7 +113,7 @@
@Test
public void testPerhapsShowBlockingHelper_shown() throws Exception {
- ExpandableNotificationRow row = mHelper.createRow();
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
mBlockingHelperManager.setNotificationShadeExpanded(1f);
@@ -125,7 +125,7 @@
@Test
public void testPerhapsShowBlockingHelper_shownForLargeGroup() throws Exception {
- ExpandableNotificationRow groupRow = mHelper.createGroup(10);
+ ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10);
groupRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
mBlockingHelperManager.setNotificationShadeExpanded(1f);
@@ -137,7 +137,7 @@
@Test
public void testPerhapsShowBlockingHelper_shownForOnlyChildNotification()
throws Exception {
- ExpandableNotificationRow groupRow = mHelper.createGroup(1);
+ ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(1);
// Explicitly get the children container & call getViewAtPosition on it instead of the row
// as other factors such as view expansion may cause us to get the parent row back instead
// of the child row.
@@ -152,7 +152,7 @@
@Test
public void testPerhapsShowBlockingHelper_notShownDueToNeutralUserSentiment() throws Exception {
- ExpandableNotificationRow row = mHelper.createRow();
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.getEntry().userSentiment = USER_SENTIMENT_NEUTRAL;
mBlockingHelperManager.setNotificationShadeExpanded(1f);
@@ -162,7 +162,7 @@
@Test
public void testPerhapsShowBlockingHelper_notShownDueToPositiveUserSentiment()
throws Exception {
- ExpandableNotificationRow row = mHelper.createRow();
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.getEntry().userSentiment = USER_SENTIMENT_POSITIVE;
mBlockingHelperManager.setNotificationShadeExpanded(1f);
@@ -171,7 +171,7 @@
@Test
public void testPerhapsShowBlockingHelper_notShownDueToShadeVisibility() throws Exception {
- ExpandableNotificationRow row = mHelper.createRow();
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
// Hide the shade
mBlockingHelperManager.setNotificationShadeExpanded(0f);
@@ -180,9 +180,19 @@
}
@Test
+ public void testPerhapsShowBlockingHelper_notShownDueToNonblockability() throws Exception {
+ ExpandableNotificationRow row = createBlockableRowSpy();
+ when(row.getIsNonblockable()).thenReturn(true);
+ row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
+ mBlockingHelperManager.setNotificationShadeExpanded(1f);
+
+ assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
+ }
+
+ @Test
public void testPerhapsShowBlockingHelper_notShownAsNotificationIsInMultipleChildGroup()
throws Exception {
- ExpandableNotificationRow groupRow = mHelper.createGroup(2);
+ ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(2);
// Explicitly get the children container & call getViewAtPosition on it instead of the row
// as other factors such as view expansion may cause us to get the parent row back instead
// of the child row.
@@ -195,7 +205,7 @@
@Test
public void testBlockingHelperShowAndDismiss() throws Exception{
- ExpandableNotificationRow row = spy(mHelper.createRow());
+ ExpandableNotificationRow row = spy(createBlockableRowSpy());
row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
when(row.isAttachedToWindow()).thenReturn(true);
mBlockingHelperManager.setNotificationShadeExpanded(1f);
@@ -211,4 +221,18 @@
verify(mEntryManager).updateNotifications();
}
+
+ private ExpandableNotificationRow createBlockableRowSpy() throws Exception {
+ ExpandableNotificationRow row = spy(mHelper.createRow());
+ when(row.getIsNonblockable()).thenReturn(false);
+ return row;
+ }
+
+ private ExpandableNotificationRow createBlockableGroupRowSpy(int numChildren) throws Exception {
+ ExpandableNotificationRow row = spy(mHelper.createGroup(numChildren));
+ when(row.getIsNonblockable()).thenReturn(false);
+ return row;
+ }
+
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java
index 21f6750..0ef2d051 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java
@@ -268,9 +268,10 @@
@Test
public void testInitializeNotificationInfoView_showBlockingHelper() throws Exception {
NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = mHelper.createRow();
+ ExpandableNotificationRow row = spy(mHelper.createRow());
row.setBlockingHelperShowing(true);
row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
+ when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -285,7 +286,7 @@
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
- any(),
+ eq(false),
eq(true) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */);
}
@@ -293,9 +294,10 @@
@Test
public void testInitializeNotificationInfoView_dontShowBlockingHelper() throws Exception {
NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = mHelper.createRow();
+ ExpandableNotificationRow row = spy(mHelper.createRow());
row.setBlockingHelperShowing(false);
row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
+ when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -310,7 +312,7 @@
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
- any(),
+ eq(false),
eq(false) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index c2cb5b9..d86e947 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -76,7 +76,6 @@
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -87,6 +86,7 @@
private static final String TEST_PACKAGE_NAME = "test_package";
private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME;
private static final int TEST_UID = 1;
+ private static final int MULTIPLE_CHANNEL_COUNT = 2;
private static final String TEST_CHANNEL = "test_channel";
private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
@@ -157,7 +157,7 @@
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -169,7 +169,7 @@
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
.thenReturn(iconDrawable);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
assertEquals(iconDrawable, iconView.getDrawable());
}
@@ -177,7 +177,7 @@
@Test
public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
@@ -193,7 +193,7 @@
eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
.thenReturn(notificationChannelGroup);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
@@ -204,7 +204,7 @@
@Test
public void testBindNotification_SetsTextChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@@ -212,7 +212,7 @@
@Test
public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, false);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, textView.getVisibility());
}
@@ -224,7 +224,7 @@
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, false);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@@ -232,8 +232,7 @@
@Test
public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@@ -241,7 +240,7 @@
@Test
public void testBindNotification_BlockButton() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final View block = mNotificationInfo.findViewById(R.id.block);
final View minimize = mNotificationInfo.findViewById(R.id.minimize);
assertEquals(VISIBLE, block.getVisibility());
@@ -252,7 +251,7 @@
public void testBindNotification_MinButton() throws Exception {
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final View block = mNotificationInfo.findViewById(R.id.block);
final View minimize = mNotificationInfo.findViewById(R.id.minimize);
assertEquals(GONE, block.getVisibility());
@@ -267,7 +266,7 @@
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
- }, null, null);
+ }, null, false);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -278,7 +277,7 @@
@Test
public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -286,11 +285,11 @@
@Test
public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
- }, null, null);
+ }, null, false);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertEquals(View.VISIBLE, settingsButton.getVisibility());
}
@@ -299,11 +298,11 @@
public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null,
+ TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(null, c);
latch.countDown();
- }, null, null);
+ }, null, true);
mNotificationInfo.findViewById(R.id.info).performClick();
// Verify that listener was triggered.
@@ -315,7 +314,8 @@
public void testBindNotification_ChannelNameInvisibleWhenBundleFromDifferentChannels()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
+ null, true);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, channelNameView.getVisibility());
@@ -325,7 +325,8 @@
@UiThreadTest
public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
+ null, true);
final TextView blockView = mNotificationInfo.findViewById(R.id.block);
assertEquals(GONE, blockView.getVisibility());
}
@@ -333,8 +334,8 @@
@Test
public void testbindNotification_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
- null, null, false, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false,
+ true);
final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
@@ -343,8 +344,7 @@
@Test
public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
- null, Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_desc),
@@ -354,7 +354,7 @@
@Test
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@@ -363,7 +363,7 @@
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.findViewById(R.id.block).performClick();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -375,7 +375,7 @@
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -387,7 +387,7 @@
throws Exception {
int originalImportance = mNotificationChannel.getImportance();
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
@@ -400,7 +400,7 @@
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
@@ -420,7 +420,7 @@
null /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
- null /* nonBlockablePkgs */,
+ false /* isNonblockable */,
true /* isForBlockingHelper */,
false /* isUserSentimentNegative */);
@@ -433,8 +433,7 @@
public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
- null, Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -445,7 +444,7 @@
public void testBlockChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -464,8 +463,7 @@
public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
- null, Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -477,7 +475,7 @@
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -496,7 +494,7 @@
public void testKeepUpdatesNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.handleCloseControls(true, false);
@@ -512,7 +510,7 @@
public void testBlockUndoDoesNotBlockNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -532,7 +530,7 @@
public void testMinUndoDoesNotMinNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -552,8 +550,7 @@
public void testCloseControlsDoesNotUpdateiMinIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -566,8 +563,7 @@
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -582,7 +578,7 @@
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
- }, null, null, Collections.singleton(TEST_PACKAGE_NAME));
+ }, null, null, true);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -598,7 +594,7 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
- }, null, null, null);
+ }, null, null, false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -628,7 +624,7 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null,
(View v, Intent intent) -> {
latch.countDown();
- }, null);
+ }, false);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
settingsLink.performClick();
@@ -653,10 +649,10 @@
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 2, sbn, null, null,
+ TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null,
(View v, Intent intent) -> {
latch.countDown();
- }, null);
+ }, false);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
settingsLink.performClick();
@@ -674,7 +670,8 @@
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 2, sbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null,
+ null, false);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(GONE, settingsLink.getVisibility());
}
@@ -694,7 +691,7 @@
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, null);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, false);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(GONE, settingsLink.getVisibility());
}
@@ -710,8 +707,7 @@
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -723,8 +719,7 @@
public void testUndoText_block() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -736,8 +731,7 @@
public void testNoHeaderOnConfirmation() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -748,8 +742,7 @@
public void testHeaderOnUndo() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java
index 2792d8c..07ac11b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java
@@ -1,17 +1,23 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
import com.android.systemui.statusbar.phone.StatusBarIconList;
+import com.android.systemui.statusbar.phone.StatusBarIconList.Slot;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,45 +47,125 @@
@Test
public void testAddSlotSlidesIcons() {
StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
- StatusBarIcon sbIcon = mock(StatusBarIcon.class);
- statusBarIconList.setIcon(0, sbIcon);
+ StatusBarIconHolder sbHolder = mock(StatusBarIconHolder.class);
+ statusBarIconList.setIcon(0, sbHolder);
statusBarIconList.getSlotIndex("zzz"); // new content added in front
- assertNull(statusBarIconList.getIcon(0));
- assertEquals(sbIcon, statusBarIconList.getIcon(1));
+ assertNull(statusBarIconList.getIcon(0, TAG_PRIMARY));
+ assertEquals(sbHolder, statusBarIconList.getIcon(1, TAG_PRIMARY));
}
@Test
public void testGetAndSetIcon() {
StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
- StatusBarIcon sbIconA = mock(StatusBarIcon.class);
- StatusBarIcon sbIconB = mock(StatusBarIcon.class);
- statusBarIconList.setIcon(0, sbIconA);
- statusBarIconList.setIcon(1, sbIconB);
- assertEquals(sbIconA, statusBarIconList.getIcon(0));
- assertEquals(sbIconB, statusBarIconList.getIcon(1));
- assertNull(statusBarIconList.getIcon(2)); // icon not set
+ StatusBarIconHolder sbHolderA = mock(StatusBarIconHolder.class);
+ StatusBarIconHolder sbHolderB = mock(StatusBarIconHolder.class);
+ statusBarIconList.setIcon(0, sbHolderA);
+ statusBarIconList.setIcon(1, sbHolderB);
+ assertEquals(sbHolderA, statusBarIconList.getIcon(0, TAG_PRIMARY));
+ assertEquals(sbHolderB, statusBarIconList.getIcon(1, TAG_PRIMARY));
+ assertNull(statusBarIconList.getIcon(2, TAG_PRIMARY)); // icon not set
}
@Test
public void testRemoveIcon() {
StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
- StatusBarIcon sbIconA = mock(StatusBarIcon.class);
- StatusBarIcon sbIconB = mock(StatusBarIcon.class);
- statusBarIconList.setIcon(0, sbIconA);
- statusBarIconList.setIcon(1, sbIconB);
- statusBarIconList.removeIcon(0);
- assertNull(statusBarIconList.getIcon(0)); // icon not set
+ StatusBarIconHolder sbHolderA = mock(StatusBarIconHolder.class);
+ StatusBarIconHolder sbHolderB = mock(StatusBarIconHolder.class);
+ statusBarIconList.setIcon(0, sbHolderA);
+ statusBarIconList.setIcon(1, sbHolderB);
+ statusBarIconList.removeIcon(0, TAG_PRIMARY);
+ assertNull(statusBarIconList.getIcon(0, TAG_PRIMARY)); // icon not set
}
@Test
- public void testGetViewIndex() {
+ public void testGetViewIndex_NoMultiples() {
StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
- StatusBarIcon sbIcon = mock(StatusBarIcon.class);
- statusBarIconList.setIcon(2, sbIcon);
- assertEquals(0, statusBarIconList.getViewIndex(2)); // Icon for item 2 is 0th child view.
- statusBarIconList.setIcon(0, sbIcon);
- assertEquals(0, statusBarIconList.getViewIndex(0)); // Icon for item 0 is 0th child view,
- assertEquals(1, statusBarIconList.getViewIndex(2)); // and item 2 is now 1st child view.
+ StatusBarIconHolder sbHolder = mock(StatusBarIconHolder.class);
+ statusBarIconList.setIcon(2, sbHolder);
+ // Icon for item 2 is 0th child view.
+ assertEquals(0, statusBarIconList.getViewIndex(2, TAG_PRIMARY));
+ statusBarIconList.setIcon(0, sbHolder);
+ // Icon for item 0 is 0th child view,
+ assertEquals(0, statusBarIconList.getViewIndex(0, TAG_PRIMARY));
+ // and item 2 is now 1st child view.
+ assertEquals(1, statusBarIconList.getViewIndex(2, TAG_PRIMARY));
}
+ @Test
+ public void testGetViewIndex_MultipleIconsPerSlot() {
+ StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+ StatusBarIconHolder sbHolder = mock(StatusBarIconHolder.class);
+
+ statusBarIconList.setIcon(2, sbHolder); // item 2, one icon 0th child
+
+ // All of these can be added to the same slot
+ // no tag bc it defaults to 0
+ StatusBarIconHolder sbHolder2 = mock(StatusBarIconHolder.class);
+ StatusBarIconHolder sbHolder3 = mock(StatusBarIconHolder.class);
+ int sb3Tag = 1;
+ when(sbHolder3.getTag()).thenReturn(sb3Tag);
+ StatusBarIconHolder sbHolder4 = mock(StatusBarIconHolder.class);
+ int sb4Tag = 2;
+ when(sbHolder4.getTag()).thenReturn(sb4Tag);
+
+ // Put a holder at slot 1, verify that it is first
+ statusBarIconList.setIcon(1, sbHolder2);
+ assertEquals(0, statusBarIconList.getViewIndex(1, TAG_PRIMARY));
+
+ // Put another holder at slot 1, verify it's index 0 and the rest come after
+ statusBarIconList.setIcon(1, sbHolder3);
+ assertEquals(0, statusBarIconList.getViewIndex(1, sb3Tag));
+ assertEquals(1, statusBarIconList.getViewIndex(1, TAG_PRIMARY));
+ // First icon should be at the end
+ assertEquals(2, statusBarIconList.getViewIndex(2, TAG_PRIMARY));
+
+ // Put another one in there just for good measure
+ statusBarIconList.setIcon(1, sbHolder4);
+ assertEquals(0, statusBarIconList.getViewIndex(1, sb4Tag));
+ assertEquals(1, statusBarIconList.getViewIndex(1, sb3Tag));
+ assertEquals(2, statusBarIconList.getViewIndex(1, TAG_PRIMARY));
+ assertEquals(3, statusBarIconList.getViewIndex(2, TAG_PRIMARY));
+ }
+
+ /**
+ * StatusBarIconList.Slot tests
+ */
+
+ @Test
+ public void testSlot_OrderIsPreserved() {
+ Slot testSlot = new Slot("test_name", null);
+
+ // no tag bc it defaults to 0
+ StatusBarIconHolder sbHolder1 = mock(StatusBarIconHolder.class);
+ StatusBarIconHolder sbHolder2 = mock(StatusBarIconHolder.class);
+ int sb2Tag = 1;
+ when(sbHolder2.getTag()).thenReturn(sb2Tag);
+ StatusBarIconHolder sbHolder3 = mock(StatusBarIconHolder.class);
+ int sb3Tag = 2;
+ when(sbHolder3.getTag()).thenReturn(sb3Tag);
+
+ ArrayList<StatusBarIconHolder> expected = new ArrayList<>();
+ expected.add(sbHolder1);
+ expected.add(sbHolder2);
+ expected.add(sbHolder3);
+
+
+ // Add 3 icons in the same slot, and verify that the list we get is equal to what we gave
+ for (StatusBarIconHolder holder : expected) {
+ testSlot.addHolder(holder);
+ }
+ assertTrue(listsEqual(expected, testSlot.getHolderList()));
+ }
+
+ private boolean listsEqual(List<StatusBarIconHolder> list1, List<StatusBarIconHolder> list2) {
+ if (list1.size() != list2.size()) return false;
+
+ for (int i = 0; i < list1.size(); i++) {
+ if (!list1.get(i).equals(list2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index 5db7792..72b0156 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -14,10 +14,17 @@
package com.android.systemui.statusbar.phone;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import android.graphics.Rect;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -25,9 +32,14 @@
import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarMobileView;
+import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -50,50 +62,119 @@
public void testSetCalledOnAdd_IconManager() {
LinearLayout layout = new LinearLayout(mContext);
TestIconManager manager = new TestIconManager(layout);
- StatusBarIcon icon = mock(StatusBarIcon.class);
-
- manager.onIconAdded(0, "test_slot", false, icon);
- verify(manager.mMock).set(eq(icon));
+ testCallOnAdd_forManager(manager);
}
@Test
public void testSetCalledOnAdd_DarkIconManager() {
LinearLayout layout = new LinearLayout(mContext);
TestDarkIconManager manager = new TestDarkIconManager(layout);
- StatusBarIcon icon = mock(StatusBarIcon.class);
-
- manager.onIconAdded(0, "test_slot", false, icon);
- verify(manager.mMock).set(eq(icon));
+ testCallOnAdd_forManager(manager);
}
- private static class TestDarkIconManager extends DarkIconManager {
- private final StatusBarIconView mMock;
+ private <T extends IconManager & TestableIconManager> void testCallOnAdd_forManager(T manager) {
+ StatusBarIconHolder holder = holderForType(TYPE_ICON);
+ manager.onIconAdded(0, "test_slot", false, holder);
+ assertTrue("Expected StatusBarIconView",
+ (manager.getViewAt(0) instanceof StatusBarIconView));
+
+ holder = holderForType(TYPE_WIFI);
+ manager.onIconAdded(1, "test_wifi", false, holder);
+ assertTrue(manager.getViewAt(1) instanceof StatusBarWifiView);
+
+ holder = holderForType(TYPE_MOBILE);
+ manager.onIconAdded(2, "test_mobile", false, holder);
+ assertTrue(manager.getViewAt(2) instanceof StatusBarMobileView);
+ }
+
+ private StatusBarIconHolder holderForType(int type) {
+ switch (type) {
+ case TYPE_MOBILE:
+ return StatusBarIconHolder.fromMobileIconState(mock(MobileIconState.class));
+
+ case TYPE_WIFI:
+ return StatusBarIconHolder.fromWifiIconState(mock(WifiIconState.class));
+
+ case TYPE_ICON:
+ default:
+ return StatusBarIconHolder.fromIcon(mock(StatusBarIcon.class));
+ }
+ }
+
+ private static class TestDarkIconManager extends DarkIconManager
+ implements TestableIconManager {
public TestDarkIconManager(LinearLayout group) {
super(group);
- mMock = mock(StatusBarIconView.class);
}
@Override
- protected StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
- return mMock;
+ public StatusIconDisplayable getViewAt(int index) {
+ return (StatusIconDisplayable) mGroup.getChildAt(index);
+ }
+
+ @Override
+ protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
+ StatusBarIcon icon) {
+ StatusBarIconView mock = mock(StatusBarIconView.class);
+ mGroup.addView(mock, index);
+
+ return mock;
+ }
+
+ @Override
+ protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
+ StatusBarWifiView mock = mock(StatusBarWifiView.class);
+ mGroup.addView(mock, index);
+ return mock;
+ }
+
+ @Override
+ protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
+ StatusBarMobileView mock = mock(StatusBarMobileView.class);
+ mGroup.addView(mock, index);
+
+ return mock;
}
}
- private static class TestIconManager extends IconManager {
-
- private final StatusBarIconView mMock;
-
+ private static class TestIconManager extends IconManager implements TestableIconManager {
public TestIconManager(ViewGroup group) {
super(group);
- mMock = mock(StatusBarIconView.class);
}
@Override
- protected StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
- return mMock;
+ public StatusIconDisplayable getViewAt(int index) {
+ return (StatusIconDisplayable) mGroup.getChildAt(index);
+ }
+
+ @Override
+ protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
+ StatusBarIcon icon) {
+ StatusBarIconView mock = mock(StatusBarIconView.class);
+ mGroup.addView(mock, index);
+
+ return mock;
+ }
+
+ @Override
+ protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
+ StatusBarWifiView mock = mock(StatusBarWifiView.class);
+ mGroup.addView(mock, index);
+ return mock;
+ }
+
+ @Override
+ protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
+ StatusBarMobileView mock = mock(StatusBarMobileView.class);
+ mGroup.addView(mock, index);
+
+ return mock;
}
}
+ private interface TestableIconManager {
+ StatusIconDisplayable getViewAt(int index);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 6b501af..8e34685 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -19,6 +19,9 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import java.util.List;
public class FakeStatusBarIconController extends BaseLeakChecker<IconManager>
implements StatusBarIconController {
@@ -53,12 +56,23 @@
}
@Override
- public void setIconVisibility(String slotTty, boolean b) {
-
+ public void setSignalIcon(String slot, WifiIconState state) {
}
@Override
- public void removeIcon(String slot) {
-
+ public void setMobileIcons(String slot, List<MobileIconState> states) {
}
+
+ @Override
+ public void setIconVisibility(String slotTty, boolean b) {
+ }
+
+ @Override
+ public void removeIcon(String slot, int tag) {
+ }
+
+ @Override
+ public void removeAllIconsForSlot(String slot) {
+ }
+
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 1605252..934ad88 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -413,6 +413,15 @@
// Indicates the number of times we got an interface down in softap mode.
optional int32 num_soft_ap_interface_down = 103;
+
+ // Indicates the number of scan requests from external apps.
+ optional int32 num_external_app_oneshot_scan_requests = 104;
+
+ // Indicates the number of times a scan request from an external foreground app was throttled.
+ optional int32 num_external_foreground_app_oneshot_scan_requests_throttled = 105;
+
+ // Indicates the number of times a scan request from an external background app was throttled.
+ optional int32 num_external_background_app_oneshot_scan_requests_throttled = 106;
}
// Information that gets logged for every WiFi connection.
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index f6ff359..40f9476 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -266,9 +266,9 @@
@GuardedBy("LOCK")
private boolean mValue;
- public DebugFlag(String key) {
+ public DebugFlag(String key, boolean defaultValue) {
mKey = key;
- refresh();
+ mValue = SystemProperties.getBoolean(key, defaultValue);
}
void refresh() {
@@ -290,7 +290,7 @@
*/
private static final class DebugFlags {
static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
- new DebugFlag("debug.optimize_startinput");
+ new DebugFlag("debug.optimize_startinput", false);
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index d09a161..bde6bd8 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -931,7 +931,7 @@
return mPort;
}
- public FileDescriptor getSocket() {
+ public FileDescriptor getFileDescriptor() {
return mSocket;
}
@@ -1065,7 +1065,10 @@
public synchronized IpSecSpiResponse allocateSecurityParameterIndex(
String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException {
checkInetAddress(destinationAddress);
- /* requestedSpi can be anything in the int range, so no check is needed. */
+ // RFC 4303 Section 2.1 - 0=local, 1-255=reserved.
+ if (requestedSpi > 0 && requestedSpi < 256) {
+ throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
+ }
checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 08e5d44..f756afb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4493,8 +4493,8 @@
StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
component.app.uid, component.realActivity.getPackageName(),
component.realActivity.getShortClassName(), resumed ?
- StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__ACTIVITY__MOVE_TO_FOREGROUND :
- StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__ACTIVITY__MOVE_TO_BACKGROUND);
+ StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
+ StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
if (resumed) {
if (mUsageStatsService != null) {
mUsageStatsService.reportEvent(component.realActivity, component.userId,
@@ -13179,10 +13179,6 @@
+ android.Manifest.permission.SHUTDOWN);
}
- // TODO: Where should the corresponding '1' (start) write go?
- StatsLog.write(StatsLog.DEVICE_ON_STATUS_CHANGED,
- StatsLog.DEVICE_ON_STATUS_CHANGED__STATE__OFF);
-
boolean timedout = false;
synchronized(this) {
@@ -14830,7 +14826,7 @@
.setPackage("android")
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
broadcastIntent(null, intent, null, null, 0, null, null, null,
- OP_NONE, null, true, false, UserHandle.USER_ALL);
+ OP_NONE, null, false, false, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -15197,6 +15193,12 @@
crashInfo.throwFileName,
crashInfo.throwLineNumber);
+ StatsLog.write(StatsLog.APP_CRASH_OCCURRED,
+ Binder.getCallingUid(),
+ eventType,
+ processName,
+ Binder.getCallingPid());
+
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
mAppErrors.crashApplication(r, crashInfo);
@@ -15367,6 +15369,9 @@
EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
+ StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName,
+ callingPid);
+
addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);
return r;
@@ -15488,19 +15493,6 @@
final String dropboxTag = processClass(process) + "_" + eventType;
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
- // Log to StatsLog before the rate-limiting.
- // The logging below is adapated from appendDropboxProcessHeaders.
- StatsLog.write(StatsLog.DROPBOX_ERROR_CHANGED,
- process != null ? process.uid : -1,
- dropboxTag,
- processName,
- process != null ? process.pid : -1,
- (process != null && process.info != null) ?
- (process.info.isInstantApp() ? 1 : 0) : -1,
- activity != null ? activity.shortComponentName : null,
- activity != null ? activity.packageName : null,
- process != null ? (process.isInterestingToUserLocked() ? 1 : 0) : -1);
-
// Rate-limit how often we're willing to do the heavy lifting below to
// collect and record logs; currently 5 logs per 10 second period.
final long now = SystemClock.elapsedRealtime();
@@ -19780,6 +19772,7 @@
catPw.flush();
}
dropBuilder.append(catSw.toString());
+ StatsLog.write(StatsLog.LOW_MEM_REPORTED);
addErrorToDropBox("lowmem", null, "system_server", null,
null, tag.toString(), dropBuilder.toString(), null, null);
//Slog.i(TAG, "Sent to dropbox:");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 724dd3f..47d0423 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -489,7 +489,7 @@
builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
mMetricsLogger.write(builder);
StatsLog.write(
- StatsLog.APP_START_CANCEL_CHANGED,
+ StatsLog.APP_START_CANCELED,
info.launchedActivity.appInfo.uid,
info.launchedActivity.packageName,
convertAppStartTransitionType(type),
@@ -561,7 +561,7 @@
packageOptimizationInfo.getCompilationFilter());
mMetricsLogger.write(builder);
StatsLog.write(
- StatsLog.APP_START_CHANGED,
+ StatsLog.APP_START_OCCURRED,
info.applicationInfo.uid,
info.packageName,
convertAppStartTransitionType(info.type),
@@ -582,15 +582,15 @@
private int convertAppStartTransitionType(int tronType) {
if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {
- return StatsLog.APP_START_CHANGED__TYPE__COLD;
+ return StatsLog.APP_START_OCCURRED__TYPE__COLD;
}
if (tronType == TYPE_TRANSITION_WARM_LAUNCH) {
- return StatsLog.APP_START_CHANGED__TYPE__WARM;
+ return StatsLog.APP_START_OCCURRED__TYPE__WARM;
}
if (tronType == TYPE_TRANSITION_HOT_LAUNCH) {
- return StatsLog.APP_START_CHANGED__TYPE__HOT;
+ return StatsLog.APP_START_OCCURRED__TYPE__HOT;
}
- return StatsLog.APP_START_CHANGED__TYPE__APP_START_TRANSITION_TYPE_UNKNOWN;
+ return StatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;
}
void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) {
@@ -611,12 +611,12 @@
info.currentTransitionProcessRunning ? 1 : 0);
mMetricsLogger.write(builder);
StatsLog.write(
- StatsLog.APP_START_FULLY_DRAWN_CHANGED,
+ StatsLog.APP_START_FULLY_DRAWN,
info.launchedActivity.appInfo.uid,
info.launchedActivity.packageName,
restoredFromBundle
- ? StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITH_BUNDLE
- : StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITHOUT_BUNDLE,
+ ? StatsLog.APP_START_FULLY_DRAWN__TYPE__WITH_BUNDLE
+ : StatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
info.launchedActivity.info.name,
info.currentTransitionProcessRunning,
startupTimeMs);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index b2872e4..7ee20fa2 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -47,6 +47,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.StatsLog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -1039,6 +1040,8 @@
Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
}
+ StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,
+ activity == null ? "unknown": activity.shortComponentName, annotation);
mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index b338029..8ecd93e 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -337,7 +337,7 @@
synchronized (mStats) {
mStats.noteProcessStartLocked(name, uid);
StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
- StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__EVENT__PROCESS_STARTED);
+ StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__STARTED);
}
}
@@ -345,15 +345,13 @@
synchronized (mStats) {
mStats.noteProcessCrashLocked(name, uid);
StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
- StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__EVENT__PROCESS_CRASHED);
+ StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__CRASHED);
}
}
void noteProcessAnr(String name, int uid) {
synchronized (mStats) {
mStats.noteProcessAnrLocked(name, uid);
- StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
- StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__EVENT__PROCESS_ANRED);
}
}
@@ -361,7 +359,7 @@
synchronized (mStats) {
mStats.noteProcessFinishLocked(name, uid);
StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
- StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__EVENT__PROCESS_FINISHED);
+ StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__FINISHED);
}
}
@@ -768,8 +766,8 @@
enforceCallingPermission();
synchronized (mStats) {
mStats.noteVideoOnLocked(uid);
- StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, uid, null,
- StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED__STATE__ON);
+ StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null,
+ StatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
}
}
@@ -777,8 +775,8 @@
enforceCallingPermission();
synchronized (mStats) {
mStats.noteVideoOffLocked(uid);
- StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, uid,
- null, StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED__STATE__OFF);
+ StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid,
+ null, StatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
}
}
@@ -795,8 +793,8 @@
enforceCallingPermission();
synchronized (mStats) {
mStats.noteResetVideoLocked();
- StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, -1, null,
- StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED__STATE__RESET);
+ StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, -1, null,
+ StatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
}
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 262a2f8..92d3772 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1470,6 +1470,8 @@
proto.end(userToken);
}
proto.flush();
+ mPerformanceMap.clear();
+ mCryptoPerformanceMap.clear();
}
@Override
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 1dbcfd6..40d2a3a 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -19,7 +19,6 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.AlarmManager;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -101,18 +100,19 @@
final class IdlenessTracker extends BroadcastReceiver {
private AlarmManager mAlarm;
- private PendingIntent mIdleTriggerIntent;
- boolean mIdle;
- boolean mScreenOn;
+
+ // After construction, mutations of idle/screen-on state will only happen
+ // on the main looper thread, either in onReceive() or in an alarm callback.
+ private boolean mIdle;
+ private boolean mScreenOn;
+
+ private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> {
+ handleIdleTrigger();
+ };
public IdlenessTracker() {
mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(ActivityManagerService.ACTION_TRIGGER_IDLE)
- .setPackage("android")
- .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-
// At boot we presume that the user has just "interacted" with the
// device in some meaningful way.
mIdle = false;
@@ -150,7 +150,7 @@
}
mScreenOn = true;
//cancel the alarm
- mAlarm.cancel(mIdleTriggerIntent);
+ mAlarm.cancel(mIdleAlarmListener);
if (mIdle) {
// possible transition to not-idle
mIdle = false;
@@ -169,20 +169,24 @@
}
mScreenOn = false;
mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- when, mIdleWindowSlop, mIdleTriggerIntent);
+ when, mIdleWindowSlop, "JS idleness", mIdleAlarmListener, null);
} else if (action.equals(ActivityManagerService.ACTION_TRIGGER_IDLE)) {
- // idle time starts now. Do not set mIdle if screen is on.
- if (!mIdle && !mScreenOn) {
- if (DEBUG) {
- Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis());
- }
- mIdle = true;
- reportNewIdleState(mIdle);
- } else {
- if (DEBUG) {
- Slog.v(TAG, "TRIGGER_IDLE received but not changing state; idle="
- + mIdle + " screen=" + mScreenOn);
- }
+ handleIdleTrigger();
+ }
+ }
+
+ private void handleIdleTrigger() {
+ // idle time starts now. Do not set mIdle if screen is on.
+ if (!mIdle && !mScreenOn) {
+ if (DEBUG) {
+ Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis());
+ }
+ mIdle = true;
+ reportNewIdleState(mIdle);
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "TRIGGER_IDLE received but not changing state; idle="
+ + mIdle + " screen=" + mScreenOn);
}
}
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c445f73..5955c9c 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2513,6 +2513,8 @@
* this handler.
*/
private void handleInitialize() {
+ native_init_once();
+
/*
* A cycle of native_init() and native_cleanup() is needed so that callbacks are
* registered after bootup even when location is disabled.
@@ -2899,6 +2901,8 @@
private static native boolean native_is_gnss_configuration_supported();
+ private static native void native_init_once();
+
private native boolean native_init();
private native void native_cleanup();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index f617964..4b58d53 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2079,11 +2079,6 @@
}
@Override
- public byte[] generateAndStoreKey(@NonNull String alias) throws RemoteException {
- return mRecoverableKeyStoreManager.generateAndStoreKey(alias);
- }
-
- @Override
public @Nullable String generateKey(@NonNull String alias) throws RemoteException {
return mRecoverableKeyStoreManager.generateKey(alias);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 1dab592..ff4c678 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -672,40 +672,6 @@
}
/**
- * Deprecated
- * Generates a key named {@code alias} in the recoverable store for the calling uid. Then
- * returns the raw key material.
- *
- * <p>TODO: Once AndroidKeyStore has added move api, do not return raw bytes.
- *
- * @deprecated
- * @hide
- */
- public byte[] generateAndStoreKey(@NonNull String alias) throws RemoteException {
- checkRecoverKeyStorePermission();
- int uid = Binder.getCallingUid();
- int userId = UserHandle.getCallingUserId();
-
- PlatformEncryptionKey encryptionKey;
- try {
- encryptionKey = mPlatformKeyManager.getEncryptKey(userId);
- } catch (NoSuchAlgorithmException e) {
- // Impossible: all algorithms must be supported by AOSP
- throw new RuntimeException(e);
- } catch (KeyStoreException | UnrecoverableKeyException e) {
- throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
- } catch (InsecureUserException e) {
- throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
- }
-
- try {
- return mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId, uid, alias);
- } catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) {
- throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
- }
- }
-
- /**
* Destroys the session with the given {@code sessionId}.
*/
public void closeSession(@NonNull String sessionId) throws RemoteException {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b7842d5..d5a32aa 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -982,7 +982,11 @@
Slog.w(TAG, getCaption() + " binding died: " + name);
synchronized (mMutex) {
mServicesBinding.remove(servicesBindingTag);
- mContext.unbindService(this);
+ try {
+ mContext.unbindService(this);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "failed to unbind " + name, e);
+ }
if (!mServicesRebinding.contains(servicesBindingTag)) {
mServicesRebinding.add(servicesBindingTag);
mHandler.postDelayed(new Runnable() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 31b0461..f31ca0a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -182,6 +182,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.ArrayUtils;
@@ -898,6 +899,8 @@
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ // update system notification channels
+ SystemNotificationChannels.createAll(context);
mZenModeHelper.updateDefaultZenRules();
mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 24abf86..9d3f48b 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -484,11 +484,11 @@
}
}
- public void installApkVerity(String filePath, FileDescriptor verityInput)
+ public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)
throws InstallerException {
if (!checkBeforeRemote()) return;
try {
- mInstalld.installApkVerity(filePath, verityInput);
+ mInstalld.installApkVerity(filePath, verityInput, contentSize);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 9807342..892fa12 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -450,11 +450,9 @@
for (String isa : dexCodeInstructionSets) {
try {
- String[] status = DexFile.getDexFileOptimizationStatus(path, isa);
- String compilationStatus = status[0];
- String compilationReason = status[1];
- pw.println(isa + ": [status=" + compilationStatus
- +"] reason=[" + compilationReason + "]");
+ DexFile.OptimizationInfo info = DexFile.getDexFileOptimizationInfo(path, isa);
+ pw.println(isa + ": [status=" + info.getStatus()
+ +"] [reason=" + info.getReason() + "]");
} catch (IOException ioe) {
pw.println(isa + ": [Exception]: " + ioe.getMessage());
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7b77c96..cb1972f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17322,8 +17322,11 @@
if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
FileDescriptor fd = result.getUnownedFileDescriptor();
try {
- mInstaller.installApkVerity(apkPath, fd);
- } catch (InstallerException e) {
+ final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);
+ mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
+ mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
+ } catch (InstallerException | IOException | DigestException |
+ NoSuchAlgorithmException e) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to set up verity: " + e);
return;
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index cdafe57..9c2ad463 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -527,9 +527,10 @@
String compilationFilter;
try {
String isa = VMRuntime.getInstructionSet(abi);
- String[] stats = DexFile.getDexFileOptimizationStatus(info.getBaseCodePath(), isa);
- compilationFilter = stats[0];
- compilationReason = stats[1];
+ DexFile.OptimizationInfo optInfo =
+ DexFile.getDexFileOptimizationInfo(info.getBaseCodePath(), isa);
+ compilationFilter = optInfo.getStatus();
+ compilationReason = optInfo.getReason();
} catch (FileNotFoundException e) {
Slog.e(TAG, "Could not get optimizations status for " + info.getBaseCodePath(), e);
compilationFilter = "error";
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 941cd44..e56caf8 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,6 +19,8 @@
import android.app.ActivityManager;
import android.content.Context;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.security.IKeystoreService;
import android.util.Slog;
import com.android.internal.policy.IKeyguardService;
@@ -51,11 +53,16 @@
private final LockPatternUtils mLockPatternUtils;
private final StateCallback mCallback;
+ IKeystoreService mKeystoreService;
+
public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
mCallback = callback;
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+
try {
service.addStateMonitorCallback(this);
} catch (RemoteException e) {
@@ -86,6 +93,12 @@
@Override // Binder interface
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
+
+ try {
+ mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error informing keystore of screen lock", e);
+ }
}
@Override // Binder interface
@@ -130,4 +143,4 @@
pw.println(prefix + "mTrusted=" + mTrusted);
pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index d2d0e60..180f343 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -26,6 +26,7 @@
import android.util.apk.ApkSignatureVerifier;
import android.util.apk.ByteBufferFactory;
import android.util.apk.SignatureNotFoundException;
+import android.util.Pair;
import android.util.Slog;
import java.io.FileDescriptor;
@@ -59,12 +60,15 @@
return SetupResult.skipped();
}
- shm = generateApkVerityIntoSharedMemory(apkPath, signedRootHash);
+ Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath,
+ signedRootHash);
+ shm = result.first;
+ int contentSize = result.second;
FileDescriptor rfd = shm.getFileDescriptor();
if (rfd == null || !rfd.valid()) {
return SetupResult.failed();
}
- return SetupResult.ok(Os.dup(rfd));
+ return SetupResult.ok(Os.dup(rfd), contentSize);
} catch (IOException | SecurityException | DigestException | NoSuchAlgorithmException |
SignatureNotFoundException | ErrnoException e) {
Slog.e(TAG, "Failed to set up apk verity: ", e);
@@ -85,10 +89,20 @@
}
/**
- * Returns a {@code SharedMemory} that contains Merkle tree and fsverity headers for the given
- * apk, in the form that can immediately be used for fsverity setup.
+ * {@see ApkSignatureVerifier#getVerityRootHash(String)}.
*/
- private static SharedMemory generateApkVerityIntoSharedMemory(
+ public static byte[] getVerityRootHash(@NonNull String apkPath)
+ throws IOException, SignatureNotFoundException, SecurityException {
+ return ApkSignatureVerifier.getVerityRootHash(apkPath);
+ }
+
+ /**
+ * Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains
+ * Merkle tree and fsverity headers for the given apk, in the form that can immediately be used
+ * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
+ * length equals to the returned {@code Integer}.
+ */
+ private static Pair<SharedMemory, Integer> generateApkVerityIntoSharedMemory(
String apkPath, byte[] expectedRootHash)
throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
SignatureNotFoundException {
@@ -101,6 +115,7 @@
throw new SecurityException("Locally generated verity root hash does not match");
}
+ int contentSize = shmBufferFactory.getBufferLimit();
SharedMemory shm = shmBufferFactory.releaseSharedMemory();
if (shm == null) {
throw new IllegalStateException("Failed to generate verity tree into shared memory");
@@ -108,7 +123,7 @@
if (!shm.setProtect(PROT_READ)) {
throw new SecurityException("Failed to set up shared memory correctly");
}
- return shm;
+ return Pair.create(shm, contentSize);
}
public static class SetupResult {
@@ -123,22 +138,24 @@
private final int mCode;
private final FileDescriptor mFileDescriptor;
+ private final int mContentSize;
- public static SetupResult ok(@NonNull FileDescriptor fileDescriptor) {
- return new SetupResult(RESULT_OK, fileDescriptor);
+ public static SetupResult ok(@NonNull FileDescriptor fileDescriptor, int contentSize) {
+ return new SetupResult(RESULT_OK, fileDescriptor, contentSize);
}
public static SetupResult skipped() {
- return new SetupResult(RESULT_SKIPPED, null);
+ return new SetupResult(RESULT_SKIPPED, null, -1);
}
public static SetupResult failed() {
- return new SetupResult(RESULT_FAILED, null);
+ return new SetupResult(RESULT_FAILED, null, -1);
}
- private SetupResult(int code, FileDescriptor fileDescriptor) {
+ private SetupResult(int code, FileDescriptor fileDescriptor, int contentSize) {
this.mCode = code;
this.mFileDescriptor = fileDescriptor;
+ this.mContentSize = contentSize;
}
public boolean isFailed() {
@@ -152,6 +169,10 @@
public @NonNull FileDescriptor getUnownedFileDescriptor() {
return mFileDescriptor;
}
+
+ public int getContentSize() {
+ return mContentSize;
+ }
}
/** A {@code ByteBufferFactory} that creates a shared memory backed {@code ByteBuffer}. */
@@ -188,5 +209,9 @@
mShm = null;
return tmp;
}
+
+ public int getBufferLimit() {
+ return mBuffer == null ? -1 : mBuffer.limit();
+ }
}
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index d252a56..753394d 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -39,6 +39,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.IBinder;
import android.os.IStatsCompanionService;
import android.os.IStatsManager;
@@ -68,14 +69,21 @@
import com.android.internal.os.KernelWakelockReader;
import com.android.internal.os.KernelWakelockStats;
import com.android.internal.os.PowerProfile;
+import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
@@ -89,14 +97,17 @@
* How long to wait on an individual subsystem to return its stats.
*/
private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
+ private static final long MILLIS_IN_A_DAY = TimeUnit.DAYS.toMillis(1);
public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
+ public static final String CONFIG_DIR = "/data/misc/stats-service";
static final String TAG = "StatsCompanionService";
static final boolean DEBUG = false;
public static final int CODE_DATA_BROADCAST = 1;
public static final int CODE_SUBSCRIBER_BROADCAST = 1;
+ public static final int DEATH_THRESHOLD = 10;
private final Context mContext;
private final AlarmManager mAlarmManager;
@@ -119,6 +130,10 @@
new StatFs(Environment.getRootDirectory().getAbsolutePath());
private final StatFs mStatFsTemp =
new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
+ @GuardedBy("sStatsdLock")
+ private final HashSet<Long> mDeathTimeMillis = new HashSet<>();
+ @GuardedBy("sStatsdLock")
+ private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
private KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
@@ -156,7 +171,7 @@
informAllUidsLocked(context);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to inform statsd latest update of all apps", e);
- forgetEverything();
+ forgetEverythingLocked();
}
}
}
@@ -751,7 +766,7 @@
});
}
- private void pullWifiActivityEnergyInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+ private void pullWifiActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
long token = Binder.clearCallingIdentity();
if (mWifiManager == null) {
mWifiManager =
@@ -919,8 +934,8 @@
pullKernelUidCpuActiveTime(tagId, ret);
break;
}
- case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: {
- pullWifiActivityEnergyInfo(tagId, ret);
+ case StatsLog.WIFI_ACTIVITY_INFO: {
+ pullWifiActivityInfo(tagId, ret);
break;
}
case StatsLog.MODEM_ACTIVITY_INFO: {
@@ -1055,7 +1070,7 @@
sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
} catch (RemoteException e) {
Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
- forgetEverything();
+ forgetEverythingLocked();
}
// Setup broadcast receiver for updates.
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
@@ -1087,7 +1102,7 @@
Slog.i(TAG, "Told statsd that StatsCompanionService is alive.");
} catch (RemoteException e) {
Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
- forgetEverything();
+ forgetEverythingLocked();
}
}
}
@@ -1096,18 +1111,60 @@
@Override
public void binderDied() {
Slog.i(TAG, "Statsd is dead - erase all my knowledge.");
- forgetEverything();
+ synchronized (sStatsdLock) {
+ long now = SystemClock.elapsedRealtime();
+ for (Long timeMillis : mDeathTimeMillis) {
+ long ageMillis = now - timeMillis;
+ if (ageMillis > MILLIS_IN_A_DAY) {
+ mDeathTimeMillis.remove(timeMillis);
+ }
+ }
+ for (Long timeMillis : mDeletedFiles.keySet()) {
+ long ageMillis = now - timeMillis;
+ if (ageMillis > MILLIS_IN_A_DAY * 7) {
+ mDeletedFiles.remove(timeMillis);
+ }
+ }
+ mDeathTimeMillis.add(now);
+ if (mDeathTimeMillis.size() >= DEATH_THRESHOLD) {
+ mDeathTimeMillis.clear();
+ File[] configs = FileUtils.listFilesOrEmpty(new File(CONFIG_DIR));
+ if (configs.length > 0) {
+ String fileName = configs[0].getName();
+ if (configs[0].delete()) {
+ mDeletedFiles.put(now, fileName);
+ }
+ }
+ }
+ forgetEverythingLocked();
+ }
}
}
- private void forgetEverything() {
+ private void forgetEverythingLocked() {
+ sStatsd = null;
+ mContext.unregisterReceiver(mAppUpdateReceiver);
+ mContext.unregisterReceiver(mUserUpdateReceiver);
+ mContext.unregisterReceiver(mShutdownEventReceiver);
+ cancelAnomalyAlarm();
+ cancelPullingAlarm();
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+
synchronized (sStatsdLock) {
- sStatsd = null;
- mContext.unregisterReceiver(mAppUpdateReceiver);
- mContext.unregisterReceiver(mUserUpdateReceiver);
- mContext.unregisterReceiver(mShutdownEventReceiver);
- cancelAnomalyAlarm();
- cancelPullingAlarm();
+ writer.println("Number of configuration files deleted: " + mDeletedFiles.size());
+ if (mDeletedFiles.size() > 0) {
+ writer.println(" timestamp, deleted file name");
+ }
+ long lastBootMillis =
+ SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime();
+ for (Long elapsedMillis : mDeletedFiles.keySet()) {
+ long deletionMillis = lastBootMillis + elapsedMillis;
+ writer.println(" " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
+ }
}
}
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index ecf1a33..f7ca363 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -231,6 +231,13 @@
return nullptr;
}
bandConfigHal = module.bands[0];
+
+ /* Prefer FM to workaround possible program list fetching limitation
+ * (if tuner scans only configured band for programs). */
+ auto fmIt = std::find_if(module.bands.begin(), module.bands.end(),
+ [](const BandConfig & band) { return utils::isFm(band.type); });
+ if (fmIt != module.bands.end()) bandConfigHal = *fmIt;
+
if (bandConfigHal.spacings.size() > 1) {
bandConfigHal.spacings = hidl_vec<uint32_t>({ *std::min_element(
bandConfigHal.spacings.begin(), bandConfigHal.spacings.end()) });
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index dcee151..21fea1c 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1125,6 +1125,16 @@
}
static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+ gnssHal_V1_1 = IGnss_V1_1::getService();
+ if (gnssHal_V1_1 == nullptr) {
+ ALOGD("gnssHal 1.1 was null, trying 1.0");
+ gnssHal = IGnss_V1_0::getService();
+ } else {
+ gnssHal = gnssHal_V1_1;
+ }
+}
+
+static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass clazz) {
method_reportLocation = env->GetMethodID(clazz, "reportLocation",
"(ZLandroid/location/Location;)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
@@ -1175,15 +1185,6 @@
LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus);
}
- // TODO(b/31632518)
- gnssHal_V1_1 = IGnss_V1_1::getService();
- if (gnssHal_V1_1 == nullptr) {
- ALOGD("gnssHal 1.1 was null, trying 1.0");
- gnssHal = IGnss_V1_0::getService();
- } else {
- gnssHal = gnssHal_V1_1;
- }
-
if (gnssHal != nullptr) {
gnssHalDeathRecipient = new GnssDeathRecipient();
hardware::Return<bool> linked = gnssHal->linkToDeath(
@@ -2068,6 +2069,8 @@
{"native_is_gnss_configuration_supported", "()Z",
reinterpret_cast<void *>(
android_location_gpsLocationProvider_is_gnss_configuration_supported)},
+ {"native_init_once", "()V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_init_once)},
{"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
{"native_cleanup", "()V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_cleanup)},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 71c2ea1..1c9782f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -78,23 +78,6 @@
return false;
}
- @Override
- public boolean setPasswordBlacklist(ComponentName who, String name, List<String> blacklist,
- boolean parent) {
- return false;
- }
-
- @Override
- public String getPasswordBlacklistName(ComponentName who, @UserIdInt int userId,
- boolean parent) {
- return null;
- }
-
- @Override
- public boolean isPasswordBlacklisted(@UserIdInt int userId, String password) {
- return false;
- }
-
public boolean isUsingUnifiedPassword(ComponentName who) {
return true;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ffa7311..90e8a9c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -820,7 +820,6 @@
private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
private static final String ATTR_VALUE = "value";
- private static final String TAG_PASSWORD_BLACKLIST = "password-blacklist";
private static final String TAG_PASSWORD_QUALITY = "password-quality";
private static final String TAG_POLICIES = "policies";
private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
@@ -961,9 +960,6 @@
// Default title of confirm credentials screen
String organizationName = null;
- // The blacklist data is stored in a file whose name is stored in the XML
- String passwordBlacklistFile = null;
-
// The component name of the backup transport which has to be used if backups are mandatory
// or null if backups are not mandatory.
ComponentName mandatoryBackupTransport = null;
@@ -1053,11 +1049,6 @@
out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
}
}
- if (passwordBlacklistFile != null) {
- out.startTag(null, TAG_PASSWORD_BLACKLIST);
- out.attribute(null, ATTR_VALUE, passwordBlacklistFile);
- out.endTag(null, TAG_PASSWORD_BLACKLIST);
- }
if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
@@ -1313,8 +1304,6 @@
} else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
minimumPasswordMetrics.nonLetter = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
- } else if (TAG_PASSWORD_BLACKLIST.equals(tag)) {
- passwordBlacklistFile = parser.getAttributeValue(null, ATTR_VALUE);
}else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
maximumTimeToUnlock = Long.parseLong(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -1589,8 +1578,6 @@
pw.println(minimumPasswordMetrics.symbols);
pw.print(prefix); pw.print("minimumPasswordNonLetter=");
pw.println(minimumPasswordMetrics.nonLetter);
- pw.print(prefix); pw.print("passwordBlacklist=");
- pw.println(passwordBlacklistFile != null);
pw.print(prefix); pw.print("maximumTimeToUnlock=");
pw.println(maximumTimeToUnlock);
pw.print(prefix); pw.print("strongAuthUnlockTimeout=");
@@ -1857,10 +1844,6 @@
return new LockPatternUtils(mContext);
}
- PasswordBlacklist newPasswordBlacklist(File file) {
- return new PasswordBlacklist(file);
- }
-
boolean storageManagerIsFileBasedEncryptionEnabled() {
return StorageManager.isFileEncryptedNativeOnly();
}
@@ -4413,136 +4396,6 @@
}
}
- /* @return the password blacklist set by the admin or {@code null} if none. */
- PasswordBlacklist getAdminPasswordBlacklistLocked(@NonNull ActiveAdmin admin) {
- final int userId = UserHandle.getUserId(admin.getUid());
- return admin.passwordBlacklistFile == null ? null : new PasswordBlacklist(
- new File(getPolicyFileDirectory(userId), admin.passwordBlacklistFile));
- }
-
- private static final String PASSWORD_BLACKLIST_FILE_PREFIX = "password-blacklist-";
- private static final String PASSWORD_BLACKLIST_FILE_SUFFIX = "";
-
- @Override
- public boolean setPasswordBlacklist(ComponentName who, String name, List<String> blacklist,
- boolean parent) {
- if (!mHasFeature) {
- return false;
- }
- Preconditions.checkNotNull(who, "who is null");
-
- synchronized (this) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
- final int userId = mInjector.userHandleGetCallingUserId();
- PasswordBlacklist adminBlacklist = getAdminPasswordBlacklistLocked(admin);
-
- if (blacklist == null || blacklist.isEmpty()) {
- // Remove the adminBlacklist
- admin.passwordBlacklistFile = null;
- saveSettingsLocked(userId);
- if (adminBlacklist != null) {
- adminBlacklist.delete();
- }
- return true;
- }
-
- // Validate server side
- Preconditions.checkNotNull(name, "name is null");
- DevicePolicyManager.enforcePasswordBlacklistSize(blacklist);
-
- // Blacklist is case insensitive so normalize to lower case
- final int blacklistSize = blacklist.size();
- for (int i = 0; i < blacklistSize; ++i) {
- blacklist.set(i, blacklist.get(i).toLowerCase());
- }
-
- final boolean isNewBlacklist = adminBlacklist == null;
- if (isNewBlacklist) {
- // Create a new file for the blacklist. There could be multiple admins, each setting
- // different blacklists, to restrict a user's credential, for example a managed
- // profile can impose restrictions on its parent while the parent is already
- // restricted by its own admin. A deterministic naming scheme would be fragile if
- // new types of admin are introduced so we generate and save the file name instead.
- // This isn't a temporary file but it reuses the name generation logic
- final File file;
- try {
- file = File.createTempFile(PASSWORD_BLACKLIST_FILE_PREFIX,
- PASSWORD_BLACKLIST_FILE_SUFFIX, getPolicyFileDirectory(userId));
- } catch (IOException e) {
- Slog.e(LOG_TAG, "Failed to make a file for the blacklist", e);
- return false;
- }
- adminBlacklist = mInjector.newPasswordBlacklist(file);
- }
-
- if (adminBlacklist.savePasswordBlacklist(name, blacklist)) {
- if (isNewBlacklist) {
- // The blacklist was saved so point the admin to the file
- admin.passwordBlacklistFile = adminBlacklist.getFile().getName();
- saveSettingsLocked(userId);
- }
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public String getPasswordBlacklistName(ComponentName who, @UserIdInt int userId,
- boolean parent) {
- if (!mHasFeature) {
- return null;
- }
- Preconditions.checkNotNull(who, "who is null");
- enforceFullCrossUsersPermission(userId);
- synchronized (this) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
- final PasswordBlacklist blacklist = getAdminPasswordBlacklistLocked(admin);
- if (blacklist == null) {
- return null;
- }
- return blacklist.getName();
- }
- }
-
- @Override
- public boolean isPasswordBlacklisted(@UserIdInt int userId, String password) {
- if (!mHasFeature) {
- return false;
- }
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.TEST_BLACKLISTED_PASSWORD, null);
- return isPasswordBlacklistedInternal(userId, password);
- }
-
- private boolean isPasswordBlacklistedInternal(@UserIdInt int userId, String password) {
- Preconditions.checkNotNull(password, "Password is null");
- enforceFullCrossUsersPermission(userId);
-
- // Normalize to lower case for case insensitive blacklist match
- final String lowerCasePassword = password.toLowerCase();
-
- synchronized (this) {
- final List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userId, /* parent */ false);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- final PasswordBlacklist blacklist
- = getAdminPasswordBlacklistLocked(admins.get(i));
- if (blacklist != null) {
- if (blacklist.isPasswordBlacklisted(lowerCasePassword)) {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
@Override
public boolean isActivePasswordSufficient(int userHandle, boolean parent) {
if (!mHasFeature) {
@@ -4938,11 +4791,6 @@
return false;
}
}
-
- if (isPasswordBlacklistedInternal(userHandle, password)) {
- Slog.w(LOG_TAG, "resetPassword: the password is blacklisted");
- return false;
- }
}
DevicePolicyData policy = getUserData(userHandle);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java b/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java
deleted file mode 100644
index a17a107..0000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2017 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.devicepolicy;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.AtomicFile;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Manages the blacklisted passwords.
- *
- * This caller must ensure synchronized access.
- */
-public class PasswordBlacklist {
- private static final String TAG = "PasswordBlacklist";
-
- private final AtomicFile mFile;
-
- /**
- * Create an object to manage the password blacklist.
- *
- * This is a lightweight operation to prepare variables but not perform any IO.
- */
- public PasswordBlacklist(File file) {
- mFile = new AtomicFile(file, "device-policy");
- }
-
- /**
- * Atomically replace the blacklist.
- *
- * Pass {@code null} for an empty list.
- */
- public boolean savePasswordBlacklist(@NonNull String name, @NonNull List<String> blacklist) {
- FileOutputStream fos = null;
- try {
- fos = mFile.startWrite();
- final DataOutputStream out = buildStreamForWriting(fos);
- final Header header = new Header(Header.VERSION_1, name, blacklist.size());
- header.write(out);
- final int blacklistSize = blacklist.size();
- for (int i = 0; i < blacklistSize; ++i) {
- out.writeUTF(blacklist.get(i));
- }
- out.flush();
- mFile.finishWrite(fos);
- return true;
- } catch (IOException e) {
- mFile.failWrite(fos);
- return false;
- }
- }
-
- /** @return the name of the blacklist or {@code null} if none set. */
- public String getName() {
- try (DataInputStream in = openForReading()) {
- return Header.read(in).mName;
- } catch (IOException e) {
- Slog.wtf(TAG, "Failed to read blacklist file", e);
- }
- return null;
- }
-
- /** @return the number of blacklisted passwords. */
- public int getSize() {
- final int blacklistSize;
- try (DataInputStream in = openForReading()) {
- return Header.read(in).mSize;
- } catch (IOException e) {
- Slog.wtf(TAG, "Failed to read blacklist file", e);
- }
- return 0;
- }
-
- /** @return whether the password matches an blacklisted item. */
- public boolean isPasswordBlacklisted(@NonNull String password) {
- final int blacklistSize;
- try (DataInputStream in = openForReading()) {
- final Header header = Header.read(in);
- for (int i = 0; i < header.mSize; ++i) {
- if (in.readUTF().equals(password)) {
- return true;
- }
- }
- } catch (IOException e) {
- Slog.wtf(TAG, "Failed to read blacklist file", e);
- // Fail safe and block all passwords. Setting a new blacklist should resolve this
- // problem which can be identified by examining the log.
- return true;
- }
- return false;
- }
-
- /** Delete the blacklist completely from disk. */
- public void delete() {
- mFile.delete();
- }
-
- /** Get the file the blacklist is stored in. */
- public File getFile() {
- return mFile.getBaseFile();
- }
-
- private DataOutputStream buildStreamForWriting(FileOutputStream fos) {
- return new DataOutputStream(new BufferedOutputStream(fos));
- }
-
- private DataInputStream openForReading() throws IOException {
- return new DataInputStream(new BufferedInputStream(mFile.openRead()));
- }
-
- /**
- * Helper to read and write the header of the blacklist file.
- */
- private static class Header {
- static final int VERSION_1 = 1;
-
- final int mVersion; // File format version
- final String mName;
- final int mSize;
-
- Header(int version, String name, int size) {
- mVersion = version;
- mName = name;
- mSize = size;
- }
-
- void write(DataOutputStream out) throws IOException {
- out.writeInt(mVersion);
- out.writeUTF(mName);
- out.writeInt(mSize);
- }
-
- static Header read(DataInputStream in) throws IOException {
- final int version = in.readInt();
- final String name = in.readUTF();
- final int size = in.readInt();
- return new Header(version, name, size);
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 520f318..cd39285 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -98,12 +98,6 @@
this.context = injector.context;
}
- @Override
- public boolean isPasswordBlacklisted(int userId, String password) {
- return false;
- }
-
-
public void notifyChangeToContentObserver(Uri uri, int userHandle) {
ContentObserver co = mMockInjector.mContentObservers.get(new Pair<>(uri, userHandle));
if (co != null) {
@@ -220,11 +214,6 @@
}
@Override
- PasswordBlacklist newPasswordBlacklist(File file) {
- return services.passwordBlacklist;
- }
-
- @Override
boolean storageManagerIsFileBasedEncryptionEnabled() {
return services.storageManager.isFileBasedEncryptionEnabled();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index ccf4a82..b76064b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4192,36 +4192,6 @@
assertTrue(dpm.clearResetPasswordToken(admin1));
}
- public void testSetPasswordBlacklistCannotBeCalledByNonAdmin() throws Exception {
- assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setPasswordBlacklist(admin1, null, null));
- verifyZeroInteractions(getServices().passwordBlacklist);
- }
-
- public void testClearingPasswordBlacklistDoesNotCreateNewBlacklist() throws Exception {
- setupProfileOwner();
- dpm.setPasswordBlacklist(admin1, null, null);
- verifyZeroInteractions(getServices().passwordBlacklist);
- }
-
- public void testSetPasswordBlacklistCreatesNewBlacklist() throws Exception {
- final String name = "myblacklist";
- final List<String> explicit = Arrays.asList("password", "letmein");
- setupProfileOwner();
- dpm.setPasswordBlacklist(admin1, name, explicit);
- verify(getServices().passwordBlacklist).savePasswordBlacklist(name, explicit);
- }
-
- public void testSetPasswordBlacklistOnlyConvertsExplicitToLowerCase() throws Exception {
- final List<String> mixedCase = Arrays.asList("password", "LETMEIN", "FooTBAll");
- final List<String> lowerCase = Arrays.asList("password", "letmein", "football");
- mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
- setupDeviceOwner();
- final String name = "Name of the Blacklist";
- dpm.setPasswordBlacklist(admin1, name, mixedCase);
- verify(getServices().passwordBlacklist).savePasswordBlacklist(name, lowerCase);
- }
-
public void testIsActivePasswordSufficient() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
mContext.packageName = admin1.getPackageName();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 81ed6e2..e753df1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -96,7 +96,6 @@
public final IBackupManager ibackupManager;
public final IAudioService iaudioService;
public final LockPatternUtils lockPatternUtils;
- public final PasswordBlacklist passwordBlacklist;
public final StorageManagerForMock storageManager;
public final WifiManager wifiManager;
public final SettingsForMock settings;
@@ -135,7 +134,6 @@
ibackupManager = mock(IBackupManager.class);
iaudioService = mock(IAudioService.class);
lockPatternUtils = mock(LockPatternUtils.class);
- passwordBlacklist = mock(PasswordBlacklist.class);
storageManager = mock(StorageManagerForMock.class);
wifiManager = mock(WifiManager.class);
settings = mock(SettingsForMock.class);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java
deleted file mode 100644
index 1b3fc2c..0000000
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2017 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.devicepolicy;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for {@link PasswordBlacklist}.
- *
- * bit FrameworksServicesTests:com.android.server.devicepolicy.PasswordBlacklistTest
- * runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java
- */
-@RunWith(AndroidJUnit4.class)
-public final class PasswordBlacklistTest {
- private File mBlacklistFile;
- private PasswordBlacklist mBlacklist;
-
- @Before
- public void setUp() throws IOException {
- mBlacklistFile = File.createTempFile("pwdbl", null);
- mBlacklist = new PasswordBlacklist(mBlacklistFile);
- }
-
- @After
- public void tearDown() {
- mBlacklist.delete();
- }
-
- @Test
- public void matchIsExact() {
- // Note: Case sensitivity is handled by the user of PasswordBlacklist by normalizing the
- // values stored in and tested against it.
- mBlacklist.savePasswordBlacklist("matchIsExact", Arrays.asList("password", "qWERty"));
- assertTrue(mBlacklist.isPasswordBlacklisted("password"));
- assertTrue(mBlacklist.isPasswordBlacklisted("qWERty"));
- assertFalse(mBlacklist.isPasswordBlacklisted("Password"));
- assertFalse(mBlacklist.isPasswordBlacklisted("qwert"));
- assertFalse(mBlacklist.isPasswordBlacklisted("letmein"));
- }
-
- @Test
- public void matchIsNotRegex() {
- mBlacklist.savePasswordBlacklist("matchIsNotRegex", Arrays.asList("a+b*"));
- assertTrue(mBlacklist.isPasswordBlacklisted("a+b*"));
- assertFalse(mBlacklist.isPasswordBlacklisted("aaaa"));
- assertFalse(mBlacklist.isPasswordBlacklisted("abbbb"));
- assertFalse(mBlacklist.isPasswordBlacklisted("aaaa"));
- }
-
- @Test
- public void matchFailsSafe() throws IOException {
- try (FileOutputStream fos = new FileOutputStream(mBlacklistFile)) {
- // Write a malformed blacklist file
- fos.write(17);
- }
- assertTrue(mBlacklist.isPasswordBlacklisted("anything"));
- assertTrue(mBlacklist.isPasswordBlacklisted("at"));
- assertTrue(mBlacklist.isPasswordBlacklisted("ALL"));
- }
-
- @Test
- public void blacklistCanBeNamed() {
- final String name = "identifier";
- mBlacklist.savePasswordBlacklist(name, Arrays.asList("one", "two", "three"));
- assertEquals(mBlacklist.getName(), name);
- }
-
- @Test
- public void reportsTheCorrectNumberOfEntries() {
- mBlacklist.savePasswordBlacklist("Count Entries", Arrays.asList("1", "2", "3", "4"));
- assertEquals(mBlacklist.getSize(), 4);
- }
-
- @Test
- public void reportsBlacklistFile() {
- assertEquals(mBlacklistFile, mBlacklist.getFile());
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a98e291..f4ec867 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -211,24 +211,6 @@
}
@Test
- public void generateAndStoreKey_storesTheKey() throws Exception {
- int uid = Binder.getCallingUid();
- int userId = UserHandle.getCallingUserId();
-
- mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
-
- assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
-
- assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
- }
-
- @Test
- public void generateAndStoreKey_returnsAKeyOfAppropriateSize() throws Exception {
- assertThat(mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS))
- .hasLength(RECOVERABLE_KEY_SIZE_BYTES);
- }
-
- @Test
public void importKey_storesTheKey() throws Exception {
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
@@ -265,7 +247,7 @@
@Test
public void removeKey_removesAKey() throws Exception {
int uid = Binder.getCallingUid();
- mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
+ mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
mRecoverableKeyStoreManager.removeKey(TEST_ALIAS);
@@ -276,7 +258,7 @@
public void removeKey_updatesShouldCreateSnapshot() throws Exception {
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
- mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
+ mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
// Pretend that key was synced
mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
@@ -1056,7 +1038,7 @@
int userId = UserHandle.getCallingUserId();
mRecoverableKeyStoreManager.setRecoverySecretTypes(new int[] { 1 });
- mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
+ mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
// Pretend that key was synced
mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
mRecoverableKeyStoreManager.setRecoverySecretTypes(new int[] { 2 });
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 36136a8..ce74457 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -206,6 +206,31 @@
}
@Test
+ public void testShouldExitForAlarm_oldAlarm() {
+ // Cal: today 2:15pm
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 14);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ // ScheduleInfo: today 12:16pm - today 3:15pm
+ mScheduleInfo.days = new int[] {getTodayDay()};
+ mScheduleInfo.startHour = 12;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.startMinute = 16;
+ mScheduleInfo.endMinute = 15;
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 1000; // very old alarm
+
+ mScheduleCalendar.setSchedule(mScheduleInfo);
+ assertTrue(mScheduleCalendar.isInSchedule(cal.getTimeInMillis()));
+
+ // don't exit for an alarm if it's an old alarm
+ assertFalse(mScheduleCalendar.shouldExitForAlarm(1000));
+ }
+
+ @Test
public void testMaybeSetNextAlarm_settingOff() {
mScheduleInfo.exitAtAlarm = false;
mScheduleInfo.nextAlarm = 0;
diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java
index 92ebf36..dbad02f 100644
--- a/telephony/java/android/telephony/NetworkServiceCallback.java
+++ b/telephony/java/android/telephony/NetworkServiceCallback.java
@@ -83,6 +83,8 @@
} catch (RemoteException e) {
Rlog.e(mTag, "Failed to onGetNetworkRegistrationStateComplete on the remote");
}
+ } else {
+ Rlog.e(mTag, "Weak reference of callback is null.");
}
}
}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
index 6d72181..2831127 100644
--- a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
+++ b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
@@ -29,27 +29,47 @@
public final class ImsCallForwardInfo implements Parcelable {
// Refer to ImsUtInterface#CDIV_CF_XXX
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter.
public int mCondition;
// 0: disabled, 1: enabled
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter.
public int mStatus;
// 0x91: International, 0x81: Unknown
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter.
public int mToA;
// Service class
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter.
public int mServiceClass;
// Number (it will not include the "sip" or "tel" URI scheme)
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter.
public String mNumber;
// No reply timer for CF
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter.
public int mTimeSeconds;
/** @hide */
+ // TODO: Will be removed in the future, use public constructor instead.
public ImsCallForwardInfo() {
}
+ /**
+ * IMS Call Forward Information.
+ */
+ public ImsCallForwardInfo(int condition, int status, int toA, int serviceClass, String number,
+ int replyTimerSec) {
+ mCondition = condition;
+ mStatus = status;
+ mToA = toA;
+ mServiceClass = serviceClass;
+ mNumber = number;
+ mTimeSeconds = replyTimerSec;
+ }
+
/** @hide */
public ImsCallForwardInfo(Parcel in) {
readFromParcel(in);
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index 1ddf199..49ead77 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -15,19 +15,24 @@
*/
package android.telephony.ims;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
- * Provided STK Call Control Suplementary Service information
+ * Provides STK Call Control Supplementary Service information.
*
* {@hide}
*/
@SystemApi
public final class ImsSsData implements Parcelable {
- //ServiceType
+ // Supplementary Service Type
+ // Call Forwarding
public static final int SS_CFU = 0;
public static final int SS_CF_BUSY = 1;
public static final int SS_CF_NO_REPLY = 2;
@@ -35,12 +40,16 @@
public static final int SS_CF_ALL = 4;
public static final int SS_CF_ALL_CONDITIONAL = 5;
public static final int SS_CFUT = 6;
+ // Called Line Presentation
public static final int SS_CLIP = 7;
public static final int SS_CLIR = 8;
public static final int SS_COLP = 9;
public static final int SS_COLR = 10;
+ // Calling Name Presentation
public static final int SS_CNAP = 11;
+ // Call Waiting
public static final int SS_WAIT = 12;
+ // Call Barring
public static final int SS_BAOC = 13;
public static final int SS_BAOIC = 14;
public static final int SS_BAOIC_EXC_HOME = 15;
@@ -52,14 +61,14 @@
public static final int SS_INCOMING_BARRING_DN = 21;
public static final int SS_INCOMING_BARRING_ANONYMOUS = 22;
- //SSRequestType
+ //Supplementary Service Request Types
public static final int SS_ACTIVATION = 0;
public static final int SS_DEACTIVATION = 1;
public static final int SS_INTERROGATION = 2;
public static final int SS_REGISTRATION = 3;
public static final int SS_ERASURE = 4;
- //TeleserviceType
+ // Supplementary Service Teleservice Type
public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0;
public static final int SS_ALL_TELESEVICES = 1;
public static final int SS_TELEPHONY = 2;
@@ -67,40 +76,226 @@
public static final int SS_SMS_SERVICES = 4;
public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5;
- // Refer to ServiceType
+ // Service Class of Supplementary Service
+ // See 27.007 +CCFC or +CLCK
/** @hide */
+ public static final int SERVICE_CLASS_NONE = 0; // no user input
+ /** @hide */
+ public static final int SERVICE_CLASS_VOICE = 1;
+ /** @hide */
+ public static final int SERVICE_CLASS_DATA = (1 << 1);
+ /** @hide */
+ public static final int SERVICE_CLASS_FAX = (1 << 2);
+ /** @hide */
+ public static final int SERVICE_CLASS_SMS = (1 << 3);
+ /** @hide */
+ public static final int SERVICE_CLASS_DATA_SYNC = (1 << 4);
+ /** @hide */
+ public static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5);
+ /** @hide */
+ public static final int SERVICE_CLASS_PACKET = (1 << 6);
+ /** @hide */
+ public static final int SERVICE_CLASS_PAD = (1 << 7);
+
+ /**
+ * Result code used if the operation was successful. See {@link #result}.
+ * @hide
+ */
+ public static final int RESULT_SUCCESS = 0;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "SS_" }, value = {
+ SS_CFU,
+ SS_CF_BUSY,
+ SS_CF_NO_REPLY,
+ SS_CF_NOT_REACHABLE,
+ SS_CF_ALL,
+ SS_CF_ALL_CONDITIONAL,
+ SS_CFUT,
+ SS_CLIP,
+ SS_CLIR,
+ SS_COLP,
+ SS_COLR,
+ SS_CNAP,
+ SS_WAIT,
+ SS_BAOC,
+ SS_BAOIC,
+ SS_BAOIC_EXC_HOME,
+ SS_BAIC,
+ SS_BAIC_ROAMING,
+ SS_ALL_BARRING,
+ SS_OUTGOING_BARRING,
+ SS_INCOMING_BARRING,
+ SS_INCOMING_BARRING_DN,
+ SS_INCOMING_BARRING_ANONYMOUS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ServiceType{}
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "SERVICE_CLASS" }, value = {
+ SERVICE_CLASS_NONE,
+ SERVICE_CLASS_VOICE,
+ SERVICE_CLASS_DATA,
+ SERVICE_CLASS_FAX,
+ SERVICE_CLASS_SMS,
+ SERVICE_CLASS_DATA_SYNC,
+ SERVICE_CLASS_DATA_ASYNC,
+ SERVICE_CLASS_PACKET,
+ SERVICE_CLASS_PAD
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ServiceClass{}
+
+ /**
+ * The Service type of this Supplementary service. Valid values include:
+ * SS_CFU,
+ * SS_CF_BUSY,
+ * SS_CF_NO_REPLY,
+ * SS_CF_NOT_REACHABLE,
+ * SS_CF_ALL,
+ * SS_CF_ALL_CONDITIONAL,
+ * SS_CFUT,
+ * SS_CLIP,
+ * SS_CLIR,
+ * SS_COLP,
+ * SS_COLR,
+ * SS_CNAP,
+ * SS_WAIT,
+ * SS_BAOC,
+ * SS_BAOIC,
+ * SS_BAOIC_EXC_HOME,
+ * SS_BAIC,
+ * SS_BAIC_ROAMING,
+ * SS_ALL_BARRING,
+ * SS_OUTGOING_BARRING,
+ * SS_INCOMING_BARRING,
+ * SS_INCOMING_BARRING_DN,
+ * SS_INCOMING_BARRING_ANONYMOUS
+ *
+ * @hide
+ */
+ // TODO: Make final, do not modify this field directly!
public int serviceType;
- // Refere to SSRequestType
- /** @hide */
+
+ /**
+ * Supplementary Service request Type. Valid values are:
+ * SS_ACTIVATION,
+ * SS_DEACTIVATION,
+ * SS_INTERROGATION,
+ * SS_REGISTRATION,
+ * SS_ERASURE
+ *
+ * @hide
+ */
+ // TODO: Make final, do not modify this field directly!
public int requestType;
- // Refer to TeleserviceType
- /** @hide */
+
+ /**
+ * Supplementary Service teleservice type:
+ * SS_TELESERVICE_ALL_TELE_AND_BEARER,
+ * SS_TELESERVICE_ALL_TELESEVICES,
+ * SS_TELESERVICE_TELEPHONY,
+ * SS_TELESERVICE_ALL_DATA,
+ * SS_TELESERVICE_SMS,
+ * SS_TELESERVICE_ALL_TELESERVICES_EXCEPT_SMS
+ *
+ * @hide
+ */
+ // TODO: Make this param final! Do not try to modify this param directly.
public int teleserviceType;
- // Service Class
- /** @hide */
+
+ /**
+ * Supplementary Service service class. Valid values are:
+ * SERVICE_CLASS_NONE,
+ * SERVICE_CLASS_VOICE,
+ * SERVICE_CLASS_DATA,
+ * SERVICE_CLASS_FAX,
+ * SERVICE_CLASS_SMS,
+ * SERVICE_CLASS_DATA_SYNC,
+ * SERVICE_CLASS_DATA_ASYNC,
+ * SERVICE_CLASS_PACKET,
+ * SERVICE_CLASS_PAD
+ *
+ * @hide
+ */
+ // TODO: Make this param final! Do not try to modify this param directly.
public int serviceClass;
- // Error information
- /** @hide */
- public int result;
- /** @hide */
- public int[] ssInfo; /* Valid for all supplementary services.
- This field will be empty for RequestType SS_INTERROGATION
- and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
- SS_INCOMING_BARRING_ANONYMOUS.*/
+ /**
+ * Result of Supplementary Service operation. Valid values are:
+ * RESULT_SUCCESS if the result is success, or
+ * ImsReasonInfo code if the result is a failure.
+ *
+ * @hide
+ */
+ // TODO: Make this param final! Do not try to modify this param directly.
+ public final int result;
- /** @hide */
- public ImsCallForwardInfo[] cfInfo; /* Valid only for supplementary services
- ServiceType SS_CF_* and RequestType SS_INTERROGATION */
+ private int[] mSsInfo;
+ private ImsCallForwardInfo[] mCfInfo;
+ private ImsSsInfo[] mImsSsInfo;
- /** @hide */
- public ImsSsInfo[] imsSsInfo; /* Valid only for ServiceType SS_INCOMING_BARRING_DN and
- ServiceType SS_INCOMING_BARRING_ANONYMOUS */
-
- public ImsSsData() {}
+ /**
+ * Generate IMS Supplementary Service information.
+ * @param serviceType The Supplementary Service type. Valid entries:
+ * SS_CFU,
+ * SS_CF_BUSY,
+ * SS_CF_NO_REPLY,
+ * SS_CF_NOT_REACHABLE,
+ * SS_CF_ALL,
+ * SS_CF_ALL_CONDITIONAL,
+ * SS_CFUT,
+ * SS_CLIP,
+ * SS_CLIR,
+ * SS_COLP,
+ * SS_COLR,
+ * SS_CNAP,
+ * SS_WAIT,
+ * SS_BAOC,
+ * SS_BAOIC,
+ * SS_BAOIC_EXC_HOME,
+ * SS_BAIC,
+ * SS_BAIC_ROAMING,
+ * SS_ALL_BARRING,
+ * SS_OUTGOING_BARRING,
+ * SS_INCOMING_BARRING,
+ * SS_INCOMING_BARRING_DN,
+ * SS_INCOMING_BARRING_ANONYMOUS
+ * @param requestType Supplementary Service request Type. Valid values are:
+ * SS_ACTIVATION,
+ * SS_DEACTIVATION,
+ * SS_INTERROGATION,
+ * SS_REGISTRATION,
+ * SS_ERASURE
+ * @param teleserviceType Supplementary Service teleservice type:
+ * SS_TELESERVICE_ALL_TELE_AND_BEARER,
+ * SS_TELESERVICE_ALL_TELESEVICES,
+ * SS_TELESERVICE_TELEPHONY,
+ * SS_TELESERVICE_ALL_DATA,
+ * SS_TELESERVICE_SMS,
+ * SS_TELESERVICE_ALL_TELESERVICES_EXCEPT_SMS
+ * @param serviceClass Supplementary Service service class. See See 27.007 +CCFC or +CLCK.
+ * @param result Result of Supplementary Service operation. Valid values are 0 if the result is
+ * success, or ImsReasonInfo code if the result is a failure.
+ */
+ public ImsSsData(@ServiceType int serviceType, int requestType, int teleserviceType,
+ @ServiceClass int serviceClass, int result) {
+ this.serviceType = serviceType;
+ this.requestType = requestType;
+ this.teleserviceType = teleserviceType;
+ this.serviceClass = serviceClass;
+ this.result = result;
+ }
private ImsSsData(Parcel in) {
- readFromParcel(in);
+ serviceType = in.readInt();
+ requestType = in.readInt();
+ teleserviceType = in.readInt();
+ serviceClass = in.readInt();
+ result = in.readInt();
+ mSsInfo = in.createIntArray();
+ mCfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
}
public static final Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() {
@@ -122,18 +317,8 @@
out.writeInt(teleserviceType);
out.writeInt(serviceClass);
out.writeInt(result);
- out.writeIntArray(ssInfo);
- out.writeParcelableArray(cfInfo, 0);
- }
-
- private void readFromParcel(Parcel in) {
- serviceType = in.readInt();
- requestType = in.readInt();
- teleserviceType = in.readInt();
- serviceClass = in.readInt();
- result = in.readInt();
- ssInfo = in.createIntArray();
- cfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
+ out.writeIntArray(mSsInfo);
+ out.writeParcelableArray(mCfInfo, 0);
}
@Override
@@ -200,7 +385,55 @@
}
public boolean isTypeInterrogation() {
- return (requestType == SS_INTERROGATION);
+ return (serviceType == SS_INTERROGATION);
+ }
+
+ /** @hide */
+ public void setSuppServiceInfo(int[] ssInfo) {
+ mSsInfo = ssInfo;
+ }
+
+ /** @hide */
+ public void setImsSpecificSuppServiceInfo(ImsSsInfo[] imsSsInfo) {
+ mImsSsInfo = imsSsInfo;
+ }
+
+ /** @hide */
+ public void setCallForwardingInfo(ImsCallForwardInfo[] cfInfo) {
+ mCfInfo = cfInfo;
+ }
+
+ /**
+ * This field will be null for RequestType SS_INTERROGATION
+ * and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
+ * SS_INCOMING_BARRING_ANONYMOUS.
+ *
+ * @hide
+ */
+ public int[] getSuppServiceInfo() {
+ return mSsInfo;
+ }
+
+ /**
+ * Valid only for ServiceTypes
+ * - SS_INCOMING_BARRING_DN and
+ * - ServiceType SS_INCOMING_BARRING_ANONYMOUS.
+ * Will be null otherwise.
+ * @hide
+ */
+ public ImsSsInfo[] getImsSpecificSuppServiceInfo() {
+ return mImsSsInfo;
+ }
+
+ /**
+ * Valid only for supplementary services
+ * - ServiceType SS_CF_* and
+ * - RequestType SS_INTERROGATION.
+ * Will be null otherwise.
+ * @hide
+ **/
+ public ImsCallForwardInfo[] getCallForwardInfo() {
+ return mCfInfo;
}
public String toString() {
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index 1d1292f..c6f8622 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -36,13 +36,31 @@
// 0: disabled, 1: enabled
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter!
public int mStatus;
/** @hide */
+ // TODO: Make private, do not modify this field directly, use getter!
public String mIcbNum;
+ /**@hide*/
+ // TODO: Remove! Do not use this constructor, instead use public version.
public ImsSsInfo() {
}
+ /**
+ *
+ * @param status The status of the service registration of activation/deactiviation. Valid
+ * entries include:
+ * {@link #NOT_REGISTERED},
+ * {@link #DISABLED},
+ * {@link #ENABLED}
+ * @param icbNum The Incoming barring number.
+ */
+ public ImsSsInfo(int status, String icbNum) {
+ mStatus = status;
+ mIcbNum = icbNum;
+ }
+
private ImsSsInfo(Parcel in) {
readFromParcel(in);
}
@@ -81,6 +99,12 @@
}
};
+ /**
+ * @return Supplementary Service Configuration status. Valid Values are:
+ * {@link #NOT_REGISTERED},
+ * {@link #DISABLED},
+ * {@link #ENABLED}
+ */
public int getStatus() {
return mStatus;
}
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
index 3734412..e247951 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -173,7 +173,7 @@
private static String getCompilerFilter(String pkg) throws IOException {
String cmd = String.format("dumpsys package %s", pkg);
String[] lines = runShellCommandSplitLines(cmd);
- final String substr = "compilation_filter=";
+ final String substr = "[status=";
for (String line : lines) {
int startIndex = line.indexOf(substr);
if (startIndex < 0) {
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
index 6bdfdc6..85e8361 100644
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -22,8 +22,12 @@
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+
+import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
+import java.util.Map.Entry;
import java.util.Random;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,19 +44,29 @@
};
@Test
- public void testDefaultTruncLen() throws Exception {
- IpSecAlgorithm explicit =
+ public void testNoTruncLen() throws Exception {
+ Entry<String, Integer>[] authAndAeadList =
+ new Entry[] {
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_MD5, 128),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA1, 160),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224)
+ };
+
+ // Expect auth and aead algorithms to throw errors if trunclen is omitted.
+ for (Entry<String, Integer> algData : authAndAeadList) {
+ try {
new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256, Arrays.copyOf(KEY_MATERIAL, 256 / 8), 256);
- IpSecAlgorithm implicit =
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
- assertTrue(
- "Default Truncation Length Incorrect, Explicit: "
- + explicit
- + "implicit: "
- + implicit,
- IpSecAlgorithm.equals(explicit, implicit));
+ algData.getKey(), Arrays.copyOf(KEY_MATERIAL, algData.getValue() / 8));
+ fail("Expected exception on unprovided auth trunclen");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ // Ensure crypt works with no truncation length supplied.
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
}
@Test
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index f186ee5..771faaf 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -62,7 +62,8 @@
c.setAuthentication(
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
- new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
+ new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0},
+ 128));
c.setAuthenticatedEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 0ca20de..970596d 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -179,7 +179,7 @@
IpSecManager.UdpEncapsulationSocket encapSocket =
mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT);
- assertNotNull(encapSocket.getSocket());
+ assertNotNull(encapSocket.getFileDescriptor());
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
encapSocket.close();
@@ -202,7 +202,7 @@
IpSecManager.UdpEncapsulationSocket encapSocket =
mIpSecManager.openUdpEncapsulationSocket();
- assertNotNull(encapSocket.getSocket());
+ assertNotNull(encapSocket.getFileDescriptor());
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
encapSocket.close();