Merge "CEC: Allow no vendor-specific data for <Vendor Command With ID>" into lmp-mr1-dev
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 75411fe..27c1978 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5942,8 +5942,7 @@
      * @hide
      */
     public void addClickableRectsForAccessibility(List<RectF> outRects) {
-        if (isClickable() || isLongClickable()
-                || (mListenerInfo != null && mListenerInfo.mOnTouchListener != null)) {
+        if (isClickable() || isLongClickable()) {
             RectF bounds = new RectF();
             bounds.set(0, 0, getWidth(), getHeight());
             outRects.add(bounds);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 38cb4cd..3e4e965 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -40,7 +40,7 @@
 static const size_t EVENT_BUFFER_SIZE = 100;
 
 // Slight delay to give the UI time to push us a new frame before we replay
-static const int DISPATCH_FRAME_CALLBACKS_DELAY = 4;
+static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
 
 TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
 
@@ -209,16 +209,16 @@
     return latest;
 }
 
-void RenderThread::drainDisplayEventQueue(bool skipCallbacks) {
+void RenderThread::drainDisplayEventQueue() {
     ATRACE_CALL();
     nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
     if (vsyncEvent > 0) {
         mVsyncRequested = false;
-        mTimeLord.vsyncReceived(vsyncEvent);
-        if (!skipCallbacks && !mFrameCallbackTaskPending) {
+        if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
             ATRACE_NAME("queue mFrameCallbackTask");
             mFrameCallbackTaskPending = true;
-            queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
+            nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
+            queueAt(mFrameCallbackTask, runAt);
         }
     }
 }
@@ -230,8 +230,13 @@
     std::set<IFrameCallback*> callbacks;
     mFrameCallbacks.swap(callbacks);
 
-    for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
-        (*it)->doFrame();
+    if (callbacks.size()) {
+        // Assume one of them will probably animate again so preemptively
+        // request the next vsync in case it occurs mid-frame
+        requestVsync();
+        for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
+            (*it)->doFrame();
+        }
     }
 }
 
@@ -273,7 +278,7 @@
         }
 
         if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
-            drainDisplayEventQueue(true);
+            drainDisplayEventQueue();
             mFrameCallbacks.insert(
                     mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
             mPendingRegistrationFrameCallbacks.clear();
@@ -299,9 +304,8 @@
     mLooper->wake();
 }
 
