Merge "Expose network scoring APIs to /system apps." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index b2689bb..87ea82e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7191,6 +7191,7 @@
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String TELECOMM_SERVICE = "telecomm";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
@@ -15115,6 +15116,7 @@
field public static final int AMR_WB = 2; // 0x2
field public static final int DEFAULT = 0; // 0x0
field public static final int HE_AAC = 4; // 0x4
+ field public static final int VORBIS = 6; // 0x6
}
public final class MediaRecorder.AudioSource {
@@ -15145,6 +15147,7 @@
field public static final int MPEG_4 = 2; // 0x2
field public static final deprecated int RAW_AMR = 3; // 0x3
field public static final int THREE_GPP = 1; // 0x1
+ field public static final int WEBM = 9; // 0x9
}
public final class MediaRecorder.VideoEncoder {
@@ -15152,6 +15155,7 @@
field public static final int H263 = 1; // 0x1
field public static final int H264 = 2; // 0x2
field public static final int MPEG_4_SP = 3; // 0x3
+ field public static final int VP8 = 4; // 0x4
}
public final class MediaRecorder.VideoSource {
@@ -25393,9 +25397,11 @@
}
public static abstract interface Telephony.BaseMmsColumns implements android.provider.BaseColumns {
+ field public static final java.lang.String ARCHIVED = "archived";
field public static final java.lang.String CONTENT_CLASS = "ct_cls";
field public static final java.lang.String CONTENT_LOCATION = "ct_l";
field public static final java.lang.String CONTENT_TYPE = "ct_t";
+ field public static final java.lang.String CREATOR = "creator";
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DATE_SENT = "date_sent";
field public static final java.lang.String DELIVERY_REPORT = "d_rpt";
@@ -25618,7 +25624,9 @@
public static abstract interface Telephony.TextBasedSmsColumns {
field public static final java.lang.String ADDRESS = "address";
+ field public static final java.lang.String ARCHIVED = "archived";
field public static final java.lang.String BODY = "body";
+ field public static final java.lang.String CREATOR = "creator";
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DATE_SENT = "date_sent";
field public static final java.lang.String ERROR_CODE = "error_code";
@@ -28425,6 +28433,14 @@
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.intent.extra.START_CALL_WITH_VIDEO_STATE";
}
+ public class TelecommManager {
+ method public void clearAccounts(java.lang.String);
+ method public java.util.List<android.telecomm.PhoneAccount> getEnabledPhoneAccounts();
+ method public android.telecomm.PhoneAccountMetadata getPhoneAccountMetadata(android.telecomm.PhoneAccount);
+ method public void registerPhoneAccount(android.telecomm.PhoneAccount, android.telecomm.PhoneAccountMetadata);
+ method public void unregisterPhoneAccount(android.telecomm.PhoneAccount);
+ }
+
public class VideoCallProfile implements android.os.Parcelable {
ctor public VideoCallProfile(int, int);
method public int describeContents();
@@ -28642,6 +28658,44 @@
field public static final int VOICEMAIL_NUMBER_MISSING = 40; // 0x28
}
+ public class MessagingConfigurationManager {
+ method public boolean getCarrierConfigBoolean(java.lang.String, boolean);
+ method public int getCarrierConfigInt(java.lang.String, int);
+ method public java.lang.String getCarrierConfigString(java.lang.String, java.lang.String);
+ method public static android.telephony.MessagingConfigurationManager getDefault();
+ method public void setCarrierConfigBoolean(java.lang.String, boolean);
+ method public void setCarrierConfigInt(java.lang.String, int);
+ method public void setCarrierConfigString(java.lang.String, java.lang.String);
+ field public static final java.lang.String CONF_ALIAS_ENABLED = "aliasEnabled";
+ field public static final java.lang.String CONF_ALIAS_MAX_CHARS = "aliasMaxChars";
+ field public static final java.lang.String CONF_ALIAS_MIN_CHARS = "aliasMinChars";
+ field public static final java.lang.String CONF_ALLOW_ATTACH_AUDIO = "allowAttachAudio";
+ field public static final java.lang.String CONF_APPEND_TRANSACTION_ID = "enabledTransID";
+ field public static final java.lang.String CONF_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber";
+ field public static final java.lang.String CONF_HTTP_PARAMS = "httpParams";
+ field public static final java.lang.String CONF_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout";
+ field public static final java.lang.String CONF_MAX_IMAGE_HEIGHT = "maxImageHeight";
+ field public static final java.lang.String CONF_MAX_IMAGE_WIDTH = "maxImageWidth";
+ field public static final java.lang.String CONF_MAX_MESSAGE_SIZE = "maxMessageSize";
+ field public static final java.lang.String CONF_MESSAGE_TEXT_MAX_SIZE = "maxMessageTextSize";
+ field public static final java.lang.String CONF_MMS_DELIVERY_REPORT_ENABLED = "enableMMSDeliveryReports";
+ field public static final java.lang.String CONF_MMS_ENABLED = "enabledMMS";
+ field public static final java.lang.String CONF_MMS_READ_REPORT_ENABLED = "enableMMSReadReports";
+ field public static final java.lang.String CONF_MULTIPART_SMS_ENABLED = "enableMultipartSMS";
+ field public static final java.lang.String CONF_NAI_SUFFIX = "naiSuffix";
+ field public static final java.lang.String CONF_NOTIFY_WAP_MMSC_ENABLED = "enabledNotifyWapMMSC";
+ field public static final java.lang.String CONF_RECIPIENT_LIMIT = "recipientLimit";
+ field public static final java.lang.String CONF_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = "sendMultipartSmsAsSeparateMessages";
+ field public static final java.lang.String CONF_SMS_DELIVERY_REPORT_ENABLED = "enableSMSDeliveryReports";
+ field public static final java.lang.String CONF_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = "smsToMmsTextLengthThreshold";
+ field public static final java.lang.String CONF_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
+ field public static final java.lang.String CONF_SUBJECT_MAX_LENGTH = "maxSubjectLength";
+ field public static final java.lang.String CONF_SUPPORT_MMS_CONTENT_DISPOSITION = "supportMmsContentDisposition";
+ field public static final java.lang.String CONF_UA_PROF_TAG_NAME = "uaProfTagName";
+ field public static final java.lang.String CONF_UA_PROF_URL = "uaProfUrl";
+ field public static final java.lang.String CONF_USER_AGENT = "userAgent";
+ }
+
public class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
@@ -28784,19 +28838,43 @@
}
public final class SmsManager {
+ method public android.net.Uri addMultimediaMessageDraft(byte[]);
+ method public android.net.Uri addTextMessageDraft(java.lang.String, java.lang.String);
+ method public boolean deleteStoredConversation(long);
+ method public boolean deleteStoredMessage(android.net.Uri);
method public java.util.ArrayList<java.lang.String> divideMessage(java.lang.String);
+ method public void downloadMultimediaMessage(java.lang.String, android.app.PendingIntent);
+ method public boolean getAutoPersisting();
method public static android.telephony.SmsManager getDefault();
+ method public android.net.Uri importMultimediaMessage(byte[], java.lang.String, long, boolean, boolean);
+ method public android.net.Uri importTextMessage(java.lang.String, int, java.lang.String, long, boolean, boolean);
method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent);
method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendMultimediaMessage(byte[], java.lang.String, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+ method public void sendStoredMultimediaMessage(android.net.Uri, android.app.PendingIntent);
+ method public void sendStoredMultipartTextMessage(android.net.Uri, java.lang.String, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+ method public void sendStoredTextMessage(android.net.Uri, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void setAutoPersisting(boolean);
method public void updateMmsDownloadStatus(int, byte[]);
method public void updateMmsSendStatus(int, boolean);
method public void updateSmsSendStatus(int, boolean);
+ method public boolean updateStoredMessageStatus(android.net.Uri, android.content.ContentValues);
+ field public static final java.lang.String MESSAGE_STATUS_ARCHIVED = "archived";
+ field public static final java.lang.String MESSAGE_STATUS_READ = "read";
+ field public static final java.lang.String MESSAGE_STATUS_SEEN = "seen";
+ field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4
+ field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2
+ field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3
+ field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1
+ field public static final java.lang.String MMS_EXTRA_DATA = "data";
field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
field public static final int RESULT_ERROR_RADIO_OFF = 2; // 0x2
+ field public static final int SMS_TYPE_INCOMING = 0; // 0x0
+ field public static final int SMS_TYPE_OUTGOING = 1; // 0x1
field public static final int STATUS_ON_ICC_FREE = 0; // 0x0
field public static final int STATUS_ON_ICC_READ = 1; // 0x1
field public static final int STATUS_ON_ICC_SENT = 5; // 0x5
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b7f1ff9..d6c17ae 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -998,8 +998,8 @@
final InstallSessionParams params = new InstallSessionParams();
params.installFlags = PackageManager.INSTALL_ALL_USERS;
- params.mode = InstallSessionParams.MODE_FULL_INSTALL;
- params.progressMax = -1;
+ params.setModeFullInstall();
+ params.setProgressMax(-1);
String opt;
while ((opt = nextOption()) != null) {
@@ -1021,10 +1021,11 @@
} else if (opt.equals("-d")) {
params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
} else if (opt.equals("-p")) {
- params.mode = InstallSessionParams.MODE_INHERIT_EXISTING;
+ params.setModeInheritExisting();
} else if (opt.equals("-S")) {
- params.deltaSize = Long.parseLong(nextOptionData());
- params.progressMax = (int) params.deltaSize;
+ final long deltaSize = Long.parseLong(nextOptionData());
+ params.setDeltaSize(deltaSize);
+ params.setProgressMax((int) params.deltaSize);
} else if (opt.equals("--abi")) {
params.abiOverride = checkAbiArgument(nextOptionData());
} else {
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 377b5a05..2d87e13 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -57,6 +57,11 @@
return newSet;
}
+ @Override
+ void invalidateCache() {
+ firstTime = true;
+ }
+
public float getFloatValue(float fraction) {
if (mNumKeyframes == 2) {
if (firstTime) {
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 7b7c876..ce47e2b 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -57,6 +57,11 @@
return newSet;
}
+ @Override
+ void invalidateCache() {
+ firstTime = true;
+ }
+
public int getIntValue(float fraction) {
if (mNumKeyframes == 2) {
if (firstTime) {
diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java
index dc8538f..5483c49 100644
--- a/core/java/android/animation/Keyframe.java
+++ b/core/java/android/animation/Keyframe.java
@@ -35,6 +35,20 @@
*/
public abstract class Keyframe implements Cloneable {
/**
+ * Flag to indicate whether this keyframe has a valid value. This flag is used when an
+ * animation first starts, to populate placeholder keyframes with real values derived
+ * from the target object.
+ */
+ boolean mHasValue;
+
+ /**
+ * Flag to indicate whether the value in the keyframe was read from the target object or not.
+ * If so, its value will be recalculated if target changes.
+ */
+ boolean mValueWasSetOnStart;
+
+
+ /**
* The time at which mValue will hold true.
*/
float mFraction;
@@ -51,12 +65,7 @@
*/
private TimeInterpolator mInterpolator = null;
- /**
- * Flag to indicate whether this keyframe has a valid value. This flag is used when an
- * animation first starts, to populate placeholder keyframes with real values derived
- * from the target object.
- */
- boolean mHasValue = false;
+
/**
* Constructs a Keyframe object with the given time and value. The time defines the
@@ -166,6 +175,20 @@
}
/**
+ * If the Keyframe's value was acquired from the target object, this flag should be set so that,
+ * if target changes, value will be reset.
+ *
+ * @return boolean Whether this Keyframe's value was retieved from the target object or not.
+ */
+ boolean valueWasSetOnStart() {
+ return mValueWasSetOnStart;
+ }
+
+ void setValueWasSetOnStart(boolean valueWasSetOnStart) {
+ mValueWasSetOnStart = valueWasSetOnStart;
+ }
+
+ /**
* Gets the value for this Keyframe.
*
* @return The value for this Keyframe.
@@ -261,7 +284,8 @@
@Override
public ObjectKeyframe clone() {
- ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mHasValue ? mValue : null);
+ ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), hasValue() ? mValue : null);
+ kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
kfClone.setInterpolator(getInterpolator());
return kfClone;
}
@@ -310,6 +334,7 @@
new IntKeyframe(getFraction(), mValue) :
new IntKeyframe(getFraction());
kfClone.setInterpolator(getInterpolator());
+ kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
return kfClone;
}
}
@@ -356,6 +381,7 @@
new FloatKeyframe(getFraction(), mValue) :
new FloatKeyframe(getFraction());
kfClone.setInterpolator(getInterpolator());
+ kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
return kfClone;
}
}
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 4026f7f..a3db3a1 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -48,6 +48,13 @@
mInterpolator = mLastKeyframe.getInterpolator();
}
+ /**
+ * If subclass has variables that it calculates based on the Keyframes, it should reset them
+ * when this method is called because Keyframe contents might have changed.
+ */
+ void invalidateCache() {
+ }
+
public static KeyframeSet ofInt(int... values) {
int numKeyframes = values.length;
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index da56a77..a4ac73f 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -883,10 +883,7 @@
final Object oldTarget = getTarget();
if (oldTarget != target) {
mTarget = target == null ? null : new WeakReference<Object>(target);
- if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
- return;
- }
- // New target type should cause re-initialization prior to starting
+ // New target should cause re-initialization prior to starting
mInitialized = false;
}
}
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index bdfbde1..73b83ef 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -775,16 +775,18 @@
* @param target The object on which the setter (and possibly getter) exist.
*/
void setupSetterAndGetter(Object target) {
+ mKeyframeSet.invalidateCache();
if (mProperty != null) {
// check to make sure that mProperty is on the class of target
try {
Object testValue = null;
for (Keyframe kf : mKeyframeSet.mKeyframes) {
- if (!kf.hasValue()) {
+ if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (testValue == null) {
testValue = convertBack(mProperty.get(target));
}
kf.setValue(testValue);
+ kf.setValueWasSetOnStart(true);
}
}
return;
@@ -799,7 +801,7 @@
setupSetter(targetClass);
}
for (Keyframe kf : mKeyframeSet.mKeyframes) {
- if (!kf.hasValue()) {
+ if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (mGetter == null) {
setupGetter(targetClass);
if (mGetter == null) {
@@ -810,6 +812,7 @@
try {
Object value = convertBack(mGetter.invoke(target));
kf.setValue(value);
+ kf.setValueWasSetOnStart(true);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
index 810f050..7256a06 100644
--- a/core/java/android/animation/StateListAnimator.java
+++ b/core/java/android/animation/StateListAnimator.java
@@ -57,6 +57,7 @@
private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ animation.setTarget(null);
if (mRunningAnimator == animation) {
mRunningAnimator = null;
}
@@ -151,7 +152,7 @@
private void start(Tuple match) {
match.mAnimator.setTarget(getTarget());
- mRunningAnimator = match.mAnimator.clone();
+ mRunningAnimator = match.mAnimator;
mRunningAnimator.start();
}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index ba2930b..28108a0 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -331,6 +331,10 @@
* its datastore, if appropriate, and close the socket that had been provided in
* {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}.
*
+ * <p class="note">If the transport returns TRANSPORT_OK from this method, then the
+ * OS will always provide a matching call to {@link #finishBackup()} even if sending
+ * data via {@link #sendBackupData(int)} failed at some point.
+ *
* @param targetPackage The package whose data is to follow.
* @param socket The socket file descriptor through which the data will be provided.
* If the transport returns {@link #TRANSPORT_PACKAGE_REJECTED} here, it must still
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d068b1f..1569b9f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2539,7 +2539,6 @@
*
* @see #getSystemService
* @see android.telecomm.TelecommManager
- * @hide
*/
public static final String TELECOMM_SERVICE = "telecomm";
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f2f363a..8c9b819 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -327,6 +327,12 @@
}
/**
+ * Indicates that the content drawn by HardwareDrawCallbacks needs to
+ * be updated, which will be done by the next call to draw()
+ */
+ abstract void invalidateRoot();
+
+ /**
* Draws the specified view.
*
* @param view The view to draw.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e2ebf6e..b033780 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -96,6 +96,7 @@
private RenderNode mRootNode;
private Choreographer mChoreographer;
private boolean mProfilingEnabled;
+ private boolean mRootNodeNeedsUpdate;
ThreadedRenderer(Context context, boolean translucent) {
final TypedArray a = context.obtainStyledAttributes(
@@ -255,30 +256,41 @@
return changed;
}
- private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
+ private void updateViewTreeDisplayList(View view) {
view.mPrivateFlags |= View.PFLAG_DRAWN;
-
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
- HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
- try {
- canvas.save();
- canvas.translate(mInsetLeft, mInsetTop);
- callbacks.onHardwarePreDraw(canvas);
- canvas.drawRenderNode(view.getDisplayList());
- callbacks.onHardwarePostDraw(canvas);
- canvas.restore();
- } finally {
- mRootNode.end(canvas);
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
-
+ view.getDisplayList();
view.mRecreateDisplayList = false;
}
+ private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+ updateViewTreeDisplayList(view);
+
+ if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
+ HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
+ try {
+ canvas.save();
+ canvas.translate(mInsetLeft, mInsetTop);
+ callbacks.onHardwarePreDraw(canvas);
+ canvas.drawRenderNode(view.getDisplayList());
+ callbacks.onHardwarePostDraw(canvas);
+ canvas.restore();
+ mRootNodeNeedsUpdate = false;
+ } finally {
+ mRootNode.end(canvas);
+ }
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
+ @Override
+ void invalidateRoot() {
+ mRootNodeNeedsUpdate = true;
+ }
+
@Override
void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
attachInfo.mIgnoreDirtyState = true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b554548..f3ad988 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -463,8 +463,13 @@
// Compute surface insets required to draw at specified Z value.
// TODO: Use real shadow insets for a constant max Z.
- final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
- attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+ if (view.isHardwareAccelerated()) {
+ final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+ attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+ } else {
+ // Software accelerated windows can't use insets.
+ attrs.surfaceInsets.setEmpty();
+ }
CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
mTranslator = compatibilityInfo.getTranslator();
@@ -2375,8 +2380,6 @@
attachInfo.mTreeObserver.dispatchOnScrollChanged();
}
- final WindowManager.LayoutParams params = mWindowAttributes;
- final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
boolean animating = mScroller != null && mScroller.computeScrollOffset();
final int curScrollY;
if (animating) {
@@ -2434,14 +2437,27 @@
attachInfo.mTreeObserver.dispatchOnDraw();
- final int xOffset = surfaceInsets != null ? -surfaceInsets.left : 0;
- final int yOffset = curScrollY + (surfaceInsets != null ? -surfaceInsets.top : 0);
+ int xOffset = 0;
+ int yOffset = curScrollY;
+ final WindowManager.LayoutParams params = mWindowAttributes;
+ final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
+ if (surfaceInsets != null) {
+ xOffset -= surfaceInsets.left;
+ yOffset -= surfaceInsets.top;
+
+ // Offset dirty rect for surface insets.
+ dirty.offset(surfaceInsets.left, surfaceInsets.right);
+ }
+
if (!dirty.isEmpty() || mIsAnimating) {
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false;
- mHardwareYOffset = yOffset;
- mHardwareXOffset = xOffset;
+ if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
+ mHardwareYOffset = yOffset;
+ mHardwareXOffset = xOffset;
+ mAttachInfo.mHardwareRenderer.invalidateRoot();
+ }
mResizeAlpha = resizeAlpha;
dirty.setEmpty();
@@ -2493,19 +2509,19 @@
boolean scalingRequired, Rect dirty) {
// Draw with software renderer.
- Canvas canvas;
+ final Canvas canvas;
try {
- int left = dirty.left;
- int top = dirty.top;
- int right = dirty.right;
- int bottom = dirty.bottom;
+ final int left = dirty.left;
+ final int top = dirty.top;
+ final int right = dirty.right;
+ final int bottom = dirty.bottom;
canvas = mSurface.lockCanvas(dirty);
// The dirty rectangle can be modified by Surface.lockCanvas()
//noinspection ConstantConditions
- if (left != dirty.left || top != dirty.top || right != dirty.right ||
- bottom != dirty.bottom) {
+ if (left != dirty.left || top != dirty.top || right != dirty.right
+ || bottom != dirty.bottom) {
attachInfo.mIgnoreDirtyState = true;
}
@@ -2827,6 +2843,10 @@
// Set the new focus host and node.
mAccessibilityFocusedHost = view;
mAccessibilityFocusedVirtualView = node;
+
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.invalidateRoot();
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index a866ca7..06fe3bf 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -16,6 +16,7 @@
package com.android.internal.app;
+import android.content.res.TypedArray;
import com.android.internal.R;
import android.app.ActivityManagerNative;
@@ -227,6 +228,12 @@
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
+
+ final int[] attrs = { android.R.attr.colorBackground };
+ final TypedArray a = getActivity().getTheme().obtainStyledAttributes(attrs);
+ getListView().setBackgroundColor(a.getColor(0, android.R.color.transparent));
+ a.recycle();
+
final ArrayAdapter<LocaleInfo> adapter = constructAdapter(getActivity(),
isInDeveloperMode());
setListAdapter(adapter);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f40b84c..cc481e1 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -57,6 +57,7 @@
public class LockPatternUtils {
private static final String TAG = "LockPatternUtils";
+ private static final boolean DEBUG = false;
/**
* The maximum number of incorrect attempts before the user is prevented
@@ -1046,8 +1047,11 @@
return false;
}
-
- return true;
+ // TODO: If we decide not to proceed with Face Unlock as a trustlet, this must be changed
+ // back to returning true. If we become certain that Face Unlock will be a trustlet, this
+ // entire function and a lot of other code can be removed.
+ if (DEBUG) Log.d(TAG, "Forcing isBiometricWeakInstalled() to return false to disable it");
+ return false;
}
/**
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index aab48b3..988d461 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -138,13 +138,6 @@
}
}
-protected:
- virtual void damageSelf(TreeInfo& info) {
- // Intentionally a no-op. As RootRenderNode gets a new DisplayListData
- // every frame this would result in every draw push being a full inval,
- // which is wrong. Only RootRenderNode has this issue.
- }
-
private:
sp<Looper> mLooper;
std::vector<OnFinishedEvent> mOnFinishedEvents;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 55e02fb..658ef96 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -235,6 +235,7 @@
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
<protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
<protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
@@ -805,6 +806,19 @@
android:description="@string/permdesc_changeWifiState"
android:label="@string/permlab_changeWifiState" />
+ <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="signature|system" />
+
+ <!-- @SystemApi @hide Allow system apps to receive broadcast
+ when a wifi network credential is changed.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="signature|system" />
+
<!-- @hide -->
<permission android:name="android.permission.ACCESS_WIMAX_STATE"
android:permissionGroup="android.permission-group.NETWORK"
diff --git a/core/res/res/layout/preference_child_material.xml b/core/res/res/layout/preference_child_material.xml
index 690d64a..e5a8819 100644
--- a/core/res/res/layout/preference_child_material.xml
+++ b/core/res/res/layout/preference_child_material.xml
@@ -29,7 +29,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="left|center_vertical"
+ android:gravity="start|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+android:id/icon"
@@ -67,7 +67,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="right|center_vertical"
+ android:gravity="end|center_vertical"
android:orientation="vertical" />
</LinearLayout>
diff --git a/core/res/res/layout/preference_information_material.xml b/core/res/res/layout/preference_information_material.xml
index f21640fc..d283f62 100644
--- a/core/res/res/layout/preference_information_material.xml
+++ b/core/res/res/layout/preference_information_material.xml
@@ -30,7 +30,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="left|center_vertical"
+ android:gravity="start|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+android:id/icon"
@@ -68,7 +68,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="right|center_vertical"
+ android:gravity="end|center_vertical"
android:orientation="vertical" />
</LinearLayout>
diff --git a/core/res/res/layout/preference_material.xml b/core/res/res/layout/preference_material.xml
index a9599139..3919f5f 100644
--- a/core/res/res/layout/preference_material.xml
+++ b/core/res/res/layout/preference_material.xml
@@ -71,7 +71,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="right|center_vertical"
+ android:gravity="end|center_vertical"
android:orientation="vertical" />
</LinearLayout>
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 4389e3d..90d8d4c 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -535,6 +535,8 @@
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
@@ -544,352 +546,378 @@
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.util.StringUtils;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
import org.xmlpull.v1.XmlPullParser;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import java.util.Random;
+import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLSocketFactory;
+
/**
- * Sample Smack implementation of a client for GCM Cloud Connection Server.
+ * Sample Smack implementation of a client for GCM Cloud Connection Server. This
+ * code can be run as a standalone CCS client.
*
* <p>For illustration purposes only.
*/
public class SmackCcsClient {
- Logger logger = Logger.getLogger("SmackCcsClient");
+ private static final Logger logger = Logger.getLogger("SmackCcsClient");
- public static final String GCM_SERVER = "gcm.googleapis.com";
- public static final int GCM_PORT = 5235;
+ private static final String GCM_SERVER = "gcm.googleapis.com";
+ private static final int GCM_PORT = 5235;
- public static final String GCM_ELEMENT_NAME = "gcm";
- public static final String GCM_NAMESPACE = "google:mobile:data";
+ private static final String GCM_ELEMENT_NAME = "gcm";
+ private static final String GCM_NAMESPACE = "google:mobile:data";
- static Random random = new Random();
- XMPPConnection connection;
- ConnectionConfiguration config;
+ static {
- /**
- * XMPP Packet Extension for GCM Cloud Connection Server.
- */
- class GcmPacketExtension extends DefaultPacketExtension {
- String json;
-
- public GcmPacketExtension(String json) {
- super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
- this.json = json;
+ ProviderManager.addExtensionProvider(GCM_ELEMENT_NAME, GCM_NAMESPACE,
+ new PacketExtensionProvider() {
+ @Override
+ public PacketExtension parseExtension(XmlPullParser parser) throws
+ Exception {
+ String json = parser.nextText();
+ return new GcmPacketExtension(json);
+ }
+ });
}
- public String getJson() {
- return json;
+ private XMPPConnection connection;
+
+ /**
+ * Indicates whether the connection is in draining state, which means that it
+ * will not accept any new downstream messages.
+ */
+ protected volatile boolean connectionDraining = false;
+
+ /**
+ * Sends a downstream message to GCM.
+ *
+ * @return true if the message has been successfully sent.
+ */
+ public boolean sendDownstreamMessage(String jsonRequest) throws
+ NotConnectedException {
+ if (!connectionDraining) {
+ send(jsonRequest);
+ return true;
+ }
+ logger.info("Dropping downstream message since the connection is draining");
+ return false;
}
- @Override
- public String toXML() {
- return String.format("<%s xmlns=\"%s\">%s</%s>", GCM_ELEMENT_NAME,
- GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
+ /**
+ * Returns a random message id to uniquely identify a message.
+ *
+ * <p>Note: This is generated by a pseudo random number generator for
+ * illustration purpose, and is not guaranteed to be unique.
+ */
+ public String nextMessageId() {
+ return "m-" + UUID.randomUUID().toString();
}
- @SuppressWarnings("unused")
- public Packet toPacket() {
- return new Message() {
- // Must override toXML() because it includes a <body>
+ /**
+ * Sends a packet with contents provided.
+ */
+ protected void send(String jsonRequest) throws NotConnectedException {
+ Packet request = new GcmPacketExtension(jsonRequest).toPacket();
+ connection.sendPacket(request);
+ }
+
+ /**
+ * Handles an upstream data message from a device application.
+ *
+ * <p>This sample echo server sends an echo message back to the device.
+ * Subclasses should override this method to properly process upstream messages.
+ */
+ protected void handleUpstreamMessage(Map<String, Object> jsonObject) {
+ // PackageName of the application that sent this message.
+ String category = (String) jsonObject.get("category");
+ String from = (String) jsonObject.get("from");
+ @SuppressWarnings("unchecked")
+ Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
+ payload.put("ECHO", "Application: " + category);
+
+ // Send an ECHO response back
+ String echo = createJsonMessage(from, nextMessageId(), payload,
+ "echo:CollapseKey", null, false);
+
+ try {
+ sendDownstreamMessage(echo);
+ } catch (NotConnectedException e) {
+ logger.log(Level.WARNING, "Not connected anymore, echo message is
+ not sent", e);
+ }
+ }
+
+ /**
+ * Handles an ACK.
+ *
+ * <p>Logs a {@code INFO} message, but subclasses could override it to
+ * properly handle ACKs.
+ */
+ protected void handleAckReceipt(Map<String, Object> jsonObject) {
+ String messageId = (String) jsonObject.get("message_id");
+ String from = (String) jsonObject.get("from");
+ logger.log(Level.INFO, "handleAckReceipt() from: " + from + ",
+ messageId: " + messageId);
+ }
+
+ /**
+ * Handles a NACK.
+ *
+ * <p>Logs a {@code INFO} message, but subclasses could override it to
+ * properly handle NACKs.
+ */
+ protected void handleNackReceipt(Map<String, Object> jsonObject) {
+ String messageId = (String) jsonObject.get("message_id");
+ String from = (String) jsonObject.get("from");
+ logger.log(Level.INFO, "handleNackReceipt() from: " + from + ",
+ messageId: " + messageId);
+ }
+
+ protected void handleControlMessage(Map<String, Object> jsonObject) {
+ logger.log(Level.INFO, "handleControlMessage(): " + jsonObject);
+ String controlType = (String) jsonObject.get("control_type");
+ if ("CONNECTION_DRAINING".equals(controlType)) {
+ connectionDraining = true;
+ } else {
+ logger.log(Level.INFO, "Unrecognized control type: %s. This could
+ happen if new features are " + "added to the CCS protocol.",
+ controlType);
+ }
+ }
+
+ /**
+ * Creates a JSON encoded GCM message.
+ *
+ * @param to RegistrationId of the target device (Required).
+ * @param messageId Unique messageId for which CCS will send an
+ * "ack/nack" (Required).
+ * @param payload Message content intended for the application. (Optional).
+ * @param collapseKey GCM collapse_key parameter (Optional).
+ * @param timeToLive GCM time_to_live parameter (Optional).
+ * @param delayWhileIdle GCM delay_while_idle parameter (Optional).
+ * @return JSON encoded GCM message.
+ */
+ public static String createJsonMessage(String to, String messageId,
+ Map<String, String> payload, String collapseKey, Long timeToLive,
+ Boolean delayWhileIdle) {
+ Map<String, Object> message = new HashMap<String, Object>();
+ message.put("to", to);
+ if (collapseKey != null) {
+ message.put("collapse_key", collapseKey);
+ }
+ if (timeToLive != null) {
+ message.put("time_to_live", timeToLive);
+ }
+ if (delayWhileIdle != null && delayWhileIdle) {
+ message.put("delay_while_idle", true);
+ }
+ message.put("message_id", messageId);
+ message.put("data", payload);
+ return JSONValue.toJSONString(message);
+ }
+
+ /**
+ * Creates a JSON encoded ACK message for an upstream message received
+ * from an application.
+ *
+ * @param to RegistrationId of the device who sent the upstream message.
+ * @param messageId messageId of the upstream message to be acknowledged to CCS.
+ * @return JSON encoded ack.
+ */
+ protected static String createJsonAck(String to, String messageId) {
+ Map<String, Object> message = new HashMap<String, Object>();
+ message.put("message_type", "ack");
+ message.put("to", to);
+ message.put("message_id", messageId);
+ return JSONValue.toJSONString(message);
+ }
+
+ /**
+ * Connects to GCM Cloud Connection Server using the supplied credentials.
+ *
+ * @param senderId Your GCM project number
+ * @param apiKey API Key of your project
+ */
+ public void connect(long senderId, String apiKey)
+ throws XMPPException, IOException, SmackException {
+ ConnectionConfiguration config =
+ new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
+ config.setSecurityMode(SecurityMode.enabled);
+ config.setReconnectionAllowed(true);
+ config.setRosterLoadedAtLogin(false);
+ config.setSendPresence(false);
+ config.setSocketFactory(SSLSocketFactory.getDefault());
+
+ connection = new XMPPTCPConnection(config);
+ connection.connect();
+
+ connection.addConnectionListener(new LoggingConnectionListener());
+
+ // Handle incoming packets
+ connection.addPacketListener(new PacketListener() {
+
+ @Override
+ public void processPacket(Packet packet) {
+ logger.log(Level.INFO, "Received: " + packet.toXML());
+ Message incomingMessage = (Message) packet;
+ GcmPacketExtension gcmPacket =
+ (GcmPacketExtension) incomingMessage.
+ getExtension(GCM_NAMESPACE);
+ String json = gcmPacket.getJson();
+ try {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> jsonObject =
+ (Map<String, Object>) JSONValue.
+ parseWithException(json);
+
+ // present for "ack"/"nack", null otherwise
+ Object messageType = jsonObject.get("message_type");
+
+ if (messageType == null) {
+ // Normal upstream data message
+ handleUpstreamMessage(jsonObject);
+
+ // Send ACK to CCS
+ String messageId = (String) jsonObject.get("message_id");
+ String from = (String) jsonObject.get("from");
+ String ack = createJsonAck(from, messageId);
+ send(ack);
+ } else if ("ack".equals(messageType.toString())) {
+ // Process Ack
+ handleAckReceipt(jsonObject);
+ } else if ("nack".equals(messageType.toString())) {
+ // Process Nack
+ handleNackReceipt(jsonObject);
+ } else if ("control".equals(messageType.toString())) {
+ // Process control message
+ handleControlMessage(jsonObject);
+ } else {
+ logger.log(Level.WARNING,
+ "Unrecognized message type (%s)",
+ messageType.toString());
+ }
+ } catch (ParseException e) {
+ logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Failed to process packet", e);
+ }
+ }
+ }, new PacketTypeFilter(Message.class));
+
+ // Log all outgoing packets
+ connection.addPacketInterceptor(new PacketInterceptor() {
+ @Override
+ public void interceptPacket(Packet packet) {
+ logger.log(Level.INFO, "Sent: {0}", packet.toXML());
+ }
+ }, new PacketTypeFilter(Message.class));
+
+ connection.login(senderId + "@gcm.googleapis.com", apiKey);
+ }
+
+ public static void main(String[] args) throws Exception {
+ final long senderId = 1234567890L; // your GCM sender id
+ final String password = "Your API key";
+
+ SmackCcsClient ccsClient = new SmackCcsClient();
+
+ ccsClient.connect(senderId, password);
+
+ // Send a sample hello downstream message to a device.
+ String toRegId = "RegistrationIdOfTheTargetDevice";
+ String messageId = ccsClient.nextMessageId();
+ Map<String, String> payload = new HashMap<String, String>();
+ payload.put("Hello", "World");
+ payload.put("CCS", "Dummy Message");
+ payload.put("EmbeddedMessageId", messageId);
+ String collapseKey = "sample";
+ Long timeToLive = 10000L;
+ String message = createJsonMessage(toRegId, messageId, payload,
+ collapseKey, timeToLive, true);
+
+ ccsClient.sendDownstreamMessage(message);
+ }
+
+ /**
+ * XMPP Packet Extension for GCM Cloud Connection Server.
+ */
+ private static final class GcmPacketExtension extends DefaultPacketExtension {
+
+ private final String json;
+
+ public GcmPacketExtension(String json) {
+ super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
+ this.json = json;
+ }
+
+ public String getJson() {
+ return json;
+ }
+
@Override
public String toXML() {
-
- StringBuilder buf = new StringBuilder();
- buf.append("<message");
- if (getXmlns() != null) {
- buf.append(" xmlns=\"").append(getXmlns()).append("\"");
- }
- if (getLanguage() != null) {
- buf.append(" xml:lang=\"").append(getLanguage()).append("\"");
- }
- if (getPacketID() != null) {
- buf.append(" id=\"").append(getPacketID()).append("\"");
- }
- if (getTo() != null) {
- buf.append(" to=\"").append(StringUtils.escapeForXML(getTo())).append("\"");
- }
- if (getFrom() != null) {
- buf.append(" from=\"").append(StringUtils.escapeForXML(getFrom())).append("\"");
- }
- buf.append(">");
- buf.append(GcmPacketExtension.this.toXML());
- buf.append("</message>");
- return buf.toString();
+ return String.format("<%s xmlns=\"%s\">%s</%s>",
+ GCM_ELEMENT_NAME, GCM_NAMESPACE,
+ StringUtils.escapeForXML(json), GCM_ELEMENT_NAME);
}
- };
- }
- }
- public SmackCcsClient() {
- // Add GcmPacketExtension
- ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
- GCM_NAMESPACE, new PacketExtensionProvider() {
-
- @Override
- public PacketExtension parseExtension(XmlPullParser parser)
- throws Exception {
- String json = parser.nextText();
- GcmPacketExtension packet = new GcmPacketExtension(json);
- return packet;
- }
- });
- }
-
- /**
- * Returns a random message id to uniquely identify a message.
- *
- * <p>Note:
- * This is generated by a pseudo random number generator for illustration purpose,
- * and is not guaranteed to be unique.
- *
- */
- public String getRandomMessageId() {
- return "m-" + Long.toString(random.nextLong());
- }
-
- /**
- * Sends a downstream GCM message.
- */
- public void send(String jsonRequest) {
- Packet request = new GcmPacketExtension(jsonRequest).toPacket();
- connection.sendPacket(request);
- }
-
- /**
- * Handles an upstream data message from a device application.
- *
- * <p>This sample echo server sends an echo message back to the device.
- * Subclasses should override this method to process an upstream message.
- */
- public void handleIncomingDataMessage(Map<String, Object> jsonObject) {
- String from = jsonObject.get("from").toString();
-
- // PackageName of the application that sent this message.
- String category = jsonObject.get("category").toString();
-
- // Use the packageName as the collapseKey in the echo packet
- String collapseKey = "echo:CollapseKey";
- @SuppressWarnings("unchecked")
- Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
- payload.put("ECHO", "Application: " + category);
-
- // Send an ECHO response back
- String echo = createJsonMessage(from, getRandomMessageId(), payload, collapseKey, null, false);
- send(echo);
- }
-
- /**
- * Handles an ACK.
- *
- * <p>By default, it only logs a {@code INFO} message, but subclasses could override it to
- * properly handle ACKS.
- */
- public void handleAckReceipt(Map<String, Object> jsonObject) {
- String messageId = jsonObject.get("message_id").toString();
- String from = jsonObject.get("from").toString();
- logger.log(Level.INFO, "handleAckReceipt() from: " + from + ", messageId: " + messageId);
- }
-
- /**
- * Handles a NACK.
- *
- * <p>By default, it only logs a {@code INFO} message, but subclasses could override it to
- * properly handle NACKS.
- */
- public void handleNackReceipt(Map<String, Object> jsonObject) {
- String messageId = jsonObject.get("message_id").toString();
- String from = jsonObject.get("from").toString();
- logger.log(Level.INFO, "handleNackReceipt() from: " + from + ", messageId: " + messageId);
- }
-
- /**
- * Creates a JSON encoded GCM message.
- *
- * @param to RegistrationId of the target device (Required).
- * @param messageId Unique messageId for which CCS will send an "ack/nack" (Required).
- * @param payload Message content intended for the application. (Optional).
- * @param collapseKey GCM collapse_key parameter (Optional).
- * @param timeToLive GCM time_to_live parameter (Optional).
- * @param delayWhileIdle GCM delay_while_idle parameter (Optional).
- * @return JSON encoded GCM message.
- */
- public static String createJsonMessage(String to, String messageId, Map<String, String> payload,
- String collapseKey, Long timeToLive, Boolean delayWhileIdle) {
- Map<String, Object> message = new HashMap<String, Object>();
- message.put("to", to);
- if (collapseKey != null) {
- message.put("collapse_key", collapseKey);
- }
- if (timeToLive != null) {
- message.put("time_to_live", timeToLive);
- }
- if (delayWhileIdle != null && delayWhileIdle) {
- message.put("delay_while_idle", true);
- }
- message.put("message_id", messageId);
- message.put("data", payload);
- return JSONValue.toJSONString(message);
- }
-
- /**
- * Creates a JSON encoded ACK message for an upstream message received from an application.
- *
- * @param to RegistrationId of the device who sent the upstream message.
- * @param messageId messageId of the upstream message to be acknowledged to CCS.
- * @return JSON encoded ack.
- */
- public static String createJsonAck(String to, String messageId) {
- Map<String, Object> message = new HashMap<String, Object>();
- message.put("message_type", "ack");
- message.put("to", to);
- message.put("message_id", messageId);
- return JSONValue.toJSONString(message);
- }
-
- /**
- * Connects to GCM Cloud Connection Server using the supplied credentials.
- *
- * @param username GCM_SENDER_ID@gcm.googleapis.com
- * @param password API Key
- * @throws XMPPException
- */
- public void connect(String username, String password) throws XMPPException {
- config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
- config.setSecurityMode(SecurityMode.enabled);
- config.setReconnectionAllowed(true);
- config.setRosterLoadedAtLogin(false);
- config.setSendPresence(false);
- config.setSocketFactory(SSLSocketFactory.getDefault());
-
- // NOTE: Set to true to launch a window with information about packets sent and received
- config.setDebuggerEnabled(true);
-
- // -Dsmack.debugEnabled=true
- XMPPConnection.DEBUG_ENABLED = true;
-
- connection = new XMPPConnection(config);
- connection.connect();
-
- connection.addConnectionListener(new ConnectionListener() {
-
- @Override
- public void reconnectionSuccessful() {
- logger.info("Reconnecting..");
- }
-
- @Override
- public void reconnectionFailed(Exception e) {
- logger.log(Level.INFO, "Reconnection failed.. ", e);
- }
-
- @Override
- public void reconnectingIn(int seconds) {
- logger.log(Level.INFO, "Reconnecting in %d secs", seconds);
- }
-
- @Override
- public void connectionClosedOnError(Exception e) {
- logger.log(Level.INFO, "Connection closed on error.");
- }
-
- @Override
- public void connectionClosed() {
- logger.info("Connection closed.");
- }
- });
-
- // Handle incoming packets
- connection.addPacketListener(new PacketListener() {
-
- @Override
- public void processPacket(Packet packet) {
- logger.log(Level.INFO, "Received: " + packet.toXML());
- Message incomingMessage = (Message) packet;
- GcmPacketExtension gcmPacket =
- (GcmPacketExtension) incomingMessage.getExtension(GCM_NAMESPACE);
- String json = gcmPacket.getJson();
- try {
- @SuppressWarnings("unchecked")
- Map<String, Object> jsonObject =
- (Map<String, Object>) JSONValue.parseWithException(json);
-
- // present for "ack"/"nack", null otherwise
- Object messageType = jsonObject.get("message_type");
-
- if (messageType == null) {
- // Normal upstream data message
- handleIncomingDataMessage(jsonObject);
-
- // Send ACK to CCS
- String messageId = jsonObject.get("message_id").toString();
- String from = jsonObject.get("from").toString();
- String ack = createJsonAck(from, messageId);
- send(ack);
- } else if ("ack".equals(messageType.toString())) {
- // Process Ack
- handleAckReceipt(jsonObject);
- } else if ("nack".equals(messageType.toString())) {
- // Process Nack
- handleNackReceipt(jsonObject);
- } else {
- logger.log(Level.WARNING, "Unrecognized message type (%s)",
- messageType.toString());
- }
- } catch (ParseException e) {
- logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Couldn't send echo.", e);
+ public Packet toPacket() {
+ Message message = new Message();
+ message.addExtension(this);
+ return message;
}
- }
- }, new PacketTypeFilter(Message.class));
-
-
- // Log all outgoing packets
- connection.addPacketInterceptor(new PacketInterceptor() {
- @Override
- public void interceptPacket(Packet packet) {
- logger.log(Level.INFO, "Sent: {0}", packet.toXML());
- }
- }, new PacketTypeFilter(Message.class));
-
- connection.login(username, password);
- }
-
- public static void main(String [] args) {
- final String userName = "Your GCM Sender Id" + "@gcm.googleapis.com";
- final String password = "API Key";
-
- SmackCcsClient ccsClient = new SmackCcsClient();
-
- try {
- ccsClient.connect(userName, password);
- } catch (XMPPException e) {
- e.printStackTrace();
}
- // Send a sample hello downstream message to a device.
- String toRegId = "RegistrationIdOfTheTargetDevice";
- String messageId = ccsClient.getRandomMessageId();
- Map<String, String> payload = new HashMap<String, String>();
- payload.put("Hello", "World");
- payload.put("CCS", "Dummy Message");
- payload.put("EmbeddedMessageId", messageId);
- String collapseKey = "sample";
- Long timeToLive = 10000L;
- Boolean delayWhileIdle = true;
- ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
- timeToLive, delayWhileIdle));
- }
+ private static final class LoggingConnectionListener
+ implements ConnectionListener {
+
+ @Override
+ public void connected(XMPPConnection xmppConnection) {
+ logger.info("Connected.");
+ }
+
+ @Override
+ public void authenticated(XMPPConnection xmppConnection) {
+ logger.info("Authenticated.");
+ }
+
+ @Override
+ public void reconnectionSuccessful() {
+ logger.info("Reconnecting..");
+ }
+
+ @Override
+ public void reconnectionFailed(Exception e) {
+ logger.log(Level.INFO, "Reconnection failed.. ", e);
+ }
+
+ @Override
+ public void reconnectingIn(int seconds) {
+ logger.log(Level.INFO, "Reconnecting in %d secs", seconds);
+ }
+
+ @Override
+ public void connectionClosedOnError(Exception e) {
+ logger.info("Connection closed on error.");
+ }
+
+ @Override
+ public void connectionClosed() {
+ logger.info("Connection closed.");
+ }
+ }
}</pre>
+
<h3 id="python">Python sample</h3>
<p>Here is an example of a CCS app server written in Python. This sample echo
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 54fa143..8cc65b2 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -173,9 +173,6 @@
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
-protected:
- virtual void damageSelf(TreeInfo& info);
-
private:
typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
@@ -250,6 +247,7 @@
void prepareLayer(TreeInfo& info);
void pushLayerUpdate(TreeInfo& info);
void deleteDisplayListData();
+ void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
void decParentRefCount();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 57279b7..a4ac262 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -185,6 +185,11 @@
} else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
dirty.setEmpty();
} else {
+ if (!dirty.intersect(0, 0, width, height)) {
+ ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
+ SK_RECT_ARGS(dirty), width, height);
+ dirty.setEmpty();
+ }
profiler().unionDirty(&dirty);
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c65961d..ef95c11 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2954,15 +2954,12 @@
* Set Hdmi Cec system audio mode.
*
* @param on whether to be on system audio mode
- * @param device out device type to be used for system audio mode.
- * Ignored if {@code on} is {@code false}
- * @param name name of system audio device
* @return output device type. 0 (DEVICE_NONE) if failed to set device.
* @hide
*/
- public int setHdmiSystemAudioSupported(boolean on, int device, String name) {
+ public int setHdmiSystemAudioSupported(boolean on) {
try {
- return getService().setHdmiSystemAudioSupported(on, device, name);
+ return getService().setHdmiSystemAudioSupported(on);
} catch (RemoteException e) {
Log.w(TAG, "Error setting system audio mode", e);
return AudioSystem.DEVICE_NONE;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ab63145..9d5fe23 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -393,10 +393,16 @@
// Indicates the mode used for SCO audio connection. The mode is virtual call if the request
// originated from an app targeting an API version before JB MR2 and raw audio after that.
private int mScoAudioMode;
+ // SCO audio mode is undefined
+ private static final int SCO_MODE_UNDEFINED = -1;
// SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
private static final int SCO_MODE_VIRTUAL_CALL = 0;
// SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
private static final int SCO_MODE_RAW = 1;
+ // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
+ private static final int SCO_MODE_VR = 2;
+
+ private static final int SCO_MODE_MAX = 2;
// Current connection state indicated by bluetooth headset
private int mScoConnectionState;
@@ -2117,7 +2123,7 @@
public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
int scoAudioMode =
(targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
- SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
+ SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
startBluetoothScoInt(cb, scoAudioMode);
}
@@ -2272,14 +2278,28 @@
mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
if (mScoAudioState == SCO_STATE_INACTIVE) {
mScoAudioMode = scoAudioMode;
+ if (scoAudioMode == SCO_MODE_UNDEFINED) {
+ mScoAudioMode = new Integer(Settings.Global.getInt(
+ mContentResolver,
+ "bluetooth_sco_channel_"+
+ mBluetoothHeadsetDevice.getAddress(),
+ SCO_MODE_VIRTUAL_CALL));
+ if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
+ mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+ }
+ }
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
- boolean status;
+ boolean status = false;
if (mScoAudioMode == SCO_MODE_RAW) {
status = mBluetoothHeadset.connectAudio();
- } else {
+ } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
mBluetoothHeadsetDevice);
+ } else if (mScoAudioMode == SCO_MODE_VR) {
+ status = mBluetoothHeadset.startVoiceRecognition(
+ mBluetoothHeadsetDevice);
}
+
if (status) {
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
} else {
@@ -2302,13 +2322,17 @@
mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
- boolean status;
+ boolean status = false;
if (mScoAudioMode == SCO_MODE_RAW) {
status = mBluetoothHeadset.disconnectAudio();
- } else {
+ } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
mBluetoothHeadsetDevice);
+ } else if (mScoAudioMode == SCO_MODE_VR) {
+ status = mBluetoothHeadset.stopVoiceRecognition(
+ mBluetoothHeadsetDevice);
}
+
if (!status) {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(
@@ -2502,17 +2526,23 @@
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
if (mScoAudioMode == SCO_MODE_RAW) {
status = mBluetoothHeadset.connectAudio();
- } else {
+ } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
mBluetoothHeadsetDevice);
+ } else if (mScoAudioMode == SCO_MODE_VR) {
+ status = mBluetoothHeadset.startVoiceRecognition(
+ mBluetoothHeadsetDevice);
}
break;
case SCO_STATE_DEACTIVATE_REQ:
if (mScoAudioMode == SCO_MODE_RAW) {
status = mBluetoothHeadset.disconnectAudio();
- } else {
+ } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
mBluetoothHeadsetDevice);
+ } else if (mScoAudioMode == SCO_MODE_VR) {
+ status = mBluetoothHeadset.stopVoiceRecognition(
+ mBluetoothHeadsetDevice);
}
break;
case SCO_STATE_DEACTIVATE_EXT_REQ:
@@ -3792,8 +3822,7 @@
}
if (mHdmiTvClient != null) {
- setHdmiSystemAudioSupported(mHdmiSystemAudioSupported,
- mHdmiSystemAudioOutputDevice, "");
+ setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
}
// indicate the end of reconfiguration phase to audio HAL
@@ -4774,113 +4803,25 @@
private boolean mHdmiSystemAudioSupported = false;
// Set only when device is tv.
private HdmiTvClient mHdmiTvClient;
- private int mHdmiSystemAudioOutputDevice = AudioSystem.DEVICE_NONE;
- private int[] mSpeakerGains;
@Override
- public int setHdmiSystemAudioSupported(boolean on, int device, String name) {
+ public int setHdmiSystemAudioSupported(boolean on) {
if (mHdmiTvClient == null) {
Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
return AudioSystem.DEVICE_NONE;
}
- if (on && !checkHdmiSystemAudioOutput(device)) {
- return AudioSystem.DEVICE_NONE;
- }
-
synchronized (mHdmiTvClient) {
- if (on) {
- mHdmiSystemAudioOutputDevice = device;
- }
if (mHdmiSystemAudioSupported == on) {
return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
}
mHdmiSystemAudioSupported = on;
- updateHdmiSystemAudioVolumeLocked(on);
+ AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
+ on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE);
}
return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
}
- private boolean checkHdmiSystemAudioOutput(int device) {
- if ((device & AudioSystem.DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO) == 0) {
- Log.w(TAG, "Unsupported Hdmi-Cec system audio output:" + device);
- return false;
- }
-
- int streamDevice = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
- // If other devices except for system audio and speaker are available,
- // fails to start system audio mode.
- if ((streamDevice & ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER) != 0) {
- Log.w(TAG, "Should turn off other devices before starting system audio:"
- + streamDevice);
- return false;
- }
- if (AudioSystem.getDeviceConnectionState(device, "") !=
- AudioSystem.DEVICE_STATE_AVAILABLE) {
- Log.w(TAG, "Output device is not connected:" + device);
- return false;
- }
- return true;
- }
-
- private void updateHdmiSystemAudioVolumeLocked(boolean on) {
- AudioDevicePort speaker = findAudioDevicePort(AudioSystem.DEVICE_OUT_SPEAKER);
- if (speaker == null) {
- Log.w(TAG, "Has no speaker output.");
- return;
- }
-
- AudioPortConfig portConfig = speaker.activeConfig();
- AudioGainConfig gainConfig = portConfig.gain();
- int[] newGains;
- // When system audio is on, backup original gains and mute all channels of speaker by
- // setting gains to 0; otherwise, restore gains of speaker.
- if (on) {
- if (gainConfig == null) {
- Log.w(TAG, "Speaker has no gain control.");
- return;
- }
- // Back up original gains.
- mSpeakerGains = Arrays.copyOf(gainConfig.values(), gainConfig.values().length);
- // Set all gains to 0.
- newGains = new int[gainConfig.values().length];
- } else {
- if (mSpeakerGains == null) {
- Log.w(TAG, "mSpeakerGains should not be null.");
- return;
- }
- newGains = Arrays.copyOf(mSpeakerGains, mSpeakerGains.length);
- }
-
- gainConfig = gainConfig.mGain.buildConfig(gainConfig.mode(),
- gainConfig.channelMask(),
- newGains,
- gainConfig.rampDurationMs());
-
- AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- if (AudioSystem.SUCCESS != audioManager.setAudioPortGain(speaker, gainConfig)) {
- Log.w(TAG, "Failed to update audio port config.");
- }
- }
-
- private AudioDevicePort findAudioDevicePort(int type) {
- ArrayList<AudioPort> devicePorts = new ArrayList<>();
- AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- int status = audioManager.listAudioDevicePorts(devicePorts);
- if (status != AudioSystem.SUCCESS) {
- Log.w(TAG, "Failed to list up all audio ports");
- return null;
- }
-
- for (AudioPort port : devicePorts) {
- AudioDevicePort devicePort = (AudioDevicePort) port;
- if (devicePort.type() == type) {
- return devicePort;
- }
- }
- return null;
- }
-
//==========================================================================================
// Camera shutter sound policy.
// config_camera_sound_forced configuration option in config.xml defines if the camera shutter
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 72367c8..8e2ca95 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -254,6 +254,7 @@
public static final int DEVICE_OUT_HDMI_ARC = 0x40000;
public static final int DEVICE_OUT_SPDIF = 0x80000;
public static final int DEVICE_OUT_FM = 0x100000;
+ public static final int DEVICE_OUT_AUX_LINE = 0x200000;
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
@@ -278,6 +279,7 @@
DEVICE_OUT_HDMI_ARC |
DEVICE_OUT_SPDIF |
DEVICE_OUT_FM |
+ DEVICE_OUT_AUX_LINE |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -287,7 +289,7 @@
DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
DEVICE_OUT_USB_DEVICE);
- public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_LINE |
+ public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE |
DEVICE_OUT_HDMI_ARC |
DEVICE_OUT_SPDIF);
public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER =
@@ -440,7 +442,8 @@
public static final int FORCE_DIGITAL_DOCK = 9;
public static final int FORCE_NO_BT_A2DP = 10;
public static final int FORCE_SYSTEM_ENFORCED = 11;
- private static final int NUM_FORCE_CONFIG = 12;
+ public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
+ private static final int NUM_FORCE_CONFIG = 13;
public static final int FORCE_DEFAULT = FORCE_NONE;
// usage for setForceUse, must match AudioSystem::force_use
@@ -449,7 +452,8 @@
public static final int FOR_RECORD = 2;
public static final int FOR_DOCK = 3;
public static final int FOR_SYSTEM = 4;
- private static final int NUM_FORCE_USE = 5;
+ public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
+ private static final int NUM_FORCE_USE = 6;
// usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
public static final int SYNC_EVENT_NONE = 0;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4f7021e..7318660 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -201,7 +201,7 @@
void disableSafeMediaVolume();
- int setHdmiSystemAudioSupported(boolean on, int device, String name);
+ int setHdmiSystemAudioSupported(boolean on);
boolean registerAudioPolicy(in AudioPolicyConfig policyConfig, IBinder cb);
oneway void unregisterAudioPolicyAsync(in IBinder cb);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3917bf1..59307d0 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -299,6 +299,9 @@
/** @hide H.264/AAC data encapsulated in MPEG2/TS */
public static final int OUTPUT_FORMAT_MPEG2TS = 8;
+
+ /** VP8/VORBIS data in a WEBM container */
+ public static final int WEBM = 9;
};
/**
@@ -321,6 +324,8 @@
public static final int HE_AAC = 4;
/** Enhanced Low Delay AAC (AAC-ELD) audio codec */
public static final int AAC_ELD = 5;
+ /** Ogg Vorbis audio codec */
+ public static final int VORBIS = 6;
}
/**
@@ -336,6 +341,7 @@
public static final int H263 = 1;
public static final int H264 = 2;
public static final int MPEG_4_SP = 3;
+ public static final int VP8 = 4;
}
/**
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 1bb36dd..8b5ff67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -27,11 +27,12 @@
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.telecomm.TelecommConstants;
+import android.telecomm.TelecommManager;
import android.util.Log;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.TtyIntent;
import com.android.systemui.R;
/**
@@ -89,7 +90,7 @@
else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
updateSimState(intent);
}
- else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
+ else if (action.equals(TelecommConstants.ACTION_CURRENT_TTY_MODE_CHANGED)) {
updateTTY(intent);
}
else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
@@ -110,7 +111,7 @@
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+ filter.addAction(TelecommConstants.ACTION_CURRENT_TTY_MODE_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
@@ -269,7 +270,9 @@
}
private final void updateTTY(Intent intent) {
- final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
+ int currentTtyMode = intent.getIntExtra(TelecommConstants.EXTRA_CURRENT_TTY_MODE,
+ TelecommConstants.TTY_MODE_OFF);
+ boolean enabled = currentTtyMode != TelecommConstants.TTY_MODE_OFF;
if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c3a9dbe..e8e2813 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3535,19 +3535,30 @@
}
} while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
- // Done -- how did it turn out?
- if (result == BackupTransport.TRANSPORT_OK){
- result = transport.finishBackup();
- } else {
- Slog.w(TAG, "Error backing up " + target.packageName);
+ // In all cases we need to give the transport its finish callback
+ int finishResult = transport.finishBackup();
+
+ // If we were otherwise in a good state, now interpret the final
+ // result based on what finishBackup() returned. If we're in a
+ // failure case already, preserve that result and ignore whatever
+ // finishBackup() reported.
+ if (result == BackupTransport.TRANSPORT_OK) {
+ result = finishResult;
}
- } else if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+
+ if (result != BackupTransport.TRANSPORT_OK) {
+ Slog.e(TAG, "Error " + result
+ + " backing up " + target.packageName);
+ }
+ }
+
+ if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
if (DEBUG) {
Slog.i(TAG, "Transport rejected backup of " + target.packageName
+ ", skipping");
}
// do nothing, clean up, and continue looping
- } else {
+ } else if (result != BackupTransport.TRANSPORT_OK) {
if (DEBUG) {
Slog.i(TAG, "Transport failed; aborting backup");
return;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 86f8777..9945909 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5720,6 +5720,17 @@
oldNetwork.asyncChannel.disconnect();
}
+ private void makeDefault(NetworkAgentInfo newNetwork) {
+ if (VDBG) log("Switching to new default network: " + newNetwork);
+ setupDataActivityTracking(newNetwork);
+ try {
+ mNetd.setDefaultNetId(newNetwork.network.netId);
+ } catch (Exception e) {
+ loge("Exception setting default network :" + e);
+ }
+ handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
+ }
+
private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
if (newNetwork == null) {
loge("Unknown NetworkAgentInfo in handleConnectionValidated");
@@ -5813,16 +5824,7 @@
}
if (keep) {
if (isNewDefault) {
- if (VDBG) log("Switching to new default network: " + newNetwork);
- setupDataActivityTracking(newNetwork);
- try {
- mNetd.setDefaultNetId(newNetwork.network.netId);
- } catch (Exception e) {
- loge("Exception setting default network :" + e);
- }
- if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) {
- handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
- }
+ makeDefault(newNetwork);
synchronized (ConnectivityService.this) {
// have a new default network, release the transition wakelock in
// a second if it's held. The second pause is to allow apps
@@ -5919,6 +5921,13 @@
}
// TODO: support proxy per network.
}
+ // Make default network if we have no default. Any network is better than no network.
+ if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
+ networkAgent.isVPN() == false &&
+ mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
+ networkAgent.networkCapabilities)) {
+ makeDefault(networkAgent);
+ }
} else if (state == NetworkInfo.State.DISCONNECTED ||
state == NetworkInfo.State.SUSPENDED) {
networkAgent.asyncChannel.disconnect();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a19eb15..87084d5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1069,27 +1069,31 @@
synchronized (mRecords) {
final int recordCount = mRecords.size();
pw.println("last known state:");
- pw.println(" mCallState=" + mCallState);
- pw.println(" mCallIncomingNumber=" + mCallIncomingNumber);
- pw.println(" mServiceState=" + mServiceState);
- pw.println(" mSignalStrength=" + mSignalStrength);
- pw.println(" mMessageWaiting=" + mMessageWaiting);
- pw.println(" mCallForwarding=" + mCallForwarding);
- pw.println(" mDataActivity=" + mDataActivity);
- pw.println(" mDataConnectionState=" + mDataConnectionState);
- pw.println(" mDataConnectionPossible=" + mDataConnectionPossible);
- pw.println(" mDataConnectionReason=" + mDataConnectionReason);
- pw.println(" mDataConnectionApn=" + mDataConnectionApn);
- pw.println(" mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
- pw.println(" mDataConnectionNetworkCapabilities=" +
- mDataConnectionNetworkCapabilities);
+ for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+ pw.println(" Phone Id=" + i);
+ pw.println(" mCallState=" + mCallState[i]);
+ pw.println(" mCallIncomingNumber=" + mCallIncomingNumber[i]);
+ pw.println(" mServiceState=" + mServiceState[i]);
+ pw.println(" mSignalStrength=" + mSignalStrength[i]);
+ pw.println(" mMessageWaiting=" + mMessageWaiting[i]);
+ pw.println(" mCallForwarding=" + mCallForwarding[i]);
+ pw.println(" mDataActivity=" + mDataActivity[i]);
+ pw.println(" mDataConnectionState=" + mDataConnectionState[i]);
+ pw.println(" mDataConnectionPossible=" + mDataConnectionPossible[i]);
+ pw.println(" mDataConnectionReason=" + mDataConnectionReason[i]);
+ pw.println(" mDataConnectionApn=" + mDataConnectionApn[i]);
+ pw.println(" mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
+ pw.println(" mDataConnectionNetworkCapabilities=" +
+ mDataConnectionNetworkCapabilities[i]);
+ pw.println(" mCellLocation=" + mCellLocation[i]);
+ pw.println(" mCellInfo=" + mCellInfo.get(i));
+ }
pw.println(" mDefaultSubId=" + mDefaultSubId);
- pw.println(" mCellLocation=" + mCellLocation);
- pw.println(" mCellInfo=" + mCellInfo);
pw.println(" mDcRtInfo=" + mDcRtInfo);
pw.println("registrations: count=" + recordCount);
for (Record r : mRecords) {
pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
+ pw.println("is Legacy = " + r.isLegacyApp + " subId = " + r.subId);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 190e87c..db915e2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -76,6 +76,10 @@
@GuardedBy("mSessions")
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
+ /** Historical sessions kept around for debugging purposes */
+ @GuardedBy("mSessions")
+ private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
+
private RemoteCallbackList<IPackageInstallerObserver> mObservers = new RemoteCallbackList<>();
private static final FilenameFilter sStageFilter = new FilenameFilter() {
@@ -344,18 +348,29 @@
}
void dump(IndentingPrintWriter pw) {
- pw.println("Active install sessions:");
- pw.increaseIndent();
synchronized (mSessions) {
- final int N = mSessions.size();
+ pw.println("Active install sessions:");
+ pw.increaseIndent();
+ int N = mSessions.size();
for (int i = 0; i < N; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
session.dump(pw);
pw.println();
}
+ pw.println();
+ pw.decreaseIndent();
+
+ pw.println("Historical install sessions:");
+ pw.increaseIndent();
+ N = mHistoricalSessions.size();
+ for (int i = 0; i < N; i++) {
+ final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
+ session.dump(pw);
+ pw.println();
+ }
+ pw.println();
+ pw.decreaseIndent();
}
- pw.println();
- pw.decreaseIndent();
}
class Callback {
@@ -367,6 +382,7 @@
notifySessionFinished(session.sessionId, success);
synchronized (mSessions) {
mSessions.remove(session.sessionId);
+ mHistoricalSessions.put(session.sessionId, session);
}
writeSessionsAsync();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 31d9704..0e6a3f0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -65,6 +65,7 @@
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String TAG = "PackageInstaller";
+ private static final boolean LOGD = true;
// TODO: enforce INSTALL_ALLOW_TEST
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -435,35 +436,25 @@
*/
private void spliceExistingFilesIntoStage() throws PackageManagerException {
final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
- final File existingDir = new File(app.getBaseCodePath());
- try {
- linkTreeIgnoringExisting(existingDir, sessionStageDir);
- } catch (ErrnoException e) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed to splice into stage");
- }
- }
+ int n = 0;
+ final File[] oldFiles = new File(app.getCodePath()).listFiles();
+ if (!ArrayUtils.isEmpty(oldFiles)) {
+ for (File oldFile : oldFiles) {
+ if (!PackageParser.isApkFile(oldFile)) continue;
- /**
- * Recursively hard link all files from source directory tree to target.
- * When a file already exists in the target tree, it leaves that file
- * intact.
- */
- private void linkTreeIgnoringExisting(File sourceDir, File targetDir) throws ErrnoException {
- final File[] sourceContents = sourceDir.listFiles();
- if (ArrayUtils.isEmpty(sourceContents)) return;
-
- for (File sourceFile : sourceContents) {
- final File targetFile = new File(targetDir, sourceFile.getName());
-
- if (sourceFile.isDirectory()) {
- targetFile.mkdir();
- linkTreeIgnoringExisting(sourceFile, targetFile);
- } else {
- Libcore.os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+ final File newFile = new File(sessionStageDir, oldFile.getName());
+ try {
+ Os.link(oldFile.getAbsolutePath(), newFile.getAbsolutePath());
+ n++;
+ } catch (ErrnoException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to splice into stage", e);
+ }
}
}
+
+ if (LOGD) Slog.d(TAG, "Spliced " + n + " existing APKs into stage");
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0ad3a68..727cff0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10026,9 +10026,6 @@
}
}
- // Nuke any cached code
- deleteCodeCacheDirsLI(pkgName);
-
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
@@ -10066,6 +10063,7 @@
deletedPkg = false;
} else {
// Successfully deleted the old package. Now proceed with re-installation
+ deleteCodeCacheDirsLI(pkgName);
try {
final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
scanMode | SCAN_UPDATE_TIME, System.currentTimeMillis(), user, abiOverride);
@@ -10177,6 +10175,8 @@
}
// Successfully disabled the old package. Now proceed with re-installation
+ deleteCodeCacheDirsLI(packageName);
+
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index fb820f0..db834a4 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -44,9 +44,9 @@
public void onDestroyed(Connection c) {}
public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {}
public void onParentConnectionChanged(Connection c, Connection parent) {}
- public void onSetCallVideoProvider(Connection c, CallVideoProvider callVideoProvider) {}
- public void onSetAudioModeIsVoip(Connection c, boolean isVoip) {}
- public void onSetStatusHints(Connection c, StatusHints statusHints) {}
+ public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {}
+ public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
+ public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
}
public final class State {
@@ -321,7 +321,7 @@
public final void setCallVideoProvider(CallVideoProvider callVideoProvider) {
mCallVideoProvider = callVideoProvider;
for (Listener l : mListeners) {
- l.onSetCallVideoProvider(this, callVideoProvider);
+ l.onCallVideoProviderChanged(this, callVideoProvider);
}
}
@@ -415,7 +415,7 @@
public final void setAudioModeIsVoip(boolean isVoip) {
mAudioModeIsVoip = isVoip;
for (Listener l : mListeners) {
- l.onSetAudioModeIsVoip(this, isVoip);
+ l.onAudioModeIsVoipChanged(this, isVoip);
}
}
@@ -427,7 +427,7 @@
public final void setStatusHints(StatusHints statusHints) {
mStatusHints = statusHints;
for (Listener l : mListeners) {
- l.onSetStatusHints(this, statusHints);
+ l.onStatusHintsChanged(this, statusHints);
}
}
@@ -516,7 +516,6 @@
*/
protected void onPhoneAccountClicked() {}
-
private void addChild(Connection connection) {
Log.d(this, "adding child %s", connection);
mChildConnections.add(connection);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 178cee8..2a6804b 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -364,19 +364,19 @@
}
@Override
- public void onSetCallVideoProvider(Connection c, CallVideoProvider callVideoProvider) {
+ public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {
String id = mIdByConnection.get(c);
mAdapter.setCallVideoProvider(id, callVideoProvider);
}
@Override
- public void onSetAudioModeIsVoip(Connection c, boolean isVoip) {
+ public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {
String id = mIdByConnection.get(c);
mAdapter.setAudioModeIsVoip(id, isVoip);
}
@Override
- public void onSetStatusHints(Connection c, StatusHints statusHints) {
+ public void onStatusHintsChanged(Connection c, StatusHints statusHints) {
String id = mIdByConnection.get(c);
mAdapter.setStatusHints(id, statusHints);
}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index a94841f..b50c1d7 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -121,4 +121,83 @@
* wait for user confirmation before proceeding.
*/
public static final char DTMF_CHARACTER_WAIT = ';';
+
+ /**
+ * TTY (teletypewriter) mode is off.
+ *
+ * @hide
+ */
+ public static final int TTY_MODE_OFF = 0;
+
+ /**
+ * TTY (teletypewriter) mode is on. The speaker is off and the microphone is muted. The user
+ * will communicate with the remote party by sending and receiving text messages.
+ *
+ * @hide
+ */
+ public static final int TTY_MODE_FULL = 1;
+
+ /**
+ * TTY (teletypewriter) mode is in hearing carryover mode (HCO). The microphone is muted but the
+ * speaker is on. The user will communicate with the remote party by sending text messages and
+ * hearing an audible reply.
+ *
+ * @hide
+ */
+ public static final int TTY_MODE_HCO = 2;
+
+ /**
+ * TTY (teletypewriter) mode is in voice carryover mode (VCO). The speaker is off but the
+ * microphone is still on. User will communicate with the remote party by speaking and receiving
+ * text message replies.
+ *
+ * @hide
+ */
+ public static final int TTY_MODE_VCO = 3;
+
+ /**
+ * Broadcast intent action indicating that the current TTY mode has changed. An intent extra
+ * provides this state as an int.
+ * @see #EXTRA_CURRENT_TTY_MODE
+ *
+ * @hide
+ */
+ public static final String ACTION_CURRENT_TTY_MODE_CHANGED =
+ "android.telecomm.intent.action.CURRENT_TTY_MODE_CHANGED";
+
+ /**
+ * The lookup key for an int that indicates the current TTY mode.
+ * Valid modes are:
+ * - {@link #TTY_MODE_OFF}
+ * - {@link #TTY_MODE_FULL}
+ * - {@link #TTY_MODE_HCO}
+ * - {@link #TTY_MODE_VCO}
+ *
+ * @hide
+ */
+ public static final String EXTRA_CURRENT_TTY_MODE =
+ "android.telecomm.intent.extra.CURRENT_TTY_MODE";
+
+ /**
+ * Broadcast intent action indicating that the TTY preferred operating mode
+ * has changed. An intent extra provides the new mode as an int.
+ * @see #EXTRA_TTY_PREFERRED_MODE
+ *
+ * @hide
+ */
+ public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
+ "android.telecomm.intent.action.TTY_PREFERRED_MODE_CHANGED";
+
+ /**
+ * The lookup key for an int that indicates preferred TTY mode.
+ * Valid modes are:
+ * - {@link #TTY_MODE_OFF}
+ * - {@link #TTY_MODE_FULL}
+ * - {@link #TTY_MODE_HCO}
+ * - {@link #TTY_MODE_VCO}
+ *
+ * @hide
+ */
+ public static final String EXTRA_TTY_PREFERRED_MODE =
+ "android.telecomm.intent.extra.TTY_PREFERRED";
}
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index fcd2eba..8bf80bb 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -28,21 +28,9 @@
/**
* Provides access to Telecomm-related functionality.
* TODO(santoscordon): Move this all into PhoneManager.
- * @hide
*/
public class TelecommManager {
- /**
- * The extra used with an {@link android.content.Intent#ACTION_CALL} or
- * {@link android.content.Intent#ACTION_DIAL} {@code Intent} to specify a {@link PhoneAccount}
- * to use when making the call.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getParcelableExtra(String)}.
- */
- public static final String EXTRA_PHONE_ACCOUNT = "account";
-
private static final String TAG = "TelecommManager";
private static final String TELECOMM_SERVICE_NAME = "telecomm";
@@ -138,8 +126,6 @@
* Remove all Accounts for a given package from the system.
*
* @param packageName A package name that may have registered Accounts.
- *
- * @hide
*/
@SystemApi
public void clearAccounts(String packageName) {
@@ -254,6 +240,44 @@
}
}
+ /**
+ * Returns whether TTY is supported on this device.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isTtySupported() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().isTtySupported();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException attempting to get TTY supported state.", e);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the current TTY mode of the device. For TTY to be on the user must enable it in
+ * settings and have a wired headset plugged in. Valid modes are:
+ * - {@link android.telecomm.TelecommConstants#TTY_MODE_OFF}
+ * - {@link android.telecomm.TelecommConstants#TTY_MODE_FULL}
+ * - {@link android.telecomm.TelecommConstants#TTY_MODE_HCO}
+ * - {@link android.telecomm.TelecommConstants#TTY_MODE_VCO}
+ *
+ * @hide
+ */
+ public int getCurrentTtyMode() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().getCurrentTtyMode();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException attempting to get the current TTY mode.", e);
+ }
+ return TelecommConstants.TTY_MODE_OFF;
+ }
+
private ITelecommService getTelecommService() {
return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
}
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 3334385..43caa1e 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -101,4 +101,14 @@
* @see PhoneManager#handlePinMmi
*/
boolean handlePinMmi(String dialString);
+
+ /**
+ * @see TelecomManager#isTtySupported
+ */
+ boolean isTtySupported();
+
+ /**
+ * @see TelecomManager#getCurrentTtyMode
+ */
+ int getCurrentTtyMode();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index cf4cb89..7ad05ab 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.content.Context;
import android.net.DhcpInfo;
import android.net.wifi.ScanSettings;
@@ -82,7 +83,29 @@
* Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED
* @hide
*/
- public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
+ public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
+
+ /**
+ * Broadcast intent action indicating that the credential of a Wi-Fi network
+ * has been changed. One extra provides the ssid of the network. Another
+ * extra provides the event type, whether the credential is saved or forgot.
+ * @hide
+ */
+ @SystemApi
+ public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
+ "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
+ /** @hide */
+ @SystemApi
+ public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
+ /** @hide */
+ @SystemApi
+ public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+ /** @hide */
+ @SystemApi
+ public static final int WIFI_CREDENTIAL_SAVED = 0;
+ /** @hide */
+ @SystemApi
+ public static final int WIFI_CREDENTIAL_FORGOT = 1;
/**
* Broadcast intent action indicating that Wi-Fi has been enabled, disabled,