-void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    task->mRunAt = now + milliseconds_to_nanoseconds(delayMs);
+void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) {
+    task->mRunAt = runAtNs;
     queue(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 4126d02..99c2e15 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -75,7 +75,7 @@
     // and will delete them after they are run
     ANDROID_API void queue(RenderTask* task);
     ANDROID_API void queueAtFront(RenderTask* task);
-    void queueDelayed(RenderTask* task, int delayMs);
+    void queueAt(RenderTask* task, nsecs_t runAtNs);
     void remove(RenderTask* task);
 
     // Mimics android.view.Choreographer
@@ -103,7 +103,7 @@
     void initThreadLocals();
     void initializeDisplayEventReceiver();
     static int displayEventReceiverCallback(int fd, int events, void* data);
-    void drainDisplayEventQueue(bool skipCallbacks = false);
+    void drainDisplayEventQueue();
     void dispatchFrameCallbacks();
     void requestVsync();
 
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index 9bd4eae..f187493 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -24,10 +24,12 @@
         , mFrameTimeNanos(0) {
 }
 
-void TimeLord::vsyncReceived(nsecs_t vsync) {
+bool TimeLord::vsyncReceived(nsecs_t vsync) {
     if (vsync > mFrameTimeNanos) {
         mFrameTimeNanos = vsync;
+        return true;
     }
+    return false;
 }
 
 nsecs_t TimeLord::computeFrameTimeMs() {
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 8b0372c..7c155d2 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -29,7 +29,8 @@
 class TimeLord {
 public:
     void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
-    void vsyncReceived(nsecs_t vsync);
+    // returns true if the vsync is newer, false if it was rejected for staleness
+    bool vsyncReceived(nsecs_t vsync);
     nsecs_t computeFrameTimeMs();
 
 private:
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 8a543ce..1c10422 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -3248,7 +3248,10 @@
 
         TelecomManager telecomManager =
                 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+
+        final long ident = Binder.clearCallingIdentity();
         IsInCall = telecomManager.isInCall();
+        Binder.restoreCallingIdentity(ident);
 
         return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
     }
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 4b9a929..7ea269b 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -69,12 +69,9 @@
     }
 
     public static MediaSessionLegacyHelper getHelper(Context context) {
-        if (DEBUG) {
-            Log.d(TAG, "Attempting to get helper with context " + context);
-        }
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new MediaSessionLegacyHelper(context);
+                sInstance = new MediaSessionLegacyHelper(context.getApplicationContext());
             }
         }
         return sInstance;
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 81c6da5..5eebf3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -426,6 +426,9 @@
             return;
         }
         List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
+        if (subscriptions == null) {
+            subscriptions = Collections.emptyList();
+        }
         // If there have been no relevant changes to any of the subscriptions, we can leave as is.
         if (hasCorrectMobileControllers(subscriptions)) {
             // Even if the controllers are correct, make sure we have the right no sims state.
@@ -500,10 +503,8 @@
     }
 
     private boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
-        if (allSubscriptions == null) {
-            // If null then the system doesn't know the subscriptions yet, instead just wait
-            // to update the MobileControllers until it knows the state.
-            return true;
+        if (allSubscriptions.size() != mMobileSignalControllers.size()) {
+            return false;
         }
         for (SubscriptionInfo info : allSubscriptions) {
             if (!mMobileSignalControllers.containsKey(info.getSubscriptionId())) {
@@ -812,7 +813,8 @@
 
     private final OnSubscriptionsChangedListener mSubscriptionListener =
             new OnSubscriptionsChangedListener() {
-        public void onSubscriptionInfoChanged() {
+        @Override
+        public void onSubscriptionsChanged() {
             updateMobileControllers();
         };
     };
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 788b5d3..b1f14a9 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1048,7 +1048,7 @@
             synchronized (nai) {
                 if (nai.created) {
                     NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
-                    if (nai.validated) {
+                    if (nai.lastValidated) {
                         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
                     } else {
                         nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
@@ -1954,17 +1954,18 @@
                     NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
                     if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
                         boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                        nai.lastValidated = valid;
                         if (valid) {
                             if (DBG) log("Validated " + nai.name());
-                            if (!nai.validated) {
-                                nai.validated = true;
+                            if (!nai.everValidated) {
+                                nai.everValidated = true;
                                 rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
                                     ReapUnvalidatedNetworks.REAP);
                                 // If score has changed, rebroadcast to NetworkFactories. b/17726566
                                 sendUpdatedScoreToFactories(nai);
                             }
                         }
-                        updateInetCondition(nai, valid);
+                        updateInetCondition(nai);
                         // Let the NetworkAgent know the state of its network
                         nai.asyncChannel.sendMessage(
                                 android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS,
@@ -3984,7 +3985,7 @@
     private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, NascentState nascent,
             ReapUnvalidatedNetworks reapUnvalidatedNetworks) {
         if (!newNetwork.created) return;
-        if (nascent == NascentState.JUST_VALIDATED && !newNetwork.validated) {
+        if (nascent == NascentState.JUST_VALIDATED && !newNetwork.everValidated) {
             loge("ERROR: nascent network not validated.");
         }
         boolean keep = newNetwork.isVPN();
@@ -4054,7 +4055,7 @@
         }
         // Linger any networks that are no longer needed.
         for (NetworkAgentInfo nai : affectedNetworks) {
-            boolean teardown = !nai.isVPN() && nai.validated;
+            boolean teardown = !nai.isVPN() && nai.everValidated;
             for (int i = 0; i < nai.networkRequests.size() && teardown; i++) {
                 NetworkRequest nr = nai.networkRequests.valueAt(i);
                 try {
@@ -4096,7 +4097,7 @@
                     mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
                                               oldDefaultNetwork);
                 }
-                mDefaultInetConditionPublished = newNetwork.validated ? 100 : 0;
+                mDefaultInetConditionPublished = newNetwork.everValidated ? 100 : 0;
                 mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
                 notifyLockdownVpn(newNetwork);
             }
@@ -4139,7 +4140,7 @@
         }
         if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
             for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                if (!nai.created || nai.validated || nai.isVPN()) continue;
+                if (!nai.created || nai.everValidated || nai.isVPN()) continue;
                 boolean reap = true;
                 for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                     // If this Network is already the highest scoring Network for a request, or if
@@ -4200,14 +4201,14 @@
         }
     }
 
-    private void updateInetCondition(NetworkAgentInfo nai, boolean valid) {
+    private void updateInetCondition(NetworkAgentInfo nai) {
         // Don't bother updating until we've graduated to validated at least once.
-        if (!nai.validated) return;
+        if (!nai.everValidated) return;
         // For now only update icons for default connection.
         // TODO: Update WiFi and cellular icons separately. b/17237507
         if (!isDefaultNetwork(nai)) return;
 
-        int newInetCondition = valid ? 100 : 0;
+        int newInetCondition = nai.lastValidated ? 100 : 0;
         // Don't repeat publish.
         if (newInetCondition == mDefaultInetConditionPublished) return;
 
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 92fbc1e..eb89f21 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -25,7 +25,11 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
+
+import libcore.io.IoUtils;
+
 import com.android.internal.util.XmlUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -60,6 +64,10 @@
     // system configuration files.
     final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
 
+    // These are the features which this device doesn't support; the OEM
+    // partition uses these to opt-out of features from the system image.
+    final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
+
     public static final class PermissionEntry {
         public final String name;
         public int[] gids;
@@ -145,9 +153,11 @@
         }
 
         // Iterate over the files in the directory and scan .xml files
+        File platformFile = null;
         for (File f : libraryDir.listFiles()) {
             // We'll read platform.xml last
             if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+                platformFile = f;
                 continue;
             }
 
@@ -163,10 +173,10 @@
             readPermissionsFromXml(f, onlyFeatures);
         }
 
-        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
-        final File permFile = new File(Environment.getRootDirectory(),
-                "etc/permissions/platform.xml");
-        readPermissionsFromXml(permFile, onlyFeatures);
+        // Read platform permissions last so it will take precedence
+        if (platformFile != null) {
+            readPermissionsFromXml(platformFile, onlyFeatures);
+        }
     }
 
     private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
@@ -298,7 +308,18 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("allow-in-power-save".equals(name)) {
+                } else if ("unavailable-feature".equals(name)) {
+                    String fname = parser.getAttributeValue(null, "name");
+                    if (fname == null) {
+                        Slog.w(TAG, "<unavailable-feature> without name at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mUnavailableFeatures.add(fname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
                     String pkgname = parser.getAttributeValue(null, "package");
                     if (pkgname == null) {
                         Slog.w(TAG, "<allow-in-power-save> without package at "
@@ -309,7 +330,7 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("fixed-ime-app".equals(name)) {
+                } else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
                     String pkgname = parser.getAttributeValue(null, "package");
                     if (pkgname == null) {
                         Slog.w(TAG, "<fixed-ime-app> without package at "
@@ -324,13 +345,19 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
                 }
-
             }
-            permReader.close();
         } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Got execption parsing permissions.", e);
+            Slog.w(TAG, "Got exception parsing permissions.", e);
         } catch (IOException e) {
-            Slog.w(TAG, "Got execption parsing permissions.", e);
+            Slog.w(TAG, "Got exception parsing permissions.", e);
+        } finally {
+            IoUtils.closeQuietly(permReader);
+        }
+
+        for (String fname : mUnavailableFeatures) {
+            if (mAvailableFeatures.remove(fname) != null) {
+                Slog.d(TAG, "Removed unavailable feature " + fname);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 779a834..f3e0bbc 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -53,7 +53,14 @@
     // default NetworkRequest in which case validation will not be attempted.
     // NOTE: This is a sticky bit; once set it is never cleared even if future validation attempts
     // fail.
-    public boolean validated;
+    public boolean everValidated;
+
+    // The result of the last validation attempt on this network (true if validated, false if not).
+    // This bit exists only because we never unvalidate a network once it's been validated, and that
+    // is because the network scoring and revalidation code does not (may not?) deal properly with
+    // networks becoming unvalidated.
+    // TODO: Fix the network scoring code, remove this, and rename everValidated to validated.
+    public boolean lastValidated;
 
     // This represents the last score received from the NetworkAgent.
     private int currentScore;
@@ -89,7 +96,8 @@
         networkMonitor = new NetworkMonitor(context, handler, this, defaultRequest);
         networkMisc = misc;
         created = false;
-        validated = false;
+        everValidated = false;
+        lastValidated = false;
     }
 
     public void addRequest(NetworkRequest networkRequest) {
@@ -114,7 +122,7 @@
 
         int score = currentScore;
 
-        if (!validated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
+        if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
         if (score < 0) score = 0;
 
         if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;
@@ -142,8 +150,9 @@
         return "NetworkAgentInfo{ ni{" + networkInfo + "}  network{" +
                 network + "}  lp{" +
                 linkProperties + "}  nc{" +
-                networkCapabilities + "}  Score{" + getCurrentScore() + "} " +
-                "validated{" + validated + "} created{" + created + "} " +
+                networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
+                "everValidated{" + everValidated + "}  lastValidated{" + lastValidated + "}  " +
+                "created{" + created + "}  " +
                 "explicitlySelected{" + networkMisc.explicitlySelected + "} }";
     }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 2c61d2c..1fba7bb 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -257,41 +257,59 @@
             if (mUseMasterVolume) {
                 // If this device only uses master volume and playback is local
                 // just adjust the master volume and return.
+                boolean isMasterMute = mAudioManager.isMasterMute();
                 if (isMute) {
-                    mAudioManagerInternal.setMasterMuteForUid(!mAudioManager.isMasterMute(),
+                    mAudioManagerInternal.setMasterMuteForUid(!isMasterMute,
                             flags, packageName, mICallback, uid);
                 } else {
                     mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
                             uid);
+                    if (isMasterMute) {
+                        mAudioManagerInternal.setMasterMuteForUid(false,
+                                flags, packageName, mICallback, uid);
+                    }
                 }
                 return;
             }
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
+            boolean isStreamMute = mAudioManager.isStreamMute(stream);
             if (useSuggested) {
                 if (AudioSystem.isStreamActive(stream, 0)) {
                     if (isMute) {
-                        mAudioManager.setStreamMute(stream, !mAudioManager.isStreamMute(stream));
+                        mAudioManager.setStreamMute(stream, !isStreamMute);
                     } else {
                         mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
                                 flags, packageName, uid);
+                        if (isStreamMute) {
+                            mAudioManager.setStreamMute(stream, false);
+                        }
                     }
                 } else {
                     flags |= previousFlagPlaySound;
+                    isStreamMute =
+                            mAudioManager.isStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE);
                     if (isMute) {
                         mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                                !mAudioManager.isStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE));
+                                !isStreamMute);
                     } else {
                         mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
                                 AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
                                 uid);
+                        if (isStreamMute) {
+                            mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
+                                    false);
+                        }
                     }
                 }
             } else {
                 if (isMute) {
-                    mAudioManager.setStreamMute(stream, !mAudioManager.isStreamMute(stream));
+                    mAudioManager.setStreamMute(stream, !isStreamMute);
                 } else {
                     mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
                             packageName, uid);
+                    if (isStreamMute) {
+                        mAudioManager.setStreamMute(stream, false);
+                    }
                 }
             }
         } else {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b4ec607..82be1bb 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -829,21 +829,27 @@
                     return;
                 }
                 try {
+                    String packageName = getContext().getOpPackageName();
                     if (mUseMasterVolume) {
+                        boolean isMasterMute = mAudioService.isMasterMute();
                         if (direction == MediaSessionManager.DIRECTION_MUTE) {
-                            mAudioService.setMasterMute(!mAudioService.isMasterMute(), flags,
-                                    getContext().getOpPackageName(), mICallback);
+                            mAudioService.setMasterMute(!isMasterMute, flags, packageName, mICallback);
                         } else {
-                            mAudioService.adjustMasterVolume(direction, flags,
-                                    getContext().getOpPackageName());
+                            mAudioService.adjustMasterVolume(direction, flags, packageName);
+                            if (isMasterMute) {
+                                mAudioService.setMasterMute(false, flags, packageName, mICallback);
+                            }
                         }
                     } else {
+                        boolean isStreamMute = mAudioService.isStreamMute(suggestedStream);
                         if (direction == MediaSessionManager.DIRECTION_MUTE) {
-                            mAudioService.setStreamMute(suggestedStream,
-                                    !mAudioService.isStreamMute(suggestedStream), mICallback);
+                            mAudioService.setStreamMute(suggestedStream, !isStreamMute, mICallback);
                         } else {
                             mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
-                                    flags, getContext().getOpPackageName());
+                                    flags, packageName);
+                            if (isStreamMute) {
+                                mAudioService.setStreamMute(suggestedStream, false, mICallback);
+                            }
                         }
                     }
                 } catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index 734fc68..d10a7ea 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -136,16 +136,59 @@
     };
 
     public static int getRafFromNetworkType(int type) {
-        // TODO map from RILConstants.NETWORK_TYPE_* to RAF_*
+        final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
+        final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
+        final int CDMA = RAF_IS95A | RAF_IS95B | RAF_1xRTT;
+        final int EVDO = RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B;
+        final int WCDMA = HS | RAF_UMTS;
+
+        int raf;
+
         switch (type) {
             case RILConstants.NETWORK_MODE_WCDMA_PREF:
-            case RILConstants.NETWORK_MODE_GSM_UMTS:
-                return RAF_UMTS | RAF_GSM;
+                raf = GSM | WCDMA;
+                break;
             case RILConstants.NETWORK_MODE_GSM_ONLY:
-                return RAF_GSM;
+                raf = GSM;
+                break;
+            case RILConstants.NETWORK_MODE_WCDMA_ONLY:
+                raf = WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_GSM_UMTS:
+                raf = GSM | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_CDMA:
+                raf = CDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
+                raf = RAF_LTE | CDMA | EVDO;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
+                raf = RAF_LTE | GSM | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
+                raf = RAF_LTE | CDMA | EVDO | GSM | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_ONLY:
+                raf = RAF_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_WCDMA:
+                raf = RAF_LTE | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
+                raf = CDMA;
+                break;
+            case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
+                raf = EVDO;
+                break;
+            case RILConstants.NETWORK_MODE_GLOBAL:
+                raf = GSM | WCDMA | CDMA | EVDO;
+                break;
             default:
-                return RAF_UNKNOWN;
+                raf = RAF_UNKNOWN;
+                break;
         }
+        return raf;
     }
 }