diff options
82 files changed, 2074 insertions, 938 deletions
diff --git a/Android.mk b/Android.mk index c2910fd04172..be7e055b2ec8 100644 --- a/Android.mk +++ b/Android.mk @@ -155,6 +155,7 @@ LOCAL_SRC_FILES += \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/INetworkPolicyListener.aidl \ core/java/android/net/INetworkPolicyManager.aidl \ + core/java/android/net/INetworkScoreService.aidl \ core/java/android/net/INetworkStatsService.aidl \ core/java/android/net/INetworkStatsSession.aidl \ core/java/android/net/nsd/INsdManager.aidl \ diff --git a/api/current.txt b/api/current.txt index 3573e6d3fe5f..4e2a3bb5f981 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27974,7 +27974,6 @@ package android.tv { public static final class TvInputManager.Session { method public void release(); - method public void setSurface(android.view.Surface); method public void setVolume(float); method public void tune(android.net.Uri); } @@ -27996,12 +27995,22 @@ package android.tv { field public static final java.lang.String SERVICE_INTERFACE = "android.tv.TvInputService"; } - public static abstract class TvInputService.TvInputSessionImpl { + public abstract class TvInputService.TvInputSessionImpl { ctor public TvInputService.TvInputSessionImpl(); + method public android.view.View onCreateOverlayView(); method public abstract void onRelease(); method public abstract boolean onSetSurface(android.view.Surface); method public abstract void onSetVolume(float); method public abstract boolean onTune(android.net.Uri); + method public void setOverlayViewEnabled(boolean); + } + + public class TvView extends android.view.SurfaceView { + ctor public TvView(android.content.Context); + ctor public TvView(android.content.Context, android.util.AttributeSet); + ctor public TvView(android.content.Context, android.util.AttributeSet, int); + method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback); + method public void unbindTvInput(); } } diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 51cb12aa8bdf..edf21dde82e2 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -33,17 +33,20 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.TextureView.SurfaceTextureListener; -import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import dalvik.system.CloseGuard; + +import java.lang.ref.WeakReference; /** @hide */ public class ActivityView extends ViewGroup { - private final String TAG = "ActivityView"; - private final boolean DEBUG = false; + private static final String TAG = "ActivityView"; + private static final boolean DEBUG = false; + DisplayMetrics mMetrics; private final TextureView mTextureView; - private IActivityContainer mActivityContainer; + private ActivityContainerWrapper mActivityContainer; private Activity mActivity; private int mWidth; private int mHeight; @@ -75,68 +78,33 @@ public class ActivityView extends ViewGroup { throw new IllegalStateException("The ActivityView's Context is not an Activity."); } - mTextureView = new TextureView(context); - mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); - addView(mTextureView); - if (DEBUG) Log.v(TAG, "ctor()"); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - mTextureView.layout(0, 0, r - l, b - t); - } - - @Override - protected void onAttachedToWindow() { - if (DEBUG) Log.v(TAG, "onAttachedToWindow()"); - super.onAttachedToWindow(); try { - final IBinder token = mActivity.getActivityToken(); - mActivityContainer = ActivityManagerNative.getDefault().createActivityContainer(token, - new ActivityContainerCallback()); + mActivityContainer = new ActivityContainerWrapper( + ActivityManagerNative.getDefault().createActivityContainer( + mActivity.getActivityToken(), new ActivityContainerCallback(this))); } catch (RemoteException e) { - throw new IllegalStateException("ActivityView: Unable to create ActivityContainer. " + throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e); } - attachToSurfaceWhenReady(); - } + mTextureView = new TextureView(context); + mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); + addView(mTextureView); - @Override - protected void onDetachedFromWindow() { - if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer); - super.onDetachedFromWindow(); - if (mActivityContainer != null) { - detach(); - try { - ActivityManagerNative.getDefault().deleteActivityContainer(mActivityContainer); - } catch (RemoteException e) { - } - mActivityContainer = null; - } + WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); + mMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics(mMetrics); + + if (DEBUG) Log.v(TAG, "ctor()"); } @Override - protected void onWindowVisibilityChanged(int visibility) { - if (DEBUG) Log.v(TAG, "onWindowVisibilityChanged(): visibility=" + visibility); - super.onWindowVisibilityChanged(visibility); - switch (visibility) { - case View.VISIBLE: - attachToSurfaceWhenReady(); - break; - case View.INVISIBLE: - break; - case View.GONE: - break; - } + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mTextureView.layout(0, 0, r - l, b - t); } private boolean injectInputEvent(InputEvent event) { - try { - return mActivityContainer != null && mActivityContainer.injectEvent(event); - } catch (RemoteException e) { - return false; - } + return mActivityContainer != null && mActivityContainer.injectEvent(event); } @Override @@ -154,40 +122,45 @@ public class ActivityView extends ViewGroup { return super.onGenericMotionEvent(event); } + @Override + public void onAttachedToWindow() { + if (DEBUG) Log.v(TAG, "onAttachedToWindow(): mActivityContainer=" + mActivityContainer + + " mSurface=" + mSurface); + } + + @Override + public void onDetachedFromWindow() { + if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer + + " mSurface=" + mSurface); + } + public boolean isAttachedToDisplay() { return mSurface != null; } public void startActivity(Intent intent) { + if (mActivityContainer == null) { + throw new IllegalStateException("Attempt to call startActivity after release"); + } if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); if (mSurface != null) { - try { - mActivityContainer.startActivity(intent); - } catch (RemoteException e) { - throw new IllegalStateException("ActivityView: Unable to startActivity. " + e); - } + mActivityContainer.startActivity(intent); } else { mQueuedIntent = intent; mQueuedPendingIntent = null; } } - private void startActivityIntentSender(IIntentSender iIntentSender) { - try { - mActivityContainer.startActivityIntentSender(iIntentSender); - } catch (RemoteException e) { - throw new IllegalStateException( - "ActivityView: Unable to startActivity from IntentSender. " + e); - } - } - public void startActivity(IntentSender intentSender) { + if (mActivityContainer == null) { + throw new IllegalStateException("Attempt to call startActivity after release"); + } if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = intentSender.getTarget(); if (mSurface != null) { - startActivityIntentSender(iIntentSender); + mActivityContainer.startActivityIntentSender(iIntentSender); } else { mQueuedPendingIntent = iIntentSender; mQueuedIntent = null; @@ -195,84 +168,102 @@ public class ActivityView extends ViewGroup { } public void startActivity(PendingIntent pendingIntent) { + if (mActivityContainer == null) { + throw new IllegalStateException("Attempt to call startActivity after release"); + } if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = pendingIntent.getTarget(); if (mSurface != null) { - startActivityIntentSender(iIntentSender); + mActivityContainer.startActivityIntentSender(iIntentSender); } else { mQueuedPendingIntent = iIntentSender; mQueuedIntent = null; } } + public void release() { + if (DEBUG) Log.v(TAG, "release() mActivityContainer=" + mActivityContainer + + " mSurface=" + mSurface); + if (mActivityContainer == null) { + Log.e(TAG, "Duplicate call to release"); + return; + } + mActivityContainer.release(); + mActivityContainer = null; + + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + + mTextureView.setSurfaceTextureListener(null); + } + private void attachToSurfaceWhenReady() { final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); - if (mActivityContainer == null || surfaceTexture == null || mSurface != null) { + if (surfaceTexture == null || mSurface != null) { // Either not ready to attach, or already attached. return; } - WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); - DisplayMetrics metrics = new DisplayMetrics(); - wm.getDefaultDisplay().getMetrics(metrics); - mSurface = new Surface(surfaceTexture); try { - mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi); + mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi); } catch (RemoteException e) { mSurface.release(); mSurface = null; - throw new IllegalStateException( - "ActivityView: Unable to create ActivityContainer. " + e); + throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e); } if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null || mQueuedPendingIntent != null ? "" : "no") + " queued intent"); if (mQueuedIntent != null) { - startActivity(mQueuedIntent); + mActivityContainer.startActivity(mQueuedIntent); mQueuedIntent = null; } else if (mQueuedPendingIntent != null) { - startActivityIntentSender(mQueuedPendingIntent); + mActivityContainer.startActivityIntentSender(mQueuedPendingIntent); mQueuedPendingIntent = null; } } - private void detach() { - if (DEBUG) Log.d(TAG, "detach: attached=" + isAttachedToDisplay()); - if (mSurface != null) { - try { - mActivityContainer.detachFromDisplay(); - } catch (RemoteException e) { - } - mSurface.release(); - mSurface = null; - } - } - private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { + if (mActivityContainer == null) { + return; + } if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height=" + height); mWidth = width; mHeight = height; - if (mActivityContainer != null) { - attachToSurfaceWhenReady(); - } + attachToSurfaceWhenReady(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { + if (mActivityContainer == null) { + return; + } if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { + if (mActivityContainer == null) { + return true; + } if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed"); - detach(); + mSurface.release(); + mSurface = null; + try { + mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi); + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to set surface of ActivityContainer. " + e); + } return true; } @@ -283,13 +274,95 @@ public class ActivityView extends ViewGroup { } - private class ActivityContainerCallback extends IActivityContainerCallback.Stub { + private static class ActivityContainerCallback extends IActivityContainerCallback.Stub { + private final WeakReference<ActivityView> mActivityViewWeakReference; + + ActivityContainerCallback(ActivityView activityView) { + mActivityViewWeakReference = new WeakReference<ActivityView>(activityView); + } + @Override public void setVisible(IBinder container, boolean visible) { - if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible); - if (visible) { - } else { + if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible + + " ActivityView=" + mActivityViewWeakReference.get()); + } + } + + private static class ActivityContainerWrapper { + private final IActivityContainer mIActivityContainer; + private final CloseGuard mGuard = CloseGuard.get(); + + ActivityContainerWrapper(IActivityContainer container) { + mIActivityContainer = container; + mGuard.open("release"); + } + + void attachToDisplay(int displayId) { + try { + mIActivityContainer.attachToDisplay(displayId); + } catch (RemoteException e) { + } + } + + void setSurface(Surface surface, int width, int height, int density) + throws RemoteException { + mIActivityContainer.setSurface(surface, width, height, density); + } + + int startActivity(Intent intent) { + try { + return mIActivityContainer.startActivity(intent); + } catch (RemoteException e) { + throw new RuntimeException("ActivityView: Unable to startActivity. " + e); + } + } + + int startActivityIntentSender(IIntentSender intentSender) { + try { + return mIActivityContainer.startActivityIntentSender(intentSender); + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to startActivity from IntentSender. " + e); + } + } + + int getDisplayId() { + try { + return mIActivityContainer.getDisplayId(); + } catch (RemoteException e) { + return -1; } } + + boolean injectEvent(InputEvent event) { + try { + return mIActivityContainer.injectEvent(event); + } catch (RemoteException e) { + return false; + } + } + + void release() { + if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called"); + try { + mIActivityContainer.release(); + mGuard.close(); + } catch (RemoteException e) { + } + } + + @Override + protected void finalize() throws Throwable { + if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: finalize called"); + try { + if (mGuard != null) { + mGuard.warnIfOpen(); + release(); + } + } finally { + super.finalize(); + } + } + } } diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl index 5b80e06e1611..cc3b10cfa88f 100644 --- a/core/java/android/app/IActivityContainer.aidl +++ b/core/java/android/app/IActivityContainer.aidl @@ -26,10 +26,10 @@ import android.view.Surface; /** @hide */ interface IActivityContainer { void attachToDisplay(int displayId); - void attachToSurface(in Surface surface, int width, int height, int density); - void detachFromDisplay(); + void setSurface(in Surface surface, int width, int height, int density); int startActivity(in Intent intent); int startActivityIntentSender(in IIntentSender intentSender); int getDisplayId(); boolean injectEvent(in InputEvent event); + void release(); } diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl new file mode 100644 index 000000000000..a72d9a024976 --- /dev/null +++ b/core/java/android/net/INetworkScoreService.aidl @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.ScoredNetwork; + +/** + * A service for updating network scores from a network scorer application. + * @hide + */ +interface INetworkScoreService +{ + /** + * Update scores. + * @return whether the update was successful. + * @throws SecurityException if the caller is not the current active scorer. + */ + boolean updateScores(in ScoredNetwork[] networks); + + /** + * Clear all scores. + * @return whether the clear was successful. + * @throws SecurityException if the caller is neither the current active scorer nor the scorer + * manager. + */ + boolean clearScores(); + + /** + * Set the active scorer and clear existing scores. + * @param packageName the package name of the new scorer to use. + * @return true if the operation succeeded, or false if the new package is not a valid scorer. + * @throws SecurityException if the caller is not the scorer manager. + */ + boolean setActiveScorer(in String packageName); +} diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java index cc3ad3ea6374..bc1965874f5e 100644 --- a/core/java/android/net/NetworkKey.java +++ b/core/java/android/net/NetworkKey.java @@ -19,11 +19,19 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + /** * Information which identifies a specific network. * * @hide */ +// NOTE: Ideally, we would abstract away the details of what identifies a network of a specific +// type, so that all networks appear the same and can be scored without concern to the network type +// itself. However, because no such cross-type identifier currently exists in the Android framework, +// and because systems might obtain information about networks from sources other than Android +// devices, we need to provide identifying details about each specific network type (wifi, cell, +// etc.) so that clients can pull out these details depending on the type of network. public class NetworkKey implements Parcelable { /** A wifi network, for which {@link #wifiKey} will be populated. */ @@ -79,6 +87,21 @@ public class NetworkKey implements Parcelable { } @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NetworkKey that = (NetworkKey) o; + + return type == that.type && Objects.equals(wifiKey, that.wifiKey); + } + + @Override + public int hashCode() { + return Objects.hash(type, wifiKey); + } + + @Override public String toString() { switch (type) { case TYPE_WIFI: diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java index 343054712c7b..5e61613f89bb 100644 --- a/core/java/android/net/NetworkScoreManager.java +++ b/core/java/android/net/NetworkScoreManager.java @@ -19,6 +19,9 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; /** * Class that manages communication between network subsystems and a network scorer. @@ -40,7 +43,7 @@ import android.content.Context; * <p>The system keeps track of a default scorer application; at any time, only this application * will receive {@link #ACTION_SCORE_NETWORKS} broadcasts and will be permitted to call * {@link #updateScores}. Applications may determine the current default scorer with - * {@link #getDefaultScorerPackage()} and request to change the default scorer by sending an + * {@link #getActiveScorerPackage()} and request to change the default scorer by sending an * {@link #ACTION_CHANGE_DEFAULT} broadcast with another scorer. * * @hide @@ -81,38 +84,82 @@ public class NetworkScoreManager { public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; private final Context mContext; + private final INetworkScoreService mService; /** @hide */ public NetworkScoreManager(Context context) { mContext = context; + IBinder iBinder = ServiceManager.getService(Context.NETWORK_SCORE_SERVICE); + mService = INetworkScoreService.Stub.asInterface(iBinder); } /** - * Obtain the package name of the current default network scorer. + * Obtain the package name of the current active network scorer. * - * At any time, only one scorer application will receive {@link #ACTION_SCORE_NETWORKS} + * <p>At any time, only one scorer application will receive {@link #ACTION_SCORE_NETWORKS} * broadcasts and be allowed to call {@link #updateScores}. Applications may use this method to * determine the current scorer and offer the user the ability to select a different scorer via * the {@link #ACTION_CHANGE_DEFAULT} intent. - * @return the full package name of the current default scorer, or null if there is no active + * @return the full package name of the current active scorer, or null if there is no active * scorer. */ - public String getDefaultScorerPackage() { - // TODO: Implement. - return null; + public String getActiveScorerPackage() { + return NetworkScorerAppManager.getActiveScorer(mContext); } /** * Update network scores. * - * This may be called at any time to re-score active networks. Scores will generally be updated - * quickly, but if this method is called too frequently, the scores may be held and applied at - * a later time. + * <p>This may be called at any time to re-score active networks. Scores will generally be + * updated quickly, but if this method is called too frequently, the scores may be held and + * applied at a later time. * * @param networks the networks which have been scored by the scorer. - * @throws SecurityException if the caller is not the default scorer. + * @return whether the update was successful. + * @throws SecurityException if the caller is not the active scorer. */ - public void updateScores(ScoredNetwork[] networks) throws SecurityException { - // TODO: Implement. + public boolean updateScores(ScoredNetwork[] networks) throws SecurityException { + try { + return mService.updateScores(networks); + } catch (RemoteException e) { + return false; + } + } + + /** + * Clear network scores. + * + * <p>Should be called when all scores need to be invalidated, i.e. because the scoring + * algorithm has changed and old scores can no longer be compared to future scores. + * + * <p>Note that scores will be cleared automatically when the active scorer changes, as scores + * from one scorer cannot be compared to those from another scorer. + * + * @return whether the clear was successful. + * @throws SecurityException if the caller is not the active scorer or privileged. + */ + public boolean clearScores() throws SecurityException { + try { + return mService.clearScores(); + } catch (RemoteException e) { + return false; + } + } + + /** + * Set the active scorer to a new package and clear existing scores. + * + * @return true if the operation succeeded, or false if the new package is not a valid scorer. + * @throws SecurityException if the caller does not hold the + * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating that + * it can manage scorer applications. + * @hide + */ + public boolean setActiveScorer(String packageName) throws SecurityException { + try { + return mService.setActiveScorer(packageName); + } catch (RemoteException e) { + return false; + } } } diff --git a/core/java/android/net/NetworkScorerApplication.java b/core/java/android/net/NetworkScorerAppManager.java index b137ad31ebf0..726208afc87e 100644 --- a/core/java/android/net/NetworkScorerApplication.java +++ b/core/java/android/net/NetworkScorerAppManager.java @@ -26,6 +26,7 @@ import android.content.pm.ResolveInfo; import android.provider.Settings; import android.provider.Settings.Global; import android.text.TextUtils; +import android.util.Log; import java.util.ArrayList; import java.util.Collection; @@ -36,13 +37,14 @@ import java.util.List; * * @hide */ -public final class NetworkScorerApplication { +public final class NetworkScorerAppManager { + private static final String TAG = "NetworkScorerAppManager"; private static final Intent SCORE_INTENT = new Intent(NetworkScoreManager.ACTION_SCORE_NETWORKS); /** This class cannot be instantiated. */ - private NetworkScorerApplication() {} + private NetworkScorerAppManager() {} /** * Returns the list of available scorer app package names. @@ -111,30 +113,38 @@ public final class NetworkScorerApplication { * @param context the context of the calling application * @param packageName the packageName of the new scorer to use. If null, scoring will be * disabled. Otherwise, the scorer will only be set if it is a valid scorer application. + * @return true if the scorer was changed, or false if the package is not a valid scorer. */ - public static void setActiveScorer(Context context, String packageName) { + public static boolean setActiveScorer(Context context, String packageName) { String oldPackageName = Settings.Global.getString(context.getContentResolver(), Settings.Global.NETWORK_SCORER_APP); if (TextUtils.equals(oldPackageName, packageName)) { // No change. - return; + return true; } + Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName); + if (packageName == null) { Settings.Global.putString(context.getContentResolver(), Global.NETWORK_SCORER_APP, null); + return true; } else { // We only make the change if the new package is valid. Collection<String> applications = getAllValidScorers(context); if (isPackageValidScorer(applications, packageName)) { Settings.Global.putString(context.getContentResolver(), Settings.Global.NETWORK_SCORER_APP, packageName); + return true; + } else { + Log.w(TAG, "Requested network scorer is not valid: " + packageName); + return false; } } } /** Determine whether the application with the given UID is the enabled scorer. */ - public static boolean isCallerDefaultScorer(Context context, int callingUid) { + public static boolean isCallerActiveScorer(Context context, int callingUid) { String defaultApp = getActiveScorer(context); if (defaultApp == null) { return false; diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java index 7af7998f2650..33e81c257e23 100644 --- a/core/java/android/net/RssiCurve.java +++ b/core/java/android/net/RssiCurve.java @@ -19,6 +19,9 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import java.util.Arrays; +import java.util.Objects; + /** * A curve defining the network score over a range of RSSI values. * @@ -94,6 +97,30 @@ public class RssiCurve implements Parcelable { out.writeByteArray(rssiBuckets); } + /** + * Determine if two RSSI curves are defined in the same way. + * + * <p>Note that two curves can be equivalent but defined differently, e.g. if one bucket in one + * curve is split into two buckets in another. For the purpose of this method, these curves are + * not considered equal to each other. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RssiCurve rssiCurve = (RssiCurve) o; + + return start == rssiCurve.start && + bucketWidth == rssiCurve.bucketWidth && + Arrays.equals(rssiBuckets, rssiCurve.rssiBuckets); + } + + @Override + public int hashCode() { + return Objects.hash(start, bucketWidth, rssiBuckets); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java index 8af3c3c42de9..790231399b4e 100644 --- a/core/java/android/net/ScoredNetwork.java +++ b/core/java/android/net/ScoredNetwork.java @@ -19,6 +19,8 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + /** * A network identifier along with a score for the quality of that network. * @@ -80,6 +82,22 @@ public class ScoredNetwork implements Parcelable { } @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ScoredNetwork that = (ScoredNetwork) o; + + return Objects.equals(networkKey, that.networkKey) && + Objects.equals(rssiCurve, that.rssiCurve); + } + + @Override + public int hashCode() { + return Objects.hash(networkKey, rssiCurve); + } + + @Override public String toString() { return "ScoredNetwork[key=" + networkKey + ",score=" + rssiCurve + "]"; } diff --git a/core/java/android/net/WifiKey.java b/core/java/android/net/WifiKey.java index ffcd85aa1b9a..9e92e89b9687 100644 --- a/core/java/android/net/WifiKey.java +++ b/core/java/android/net/WifiKey.java @@ -19,6 +19,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; import java.util.regex.Pattern; /** @@ -87,6 +88,21 @@ public class WifiKey implements Parcelable { } @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + WifiKey wifiKey = (WifiKey) o; + + return Objects.equals(ssid, wifiKey.ssid) && Objects.equals(bssid, wifiKey.bssid); + } + + @Override + public int hashCode() { + return Objects.hash(ssid, bssid); + } + + @Override public String toString() { return "WifiKey[SSID=" + ssid + ",BSSID=" + bssid + "]"; } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 426f21eae3df..e6406497cbf6 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2861,29 +2861,21 @@ public abstract class BatteryStats implements Parcelable { int oldTemp = -1; int oldVolt = -1; long lastTime = -1; + long firstTime = -1; - public void printNextItem(PrintWriter pw, HistoryItem rec, long now, boolean checkin, + public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin, boolean verbose) { if (!checkin) { pw.print(" "); - if (now >= 0) { - TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); - } else { - TimeUtils.formatDuration(rec.time, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); - } + TimeUtils.formatDuration(rec.time - baseTime, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); pw.print(" ("); pw.print(rec.numReadInts); pw.print(") "); } else { if (lastTime < 0) { - if (now >= 0) { - pw.print("@"); - pw.print(rec.time-now); - } else { - pw.print(rec.time); - } + pw.print(rec.time - baseTime); } else { - pw.print(rec.time-lastTime); + pw.print(rec.time - lastTime); } lastTime = rec.time; } @@ -3132,10 +3124,27 @@ public abstract class BatteryStats implements Parcelable { pw.println("):"); HistoryPrinter hprinter = new HistoryPrinter(); long lastTime = -1; + long baseTime = -1; + boolean printed = false; while (getNextHistoryLocked(rec)) { lastTime = rec.time; + if (baseTime < 0) { + baseTime = lastTime; + } if (rec.time >= histStart) { - hprinter.printNextItem(pw, rec, histStart >= 0 ? -1 : now, false, + if (histStart >= 0 && !printed) { + if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) { + printed = true; + } else if (rec.currentTime != 0) { + printed = true; + byte cmd = rec.cmd; + rec.cmd = HistoryItem.CMD_CURRENT_TIME; + hprinter.printNextItem(pw, rec, baseTime, false, + (flags&DUMP_VERBOSE) != 0); + rec.cmd = cmd; + } + } + hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0); } } @@ -3152,8 +3161,12 @@ public abstract class BatteryStats implements Parcelable { try { pw.println("Old battery History:"); HistoryPrinter hprinter = new HistoryPrinter(); + long baseTime = -1; while (getNextOldHistoryLocked(rec)) { - hprinter.printNextItem(pw, rec, now, false, (flags&DUMP_VERBOSE) != 0); + if (baseTime < 0) { + baseTime = rec.time; + } + hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0); } pw.println(); } finally { @@ -3226,20 +3239,42 @@ public abstract class BatteryStats implements Parcelable { pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); pw.print(HISTORY_STRING_POOL); pw.print(','); pw.print(i); - pw.print(','); - pw.print(getHistoryTagPoolString(i)); - pw.print(','); + pw.print(","); pw.print(getHistoryTagPoolUid(i)); + pw.print(",\""); + String str = getHistoryTagPoolString(i); + str = str.replace("\\", "\\\\"); + str = str.replace("\"", "\\\""); + pw.print(str); + pw.print("\""); pw.println(); } HistoryPrinter hprinter = new HistoryPrinter(); long lastTime = -1; + long baseTime = -1; + boolean printed = false; while (getNextHistoryLocked(rec)) { lastTime = rec.time; + if (baseTime < 0) { + baseTime = lastTime; + } if (rec.time >= histStart) { + if (histStart >= 0 && !printed) { + if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) { + printed = true; + } else if (rec.currentTime != 0) { + printed = true; + byte cmd = rec.cmd; + rec.cmd = HistoryItem.CMD_CURRENT_TIME; + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); + hprinter.printNextItem(pw, rec, baseTime, true, false); + rec.cmd = cmd; + } + } pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); pw.print(HISTORY_DATA); pw.print(','); - hprinter.printNextItem(pw, rec, histStart >= 0 ? -1 : now, true, false); + hprinter.printNextItem(pw, rec, baseTime, true, false); } } if (histStart >= 0) { diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl index a927dc9ee695..a4c99e450596 100644 --- a/core/java/android/tv/ITvInputManager.aidl +++ b/core/java/android/tv/ITvInputManager.aidl @@ -17,6 +17,7 @@ package android.tv; import android.content.ComponentName; +import android.graphics.Rect; import android.net.Uri; import android.tv.ITvInputClient; import android.tv.TvInputInfo; @@ -40,4 +41,9 @@ interface ITvInputManager { void setSurface(in IBinder sessionToken, in Surface surface, int userId); void setVolume(in IBinder sessionToken, float volume, int userId); void tune(in IBinder sessionToken, in Uri channelUri, int userId); + + void createOverlayView(in IBinder sessionToken, in IBinder windowToken, in Rect frame, + int userId); + void relayoutOverlayView(in IBinder sessionToken, in Rect frame, int userId); + void removeOverlayView(in IBinder sessionToken, int userId); } diff --git a/core/java/android/tv/ITvInputService.aidl b/core/java/android/tv/ITvInputService.aidl index d80f286d0e30..672784fc6dff 100644 --- a/core/java/android/tv/ITvInputService.aidl +++ b/core/java/android/tv/ITvInputService.aidl @@ -17,7 +17,6 @@ package android.tv; import android.tv.ITvInputServiceCallback; -import android.tv.ITvInputSession; import android.tv.ITvInputSessionCallback; /** diff --git a/core/java/android/tv/ITvInputSession.aidl b/core/java/android/tv/ITvInputSession.aidl index d379d2d96c28..32fee4babdbd 100644 --- a/core/java/android/tv/ITvInputSession.aidl +++ b/core/java/android/tv/ITvInputSession.aidl @@ -16,6 +16,7 @@ package android.tv; +import android.graphics.Rect; import android.net.Uri; import android.view.Surface; @@ -31,4 +32,8 @@ oneway interface ITvInputSession { // is to introduce some new concepts that will solve a number of problems in audio policy today. void setVolume(float volume); void tune(in Uri channelUri); + + void createOverlayView(in IBinder windowToken, in Rect frame); + void relayoutOverlayView(in Rect frame); + void removeOverlayView(); } diff --git a/core/java/android/tv/ITvInputSessionWrapper.java b/core/java/android/tv/ITvInputSessionWrapper.java index 66fe5e1e4bff..a6e0877cc914 100644 --- a/core/java/android/tv/ITvInputSessionWrapper.java +++ b/core/java/android/tv/ITvInputSessionWrapper.java @@ -17,13 +17,16 @@ package android.tv; import android.content.Context; +import android.graphics.Rect; import android.net.Uri; +import android.os.IBinder; import android.os.Message; import android.tv.TvInputService.TvInputSessionImpl; import android.util.Log; import android.view.Surface; import com.android.internal.os.HandlerCaller; +import com.android.internal.os.SomeArgs; /** * Implements the internal ITvInputSession interface to convert incoming calls on to it back to @@ -38,6 +41,9 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand private static final int DO_SET_SURFACE = 2; private static final int DO_SET_VOLUME = 3; private static final int DO_TUNE = 4; + private static final int DO_CREATE_OVERLAY_VIEW = 5; + private static final int DO_RELAYOUT_OVERLAY_VIEW = 6; + private static final int DO_REMOVE_OVERLAY_VIEW = 7; private TvInputSessionImpl mTvInputSession; private final HandlerCaller mCaller; @@ -71,6 +77,20 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mTvInputSession.tune((Uri) msg.obj); return; } + case DO_CREATE_OVERLAY_VIEW: { + SomeArgs args = (SomeArgs) msg.obj; + mTvInputSession.createOverlayView((IBinder) args.arg1, (Rect) args.arg2); + args.recycle(); + return; + } + case DO_RELAYOUT_OVERLAY_VIEW: { + mTvInputSession.relayoutOverlayView((Rect) msg.obj); + return; + } + case DO_REMOVE_OVERLAY_VIEW: { + mTvInputSession.removeOverlayView(true); + return; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); return; @@ -97,4 +117,20 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand public void tune(Uri channelUri) { mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TUNE, channelUri)); } + + @Override + public void createOverlayView(IBinder windowToken, Rect frame) { + mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_OVERLAY_VIEW, windowToken, + frame)); + } + + @Override + public void relayoutOverlayView(Rect frame) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RELAYOUT_OVERLAY_VIEW, frame)); + } + + @Override + public void removeOverlayView() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_OVERLAY_VIEW)); + } } diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java index 4cf2b3595fd5..05f0b9cf70ab 100644 --- a/core/java/android/tv/TvInputManager.java +++ b/core/java/android/tv/TvInputManager.java @@ -17,6 +17,7 @@ package android.tv; import android.content.ComponentName; +import android.graphics.Rect; import android.net.Uri; import android.os.Handler; import android.os.IBinder; @@ -24,6 +25,7 @@ import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import android.view.Surface; +import android.view.View; import java.util.ArrayList; import java.util.HashMap; @@ -320,8 +322,8 @@ public final class TvInputManager { /** The Session provides the per-session functionality of TV inputs. */ public static final class Session { private final ITvInputManager mService; - private final IBinder mToken; private final int mUserId; + private IBinder mToken; /** @hide */ private Session(ComponentName name, IBinder token, ITvInputManager service, int userId) { @@ -332,10 +334,16 @@ public final class TvInputManager { /** * Releases this session. + * + * @throws IllegalStateException if the session has been already released. */ public void release() { + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } try { mService.releaseSession(mToken, mUserId); + mToken = null; } catch (RemoteException e) { throw new RuntimeException(e); } @@ -345,8 +353,12 @@ public final class TvInputManager { * Sets the {@link android.view.Surface} for this session. * * @param surface A {@link android.view.Surface} used to render video. + * @throws IllegalStateException if the session has been already released. */ - public void setSurface(Surface surface) { + void setSurface(Surface surface) { + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } // surface can be null. try { mService.setSurface(mToken, surface, mUserId); @@ -360,8 +372,12 @@ public final class TvInputManager { * * @param volume A volume value between 0.0f to 1.0f. * @throws IllegalArgumentException if the volume value is out of range. + * @throws IllegalStateException if the session has been already released. */ public void setVolume(float volume) { + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } try { if (volume < 0.0f || volume > 1.0f) { throw new IllegalArgumentException("volume should be between 0.0f and 1.0f"); @@ -377,16 +393,90 @@ public final class TvInputManager { * * @param channelUri The URI of a channel. * @throws IllegalArgumentException if the argument is {@code null}. + * @throws IllegalStateException if the session has been already released. */ public void tune(Uri channelUri) { if (channelUri == null) { throw new IllegalArgumentException("channelUri cannot be null"); } + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } try { mService.tune(mToken, channelUri, mUserId); } catch (RemoteException e) { throw new RuntimeException(e); } } + + /** + * Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView} + * should be called whenever the layout of its containing view is changed. + * {@link #removeOverlayView()} should be called to remove the overlay view. + * Since a session can have only one overlay view, this method should be called only once + * or it can be called again after calling {@link #removeOverlayView()}. + * + * @param view A view playing TV. + * @param frame A position of the overlay view. + * @throws IllegalArgumentException if any of the arguments is {@code null}. + * @throws IllegalStateException if {@code view} is not attached to a window or + * if the session has been already released. + */ + void createOverlayView(View view, Rect frame) { + if (view == null) { + throw new IllegalArgumentException("view cannot be null"); + } + if (frame == null) { + throw new IllegalArgumentException("frame cannot be null"); + } + if (view.getWindowToken() == null) { + throw new IllegalStateException("view must be attached to a window"); + } + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } + try { + mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Relayouts the current overlay view. + * + * @param frame A new position of the overlay view. + * @throws IllegalArgumentException if the arguments is {@code null}. + * @throws IllegalStateException if the session has been already released. + */ + void relayoutOverlayView(Rect frame) { + if (frame == null) { + throw new IllegalArgumentException("frame cannot be null"); + } + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } + try { + mService.relayoutOverlayView(mToken, frame, mUserId); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Removes the current overlay view. + * + * @throws IllegalStateException if the session has been already released. + */ + void removeOverlayView() { + if (mToken == null) { + throw new IllegalStateException("the session has been already released"); + } + try { + mService.removeOverlayView(mToken, mUserId); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } } } diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java index d7f6c328a5aa..80eb40752228 100644 --- a/core/java/android/tv/TvInputService.java +++ b/core/java/android/tv/TvInputService.java @@ -18,7 +18,10 @@ package android.tv; import android.app.Service; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.net.Uri; import android.os.Handler; import android.os.IBinder; @@ -26,7 +29,10 @@ import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; +import android.view.Gravity; import android.view.Surface; +import android.view.View; +import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -125,7 +131,37 @@ public abstract class TvInputService extends Service { /** * Base class for derived classes to implement to provide {@link TvInputManager.Session}. */ - public abstract static class TvInputSessionImpl { + public abstract class TvInputSessionImpl { + private final WindowManager mWindowManager; + private WindowManager.LayoutParams mWindowParams; + private View mOverlayView; + private boolean mOverlayViewEnabled; + private IBinder mWindowToken; + private Rect mOverlayFrame; + + public TvInputSessionImpl() { + mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); + } + + public void setOverlayViewEnabled(final boolean enable) { + mHandler.post(new Runnable() { + @Override + public void run() { + if (enable == mOverlayViewEnabled) { + return; + } + mOverlayViewEnabled = enable; + if (enable) { + if (mWindowToken != null) { + createOverlayView(mWindowToken, mOverlayFrame); + } + } else { + removeOverlayView(false); + } + } + }); + } + /** * Called when the session is released. */ @@ -157,11 +193,22 @@ public abstract class TvInputService extends Service { public abstract boolean onTune(Uri channelUri); /** + * Called when an application requests to create an overlay view. Each session + * implementation can override this method and return its own view. + * + * @return a view attached to the overlay window + */ + public View onCreateOverlayView() { + return null; + } + + /** * This method is called when the application would like to stop using the current input * session. */ void release() { onRelease(); + removeOverlayView(true); } /** @@ -186,6 +233,87 @@ public abstract class TvInputService extends Service { onTune(channelUri); // TODO: Handle failure. } + + /** + * Creates an overlay view. This calls {@link onCreateOverlayView} to get + * a view to attach to the overlay window. + * + * @param windowToken A window token of an application. + * @param frame A position of the overlay view. + */ + void createOverlayView(IBinder windowToken, Rect frame) { + if (mOverlayView != null) { + mWindowManager.removeView(mOverlayView); + mOverlayView = null; + } + if (DEBUG) { + Log.d(TAG, "create overlay view(" + frame + ")"); + } + mWindowToken = windowToken; + mOverlayFrame = frame; + if (!mOverlayViewEnabled) { + return; + } + mOverlayView = onCreateOverlayView(); + if (mOverlayView == null) { + return; + } + // TvView's window type is TYPE_APPLICATION_MEDIA and we want to create + // an overlay window above the media window but below the application window. + int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; + // We make the overlay view non-focusable and non-touchable so that + // the application that owns the window token can decide whether to consume or + // dispatch the input events. + int flag = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + mWindowParams = new WindowManager.LayoutParams( + frame.right - frame.left, frame.bottom - frame.top, + frame.left, frame.top, type, flag, PixelFormat.TRANSPARENT); + mWindowParams.privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; + mWindowParams.gravity = Gravity.START | Gravity.TOP; + mWindowParams.token = windowToken; + mWindowManager.addView(mOverlayView, mWindowParams); + } + + /** + * Relayouts the current overlay view. + * + * @param frame A new position of the overlay view. + */ + void relayoutOverlayView(Rect frame) { + if (DEBUG) { + Log.d(TAG, "relayout overlay view(" + frame + ")"); + } + mOverlayFrame = frame; + if (!mOverlayViewEnabled || mOverlayView == null) { + return; + } + mWindowParams.x = frame.left; + mWindowParams.y = frame.top; + mWindowParams.width = frame.right - frame.left; + mWindowParams.height = frame.bottom - frame.top; + mWindowManager.updateViewLayout(mOverlayView, mWindowParams); + } + + /** + * Removes the current overlay view. + */ + void removeOverlayView(boolean clearWindowToken) { + if (DEBUG) { + Log.d(TAG, "remove overlay view(" + mOverlayView + ")"); + } + if (clearWindowToken) { + mWindowToken = null; + mOverlayFrame = null; + } + if (mOverlayView != null) { + mWindowManager.removeView(mOverlayView); + mOverlayView = null; + mWindowParams = null; + } + } } private final class ServiceHandler extends Handler { diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java new file mode 100644 index 000000000000..325950d024fb --- /dev/null +++ b/core/java/android/tv/TvView.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.tv; + +import android.content.ComponentName; +import android.content.Context; +import android.graphics.Rect; +import android.os.Handler; +import android.tv.TvInputManager; +import android.tv.TvInputManager.Session; +import android.tv.TvInputManager.SessionCreateCallback; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.ViewTreeObserver; + +/** + * View playing TV + */ +public class TvView extends SurfaceView { + private static final String TAG = "TvView"; + + private final Handler mHandler = new Handler(); + private TvInputManager.Session mSession; + private Surface mSurface; + private boolean mOverlayViewCreated; + private Rect mOverlayViewFrame; + private boolean mGlobalListenersAdded; + private TvInputManager mTvInputManager; + private SessionCreateCallback mSessionCreateCallback; + + private SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width=" + width + + ", height=" + height + ")"); + if (holder.getSurface() == mSurface) { + return; + } + mSurface = holder.getSurface(); + setSessionSurface(mSurface); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + mSurface = holder.getSurface(); + setSessionSurface(mSurface); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + mSurface = null; + setSessionSurface(null); + } + }; + + public TvView(Context context) { + this(context, null, 0); + } + + public TvView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TvView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + getHolder().addCallback(mSurfaceHolderCallback); + mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE); + } + + /** + * Binds a TV input to this view. {@link SessionCreateCallback#onSessionCreated} will be + * called to send the result of this binding with {@link TvInputManager.Session}. + * If a TV input is already bound, the input will be unbound from this view and its session + * will be released. + * + * @param name TV input name will be bound to this view. + * @param callback called when TV input is bound. The callback sends + * {@link TvInputManager.Session} + * @throws IllegalArgumentException if any of the arguments is {@code null}. + */ + public void bindTvInput(ComponentName name, SessionCreateCallback callback) { + if (name == null) { + throw new IllegalArgumentException("name cannot be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + if (mSession != null) { + release(); + } + // When bindTvInput is called multiple times before the callback is called, + // only the callback of the last bindTvInput call will be actually called back. + // The previous callbacks will be ignored. For the logic, mSessionCreateCallback + // is newly assigned for every bindTvInput call and compared with + // MySessionCreateCallback.this. + mSessionCreateCallback = new MySessionCreateCallback(callback); + mTvInputManager.createSession(name, mSessionCreateCallback, mHandler); + } + + /** + * Unbinds a TV input currently bound. Its corresponding {@link TvInputManager.Session} + * is released. + */ + public void unbindTvInput() { + if (mSession != null) { + release(); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + createSessionOverlayView(); + } + + @Override + protected void onDetachedFromWindow() { + removeSessionOverlayView(); + super.onDetachedFromWindow(); + } + + /** @hide */ + @Override + protected void updateWindow(boolean force, boolean redrawNeeded) { + super.updateWindow(force, redrawNeeded); + relayoutSessionOverlayView(); + } + + private void release() { + setSessionSurface(null); + removeSessionOverlayView(); + mSession.release(); + mSession = null; + } + + private void setSessionSurface(Surface surface) { + if (mSession == null) { + return; + } + mSession.setSurface(surface); + } + + private void createSessionOverlayView() { + if (mSession == null || !isAttachedToWindow() + || mOverlayViewCreated) { + return; + } + mOverlayViewFrame = getViewFrameOnScreen(); + mSession.createOverlayView(this, mOverlayViewFrame); + mOverlayViewCreated = true; + } + + private void removeSessionOverlayView() { + if (mSession == null || !mOverlayViewCreated) { + return; + } + mSession.removeOverlayView(); + mOverlayViewCreated = false; + mOverlayViewFrame = null; + } + + private void relayoutSessionOverlayView() { + if (mSession == null || !isAttachedToWindow() + || !mOverlayViewCreated) { + return; + } + Rect viewFrame = getViewFrameOnScreen(); + if (viewFrame.equals(mOverlayViewFrame)) { + return; + } + mSession.relayoutOverlayView(viewFrame); + mOverlayViewFrame = viewFrame; + } + + private Rect getViewFrameOnScreen() { + int[] location = new int[2]; + getLocationOnScreen(location); + return new Rect(location[0], location[1], + location[0] + getWidth(), location[1] + getHeight()); + } + + private class MySessionCreateCallback implements SessionCreateCallback { + final SessionCreateCallback mExternalCallback; + + MySessionCreateCallback(SessionCreateCallback externalCallback) { + mExternalCallback = externalCallback; + } + + @Override + public void onSessionCreated(Session session) { + if (this != mSessionCreateCallback) { + // This callback is obsolete. + session.release(); + return; + } + mSession = session; + if (session != null) { + // mSurface may not be ready yet as soon as starting an application. + // In the case, we don't send Session.setSurface(null) unnecessarily. + // setSessionSurface will be called in surfaceCreated. + if (mSurface != null) { + setSessionSurface(mSurface); + } + createSessionOverlayView(); + } + if (mExternalCallback != null) { + mExternalCallback.onSessionCreated(session); + } + } + } +} diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 23123dd8ba8e..4a2cc1a36aa6 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -422,7 +422,8 @@ public class SurfaceView extends View { mWindowType = type; } - private void updateWindow(boolean force, boolean redrawNeeded) { + /** @hide */ + protected void updateWindow(boolean force, boolean redrawNeeded) { if (!mHaveFrame) { return; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1f9ba4691ed1..be316e23fd3e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4737,13 +4737,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void manageFocusHotspot(boolean focused, View v) { if (mBackground != null && mBackground.supportsHotspots()) { final Rect r = new Rect(); - if (v != null) { + if (!focused && v != null) { v.getBoundsOnScreen(r); final int[] location = new int[2]; getLocationOnScreen(location); r.offset(-location[0], -location[1]); } else { - r.set(mLeft, mTop, mRight, mBottom); + r.set(0, 0, mRight - mLeft, mBottom - mTop); } final float x = r.exactCenterX(); @@ -4858,16 +4858,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { mPrivateFlags &= ~PFLAG_FOCUSED; - if (hasFocus()) { - manageFocusHotspot(false, focused); - } - if (propagate && mParent != null) { mParent.clearChildFocus(this); } onFocusChanged(false, 0, null); + manageFocusHotspot(false, focused); refreshDrawableState(); if (propagate && (!refocus || !rootViewRequestFocus())) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4e4f37ba995e..097dff050203 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3722,7 +3722,8 @@ public final class ViewRootImpl implements ViewParent, if (result == InputMethodManager.DISPATCH_HANDLED) { return FINISH_HANDLED; } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) { - return FINISH_NOT_HANDLED; + // The IME could not handle it, so skip along to the next InputStage + return FORWARD; } else { return DEFER; // callback will be invoked later } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 4c11fa95eddc..eaedba558719 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -5580,13 +5580,13 @@ public final class BatteryStatsImpl extends BatteryStats { if (end) { Slog.w(TAG, "New history ends before old history!"); } else if (!out.same(mHistoryReadTmp)) { - long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG)); pw.println("Histories differ!"); pw.println("Old history:"); - (new HistoryPrinter()).printNextItem(pw, out, now, false, true); + (new HistoryPrinter()).printNextItem(pw, out, 0, false, true); pw.println("New history:"); - (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now, false, true); + (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false, + true); pw.flush(); } } @@ -5664,7 +5664,12 @@ public final class BatteryStatsImpl extends BatteryStats { return false; } + final long lastRealtime = out.time; + final long lastWalltime = out.currentTime; readHistoryDelta(mHistoryBuffer, out); + if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) { + out.currentTime = lastWalltime + (out.time - lastRealtime); + } return true; } diff --git a/core/res/res/drawable/edit_text_quantum.xml b/core/res/res/drawable/edit_text_quantum.xml index d1f9831fb478..c42c7b7dc6a8 100644 --- a/core/res/res/drawable/edit_text_quantum.xml +++ b/core/res/res/drawable/edit_text_quantum.xml @@ -14,29 +14,26 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_window_focused="false" android:state_enabled="true"> - <nine-patch android:src="@drawable/textfield_default_qntm_alpha" - android:tint="?attr/colorControlNormal" /> - </item> - <item android:state_window_focused="false" android:state_enabled="false"> - <nine-patch android:src="@drawable/textfield_default_qntm_alpha" - android:tint="?attr/colorControlNormal" /> - </item> - <item android:state_enabled="true" android:state_focused="true"> - <nine-patch android:src="@drawable/textfield_activated_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item android:state_enabled="true" android:state_activated="true"> - <nine-patch android:src="@drawable/textfield_activated_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item android:state_enabled="true"> - <nine-patch android:src="@drawable/textfield_default_qntm_alpha" - android:tint="?attr/colorControlNormal" /> - </item> +<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android" + android:tint="?attr/colorControlActivated"> <item> - <nine-patch android:src="@drawable/textfield_default_qntm_alpha" - android:tint="?attr/colorControlNormal" /> + <selector> + <item android:state_window_focused="false"> + <nine-patch android:src="@drawable/textfield_default_qntm_alpha" + android:tint="?attr/colorControlNormal" /> + </item> + <item android:state_enabled="false"> + <nine-patch android:src="@drawable/textfield_default_qntm_alpha" + android:tint="?attr/colorControlNormal" /> + </item> + <item android:state_focused="false" android:state_activated="false"> + <nine-patch android:src="@drawable/textfield_default_qntm_alpha" + android:tint="?attr/colorControlNormal" /> + </item> + <item> + <nine-patch android:src="@drawable/textfield_activated_qntm_alpha" + android:tint="?attr/colorControlNormal" /> + </item> + </selector> </item> -</selector> +</touch-feedback> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2df5dc12df82..c610146b7afd 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1432,4 +1432,6 @@ <!-- default window inset isRound property --> <bool name="config_windowIsRound">false</bool> + <!-- Package name for default network scorer app; overridden by product overlays. --> + <string name="config_defaultNetworkScorerPackageName"></string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 03c617ac52ca..26efe36a5a7a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1625,6 +1625,7 @@ <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" /> <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" /> <java-symbol type="string" name="config_customAdbPublicKeyConfirmationComponent" /> + <java-symbol type="string" name="config_defaultNetworkScorerPackageName" /> <java-symbol type="layout" name="resolver_list" /> <java-symbol type="id" name="resolver_list" /> diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml index 60b6dc18f0c4..cbfa84d0ef81 100644 --- a/core/tests/bluetoothtests/AndroidManifest.xml +++ b/core/tests/bluetoothtests/AndroidManifest.xml @@ -31,5 +31,8 @@ <instrumentation android:name="android.bluetooth.BluetoothTestRunner" android:targetPackage="com.android.bluetooth.tests" android:label="Bluetooth Tests" /> + <instrumentation android:name="android.bluetooth.BluetoothInstrumentation" + android:targetPackage="com.android.bluetooth.tests" + android:label="Bluetooth Test Utils" /> </manifest> diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java new file mode 100644 index 000000000000..34393f98ae46 --- /dev/null +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.bluetooth; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.Context; +import android.os.Bundle; + +public class BluetoothInstrumentation extends Instrumentation { + + private BluetoothTestUtils mUtils = null; + private BluetoothAdapter mAdapter = null; + private Bundle mArgs = null; + + private BluetoothTestUtils getBluetoothTestUtils() { + if (mUtils == null) { + mUtils = new BluetoothTestUtils(getContext(), + BluetoothInstrumentation.class.getSimpleName()); + } + return mUtils; + } + + private BluetoothAdapter getBluetoothAdapter() { + if (mAdapter == null) { + mAdapter = ((BluetoothManager)getContext().getSystemService( + Context.BLUETOOTH_SERVICE)).getAdapter(); + } + return mAdapter; + } + + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + mArgs = arguments; + start(); + } + + @Override + public void onStart() { + String command = mArgs.getString("command"); + if ("enable".equals(command)) { + enable(); + } else if ("disable".equals(command)) { + disable(); + } else if ("unpairAll".equals(command)) { + unpairAll(); + } else if ("getName".equals(command)) { + getName(); + } else { + finish(null); + } + } + + public void enable() { + getBluetoothTestUtils().enable(getBluetoothAdapter()); + finish(null); + } + + public void disable() { + getBluetoothTestUtils().disable(getBluetoothAdapter()); + finish(null); + } + + public void unpairAll() { + getBluetoothTestUtils().unpairAll(getBluetoothAdapter()); + finish(null); + } + + public void getName() { + String name = getBluetoothAdapter().getName(); + Bundle bundle = new Bundle(); + bundle.putString("name", name); + finish(bundle); + } + + public void finish(Bundle result) { + if (result == null) { + result = new Bundle(); + } + finish(Activity.RESULT_OK, result); + } +} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java index 4858be8c2a8e..8fbd2147c9d0 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java @@ -34,6 +34,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class BluetoothTestUtils extends Assert { @@ -893,6 +894,17 @@ public class BluetoothTestUtils extends Assert { } /** + * Deletes all pairings of remote devices + * @param adapter the BT adapter + */ + public void unpairAll(BluetoothAdapter adapter) { + Set<BluetoothDevice> devices = adapter.getBondedDevices(); + for (BluetoothDevice device : devices) { + unpair(adapter, device); + } + } + + /** * Connects a profile from the local device to a remote device and checks to make sure that the * profile is connected and that the correct actions were broadcast. * diff --git a/core/tests/coretests/src/android/net/NetworkScorerApplicationTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java index 6d5ede8e8f80..cac6b931bf30 100644 --- a/core/tests/coretests/src/android/net/NetworkScorerApplicationTest.java +++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java @@ -33,7 +33,7 @@ import org.mockito.MockitoAnnotations; import java.util.Iterator; -public class NetworkScorerApplicationTest extends InstrumentationTestCase { +public class NetworkScorerAppManagerTest extends InstrumentationTestCase { @Mock private Context mMockContext; @Mock private PackageManager mMockPm; @@ -64,7 +64,7 @@ public class NetworkScorerApplicationTest extends InstrumentationTestCase { setScorers(package1, package2, package3); Iterator<String> result = - NetworkScorerApplication.getAllValidScorers(mMockContext).iterator(); + NetworkScorerAppManager.getAllValidScorers(mMockContext).iterator(); assertTrue(result.hasNext()); assertEquals("package1", result.next()); diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd index a12244379969..f169f5f7deb5 100644 --- a/docs/html/guide/topics/ui/actionbar.jd +++ b/docs/html/guide/topics/ui/actionbar.jd @@ -1145,7 +1145,7 @@ defined in a resource looks like this:</p> <item>Venus</item> <item>Earth</item> </string-array> -</pre> +</resources> </pre> <p>The {@link android.widget.ArrayAdapter} returned by {@link diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index 03dd8417cb91..796da50a9bcb 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -62,27 +62,31 @@ class Ripple { /** Whether the center is within the parent bounds. */ private boolean mInside; + + /** Whether to pulse this ripple. */ + boolean mPulse; /** Enter state. A value in [0...1] or -1 if not set. */ - private float mEnterState = -1; + float mEnterState = -1; /** Exit state. A value in [0...1] or -1 if not set. */ - private float mExitState = -1; + float mExitState = -1; /** Outside state. A value in [0...1] or -1 if not set. */ - private float mOutsideState = -1; + float mOutsideState = -1; /** Pulse state. A value in [0...1] or -1 if not set. */ - private float mPulseState = -1; + float mPulseState = -1; /** * Creates a new ripple with the specified parent bounds, padding, initial * position, and screen density. */ - public Ripple(Rect bounds, Rect padding, float x, float y, float density) { + public Ripple(Rect bounds, Rect padding, float x, float y, float density, boolean pulse) { mBounds = bounds; mPadding = padding; mInside = mBounds.contains((int) x, (int) y); + mPulse = pulse; mX = x; mY = y; @@ -115,6 +119,16 @@ class Ripple { } } + public void onBoundsChanged() { + final boolean inside = mBounds.contains((int) mX, (int) mY); + if (mInside != inside) { + if (mAnimator != null) { + mAnimator.outside(); + } + mInside = inside; + } + } + public RippleAnimator animate() { if (mAnimator == null) { mAnimator = new RippleAnimator(this); @@ -308,9 +322,11 @@ class Ripple { MathUtils.constrain((currentTime - mOutsideTime) / (float) OUTSIDE_DURATION, 0, 1)); // Pulse is a little more complicated. - final long pulseTime = (currentTime - mEnterTime - ENTER_DURATION - PULSE_DELAY); - mTarget.mPulseState = pulseTime < 0 ? -1 - : (pulseTime % (PULSE_INTERVAL + PULSE_DURATION)) / (float) PULSE_DURATION; + if (mTarget.mPulse) { + final long pulseTime = (currentTime - mEnterTime - ENTER_DURATION - PULSE_DELAY); + mTarget.mPulseState = pulseTime < 0 ? -1 + : (pulseTime % (PULSE_INTERVAL + PULSE_DURATION)) / (float) PULSE_DURATION; + } } } } diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index cf08031fe236..813d755c5d9d 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -112,6 +112,16 @@ public class TouchFeedbackDrawable extends LayerDrawable { } @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + + final int N = mActiveRipplesCount; + for (int i = 0; i < N; i++) { + mActiveRipples[i].onBoundsChanged(); + } + } + + @Override public boolean setVisible(boolean visible, boolean restart) { if (!visible) { if (mTouchedRipples != null) { @@ -291,7 +301,9 @@ public class TouchFeedbackDrawable extends LayerDrawable { y = bounds.exactCenterY(); } - final Ripple newRipple = new Ripple(bounds, padding, x, y, mDensity); + // TODO: Clean this up in the API. + final boolean pulse = (id != R.attr.state_focused); + final Ripple newRipple = new Ripple(bounds, padding, x, y, mDensity, pulse); newRipple.animate().enter(); mActiveRipples[mActiveRipplesCount++] = newRipple; diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 7c4568241c40..4fbd2a4a91eb 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -297,8 +297,6 @@ JDrm::JDrm( } JDrm::~JDrm() { - mDrm.clear(); - JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mObject); @@ -363,6 +361,13 @@ void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) } } +void JDrm::disconnect() { + if (mDrm != NULL) { + mDrm->destroyPlugin(); + mDrm.clear(); + } +} + // static bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { @@ -527,6 +532,7 @@ static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) { sp<JDrm> drm = setDrm(env, thiz, NULL); if (drm != NULL) { drm->setListener(NULL); + drm->disconnect(); } } diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index 620ad2832bab..b7b8e5dd6b6c 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -47,6 +47,8 @@ struct JDrm : public BnDrmClient { void notify(DrmPlugin::EventType, int extra, const Parcel *obj); status_t setListener(const sp<DrmListener>& listener); + void disconnect(); + protected: virtual ~JDrm(); diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 0e552284750b..d7813368310e 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -859,6 +859,7 @@ void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) result = malloc(exifdata->size); if (result) { memcpy(result, exifdata->data, exifdata->size); + outThumbSize = exifdata->size; } } exif_data_unref(exifdata); diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index a9322b993101..1406f6ba4b83 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -878,7 +878,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback protected int[] mConfigSpec; private int[] filterConfigSpec(int[] configSpec) { - if (mEGLContextClientVersion != 2) { + if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) { return configSpec; } /* We know none of the subclasses define EGL_RENDERABLE_TYPE. @@ -888,7 +888,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback int[] newConfigSpec = new int[len + 2]; System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; - newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ + if (mEGLContextClientVersion == 2) { + newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT; /* EGL_OPENGL_ES2_BIT */ + } else { + newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */ + } newConfigSpec[len+1] = EGL10.EGL_NONE; return newConfigSpec; } diff --git a/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 000000000000..85db9c82cf20 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 000000000000..c4941a637d41 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 000000000000..4618f40f95ce --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png Binary files differnew file mode 100644 index 000000000000..36e7e45494ef --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 000000000000..c0bf31d02f30 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml index 28d962500411..f3c1b9043ed5 100644 --- a/packages/SystemUI/res/layout/flip_settings.xml +++ b/packages/SystemUI/res/layout/flip_settings.xml @@ -22,4 +22,5 @@ android:layout_height="wrap_content" android:background="#5f000000" android:animateLayoutChanges="true" + android:visibility="gone" android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings.xml b/packages/SystemUI/res/layout/quick_settings.xml deleted file mode 100644 index 75082bafb017..000000000000 --- a/packages/SystemUI/res/layout/quick_settings.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<com.android.systemui.statusbar.phone.SettingsPanelView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:id="@+id/settings_panel" - android:background="@drawable/notification_panel_bg" - > - <!-- TODO: Put into ScrollView --> - <com.android.systemui.statusbar.phone.QuickSettingsScrollView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/close_handle_underlap" - android:overScrollMode="ifContentScrolls" - > - <com.android.systemui.statusbar.phone.QuickSettingsContainerView - android:id="@+id/quick_settings_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:animateLayoutChanges="true" - android:columnCount="@integer/quick_settings_num_columns" - /> - </com.android.systemui.statusbar.phone.QuickSettingsScrollView> - - <View - android:id="@+id/handle" - android:layout_width="match_parent" - android:layout_height="@dimen/close_handle_height" - android:background="@drawable/status_bar_close" - android:visibility="invisible" - /> - -</com.android.systemui.statusbar.phone.SettingsPanelView >
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_search_bar.xml b/packages/SystemUI/res/layout/recents_search_bar.xml new file mode 100644 index 000000000000..915283e30f65 --- /dev/null +++ b/packages/SystemUI/res/layout/recents_search_bar.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/search_bg_transparent"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:text="@string/recents_search_bar_label" + android:textColor="#99ffffff" + android:textSize="18sp" + android:textAllCaps="true" /> +</FrameLayout> + diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index 7f640328cd9e..4442bca85915 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -63,13 +63,6 @@ android:maxLines="2" android:ellipsize="marquee" android:fadingEdge="horizontal" /> - <ImageView - android:id="@+id/activity_icon" - android:layout_width="@dimen/recents_task_view_activity_icon_size" - android:layout_height="@dimen/recents_task_view_activity_icon_size" - android:layout_gravity="center_vertical|end" - android:padding="12dp" - android:visibility="invisible" /> </com.android.systemui.recents.views.TaskBarView> </com.android.systemui.recents.views.TaskView> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 8a3f09037540..9e21cd3908ad 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -36,8 +36,9 @@ android:layout_gravity="bottom" /> - <ViewStub android:id="@+id/keyguard_flip_stub" - android:layout="@layout/status_bar_flip_button" + <include + layout="@layout/status_bar_flip_button" + android:id="@+id/keyguard_flipper" android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="right|top" @@ -76,8 +77,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" > - <ViewStub android:id="@+id/flip_settings_stub" - android:layout="@layout/flip_settings" + <include + layout="@layout/flip_settings" android:layout_width="match_parent" android:layout_height="wrap_content" /> diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 56523dbc3699..897572898e8a 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -84,6 +84,7 @@ /> <include layout="@layout/status_bar_flip_button" + android:id="@+id/header_flipper" android:layout_width="50dp" android:layout_height="50dp" android:layout_marginStart="12dp" /> diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml index db672eac334b..b7dff8cec210 100644 --- a/packages/SystemUI/res/layout/status_bar_flip_button.xml +++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml @@ -16,7 +16,6 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/settings_button_holder" android:layout_width="50dp" android:layout_height="50dp"> <ImageView android:id="@+id/settings_button" diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index 2b01a06bb0f8..92c22ccd9717 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -39,10 +39,6 @@ android:layout_width="@dimen/notification_panel_width" android:layout_height="wrap_content" android:layout_gravity="start|top" /> - <ViewStub android:id="@+id/quick_settings_stub" - android:layout="@layout/quick_settings" - android:layout_width="@dimen/notification_panel_width" - android:layout_height="match_parent" /> </com.android.systemui.statusbar.phone.PanelHolder> </com.android.systemui.statusbar.phone.StatusBarWindowView> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index c6bc44d5a9f5..fe2224ecfab0 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -20,9 +20,6 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - <!-- Enable quick settings on tablets --> - <bool name="config_hasSettingsPanel">true</bool> - <!-- The number of columns in the QuickSettings --> <integer name="quick_settings_num_columns">3</integer> @@ -31,7 +28,4 @@ <!-- The number of columns that the top level tiles span in the QuickSettings --> <integer name="quick_settings_user_time_settings_tile_span">1</integer> - - <!-- Enable the "flip settings" panel --> - <bool name="config_hasFlipSettingsPanel">true</bool> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index b4fafec5f448..5b5587df48fa 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -23,10 +23,9 @@ <dimen name="notification_panel_margin_bottom">192dp</dimen> <dimen name="notification_panel_margin_left">16dp</dimen> - <!-- Gravity for the notification & quick settings panels --> - <!-- 0x31 = top|center_horizontal ; 0x800035 = end|top --> + <!-- Gravity for the notification panel --> + <!-- 0x31 = top|center_horizontal --> <integer name="notification_panel_layout_gravity">0x31</integer> - <integer name="settings_panel_layout_gravity">0x800035</integer> <!-- Diameter of outer shape drawable shown in navbar search--> <dimen name="navbar_search_outerring_diameter">430dip</dimen> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 250c2686136c..722ca1555ea0 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -99,11 +99,8 @@ <integer name="blinds_pop_duration_ms">10</integer> - <!-- Disable the separate quick settings panel --> - <bool name="config_hasSettingsPanel">true</bool> - - <!-- Enable the "flip settings" panel --> - <bool name="config_hasFlipSettingsPanel">true</bool> + <!-- The device supports quick settings. --> + <bool name="config_hasQuickSettings">true</bool> <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? --> <bool name="config_show4GForLTE">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 9aacf42221b6..3047f1545efb 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -174,18 +174,9 @@ <dimen name="notification_panel_margin_bottom">0dp</dimen> <dimen name="notification_panel_margin_left">0dp</dimen> - <!-- Gravity for the notification & quick settings panels --> + <!-- Gravity for the notification panel --> <!-- 0x37 = fill_horizontal|top --> <integer name="notification_panel_layout_gravity">0x37</integer> - <integer name="settings_panel_layout_gravity">0x37</integer> - - <!-- Fraction of the status bar that, when dragged, will produce the quick settings panel - instead of the notification panel. See also @dimen/settings_panel_dragzone_min. - If zero, the settings panel will not be directly draggable from the status bar. --> - <item type="dimen" name="settings_panel_dragzone_fraction">0%</item> - - <!-- Quick settings dragzone, if used, should be at least this big (may be zero). --> - <dimen name="settings_panel_dragzone_min">100dp</dimen> <!-- Height of the carrier/wifi name label --> <dimen name="carrier_label_height">24dp</dimen> @@ -245,6 +236,12 @@ <!-- The amount of space a user has to scroll to dismiss any info panes. --> <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen> + <!-- The height of the search bar space. --> + <dimen name="recents_search_bar_space_height">40dp</dimen> + + <!-- The search bar edge margins. --> + <dimen name="recents_search_bar_space_edge_margins">12dp</dimen> + <!-- Used to calculate the translation animation duration, the expected amount of movement in dps over one second of time. --> <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 73e5e194eb57..72d14fefce1f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -511,6 +511,8 @@ <string name="recents_empty_message">RECENTS</string> <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] --> <string name="recents_app_info_button_label">Application Info</string> + <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] --> + <string name="recents_search_bar_label">search</string> <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. --> diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 4fb90cb0c902..f2e322d97157 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -44,6 +44,7 @@ import android.view.View; import android.view.WindowManager; import com.android.systemui.R; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -240,12 +241,10 @@ public class AlternateRecentsComponent { } /** Returns whether there is are multiple recents tasks */ - boolean hasMultipleRecentsTask() { + boolean hasMultipleRecentsTask(List<ActivityManager.RecentTaskInfo> tasks) { // NOTE: Currently there's no method to get the number of non-home tasks, so we have to // compute this ourselves SystemServicesProxy ssp = mSystemServicesProxy; - List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(4, - UserHandle.CURRENT.getIdentifier()); Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator(); while (iter.hasNext()) { ActivityManager.RecentTaskInfo t = iter.next(); @@ -259,6 +258,17 @@ public class AlternateRecentsComponent { return (tasks.size() > 1); } + /** Returns whether the base intent of the top task stack was launched with the flag + * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */ + boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) { + if (tasks.size() > 0) { + ActivityManager.RecentTaskInfo t = tasks.get(0); + Console.log(t.baseIntent.toString()); + return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; + } + return false; + } + /** Converts from the device rotation to the degree */ float getDegreesForRotation(int value) { switch (value) { @@ -334,10 +344,18 @@ public class AlternateRecentsComponent { isTopTaskHome = ssp.isInHomeStack(topTask.id); } - // Otherwise, Recents is not the front-most activity and we should animate into it - boolean hasMultipleTasks = hasMultipleRecentsTask(); + // Otherwise, Recents is not the front-most activity and we should animate into it. If + // the activity at the root of the top task stack is excluded from recents, or if that + // task stack is in the home stack, then we just do a simple transition. Otherwise, we + // animate to the rects defined by the Recents service, which can differ depending on the + // number of items in the list. + List<ActivityManager.RecentTaskInfo> recentTasks = + ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier()); + boolean hasMultipleTasks = hasMultipleRecentsTask(recentTasks); + boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks); Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect; - if (!isTopTaskHome && taskRect != null && taskRect.width() > 0 && taskRect.height() > 0) { + if (!isTopTaskHome && !isTaskExcludedFromRecents && + (taskRect != null) && (taskRect.width() > 0) && (taskRect.height() > 0)) { // Loading from thumbnail Bitmap thumbnail; Bitmap firstThumbnail = loadFirstTaskThumbnail(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 64770a459636..72d9a52360a8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -29,6 +29,7 @@ public class Constants { public static final boolean EnableTaskFiltering = true; public static final boolean EnableTaskStackClipping = false; public static final boolean EnableInfoPane = true; + public static final boolean EnableSearchButton = false; // This disables the bitmap and icon caches public static final boolean DisableBackgroundCache = false; @@ -84,6 +85,9 @@ public class Constants { public static final int TaskStackOverscrollRange = 150; public static final int FilterStartDelay = 25; + // The amount to inverse scale the movement if we are overscrolling + public static final float TouchOverscrollScaleFactor = 3f; + // The padding will be applied to the smallest dimension, and then applied to all sides public static final float StackPaddingPct = 0.15f; // The overlap height relative to the task height diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 5e5b84157bfb..d54df1333111 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -44,6 +44,8 @@ public class RecentsConfiguration { public int taskStackMaxDim; public int taskViewInfoPaneAnimDuration; public int taskViewRoundedCornerRadiusPx; + public int searchBarSpaceHeightPx; + public int searchBarSpaceEdgeMarginsPx; public boolean launchedWithThumbnailAnimation; @@ -92,6 +94,9 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_animate_task_view_info_pane_duration); taskViewRoundedCornerRadiusPx = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); + searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); + searchBarSpaceEdgeMarginsPx = + res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins); } /** Updates the system insets */ @@ -99,6 +104,26 @@ public class RecentsConfiguration { systemInsets.set(insets); } + /** Returns the search bar bounds in the specified orientation */ + public void getSearchBarBounds(int width, int height, + Rect searchBarSpaceBounds, Rect searchBarBounds) { + // Return empty rects if search is not enabled + if (!Constants.DebugFlags.App.EnableSearchButton) { + searchBarSpaceBounds.set(0, 0, 0, 0); + searchBarBounds.set(0, 0, 0, 0); + return; + } + + // Calculate the search bar bounds, and account for the system insets + int edgeMarginPx = searchBarSpaceEdgeMarginsPx; + int availableWidth = width - systemInsets.left - systemInsets.right; + searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx); + + // Inset from the search bar space to get the search bar bounds + searchBarBounds.set(searchBarSpaceBounds); + searchBarBounds.inset(edgeMarginPx, edgeMarginPx); + } + /** Converts from DPs to PXs */ public int pxFromDp(float size) { return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java index 06ca9e2ba228..36b761e96f0e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -66,22 +66,33 @@ class SystemUIMessageHandler extends Handler { Bundle replyData = new Bundle(); TaskViewTransform transform; + // Get the search bar bounds so that we can account for its height in the children + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); + RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.getSearchBarBounds(windowRect.width(), windowRect.height(), + searchBarSpaceBounds, searchBarBounds); + // Calculate the target task rect for when there is one task // NOTE: Since the nav bar height is already accounted for in the windowRect, don't // pass in a bottom inset stack.addTask(new Task()); - tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0); + tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top - + systemInsets.bottom - searchBarSpaceBounds.height(), 0); tsv.boundScroll(); transform = tsv.getStackTransform(0, tsv.getStackScroll()); + transform.rect.offset(0, searchBarSpaceBounds.height()); replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT, new Rect(transform.rect)); // Also calculate the target task rect when there are multiple tasks stack.addTask(new Task()); - tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0); + tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top - + systemInsets.bottom - searchBarSpaceBounds.height(), 0); tsv.setStackScrollRaw(Integer.MAX_VALUE); tsv.boundScroll(); transform = tsv.getStackTransform(1, tsv.getStackScroll()); + transform.rect.offset(0, searchBarSpaceBounds.height()); replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT, new Rect(transform.rect)); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index fd0f6d12dc4f..da265e1754ef 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -415,7 +415,10 @@ public class RecentsTaskLoader { ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId); String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) : t.activityLabel.toString()); - Bitmap activityIcon = t.activityIcon; + BitmapDrawable activityIcon = null; + if (t.activityIcon != null) { + activityIcon = new BitmapDrawable(res, t.activityIcon); + } boolean isForemostTask = (i == (taskCount - 1)); // Create a new task diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index 7f0d9ee25cef..33ac0a8ddec9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -19,6 +19,8 @@ package com.android.systemui.recents; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.SearchManager; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -26,11 +28,15 @@ import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.text.TextUtils; +import android.util.Log; import java.util.ArrayList; import java.util.List; @@ -45,6 +51,7 @@ public class SystemServicesProxy { PackageManager mPm; IPackageManager mIpm; UserManager mUm; + SearchManager mSm; String mPackage; Bitmap mDummyIcon; @@ -55,6 +62,7 @@ public class SystemServicesProxy { mPm = context.getPackageManager(); mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mIpm = AppGlobals.getPackageManager(); + mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); mPackage = context.getPackageName(); if (Constants.DebugFlags.App.EnableSystemServicesProxy) { @@ -199,4 +207,28 @@ public class SystemServicesProxy { } return icon; } + + + /** + * Composes an intent to launch the global search activity. + */ + public Intent getGlobalSearchIntent(Rect sourceBounds) { + if (mSm == null) return null; + + // Try and get the global search activity + ComponentName globalSearchActivity = mSm.getGlobalSearchActivity(); + if (globalSearchActivity == null) return null; + + // Bundle the source of the search + Bundle appSearchData = new Bundle(); + appSearchData.putString("source", mPackage); + + // Compose the intent and Start the search activity + Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setComponent(globalSearchActivity); + intent.putExtra(SearchManager.APP_DATA, appSearchData); + intent.setSourceBounds(sourceBounds); + return intent; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index ff062f6c4231..1566a49d3421 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -18,6 +18,7 @@ package com.android.systemui.recents.model; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -69,8 +70,8 @@ public class Task { public TaskKey key; public Drawable applicationIcon; + public Drawable activityIcon; public String activityLabel; - public Bitmap activityIcon; public Bitmap thumbnail; public boolean isActive; public int userId; @@ -82,7 +83,7 @@ public class Task { } public Task(int id, boolean isActive, Intent intent, String activityTitle, - Bitmap activityIcon, int userId) { + BitmapDrawable activityIcon, int userId) { this.key = new TaskKey(id, intent, userId); this.activityLabel = activityTitle; this.activityIcon = activityIcon; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index b054a22e52d1..a04cd3e3ea49 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -27,8 +27,11 @@ import android.graphics.Rect; import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; +import android.view.Gravity; +import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; +import android.widget.TextView; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; @@ -36,6 +39,7 @@ import com.android.systemui.recents.RecentsTaskLoader; import com.android.systemui.recents.model.SpaceNode; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.R; import java.util.ArrayList; @@ -53,11 +57,16 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // The space partitioning root of this container SpaceNode mBSP; + // Search bar view + View mSearchBar; // Recents view callbacks RecentsViewCallbacks mCb; + LayoutInflater mInflater; + public RecentsView(Context context) { super(context); + mInflater = LayoutInflater.from(context); setWillNotDraw(false); } @@ -71,12 +80,22 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV mBSP = n; // Create and add all the stacks for this partition of space. + boolean hasTasks = false; removeAllViews(); ArrayList<TaskStack> stacks = mBSP.getStacks(); for (TaskStack stack : stacks) { TaskStackView stackView = new TaskStackView(getContext(), stack); stackView.setCallbacks(this); addView(stackView); + hasTasks |= (stack.getTaskCount() > 0); + } + + // Create the search bar (and hide it if we have no recent tasks) + if (Constants.DebugFlags.App.EnableSearchButton) { + createSearchBar(); + if (!hasTasks) { + mSearchBar.setVisibility(View.GONE); + } } } @@ -85,29 +104,45 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Get the first stack view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - TaskStackView stackView = (TaskStackView) getChildAt(i); - TaskStack stack = stackView.mStack; - ArrayList<Task> tasks = stack.getTasks(); - - // Get the first task in the stack - if (!tasks.isEmpty()) { - Task task = tasks.get(tasks.size() - 1); - TaskView tv = null; - - // Try and use the first child task view as the source of the launch animation - if (stackView.getChildCount() > 0) { - TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1); - if (stv.getTask() == task) { - tv = stv; + View child = getChildAt(i); + if (child instanceof TaskStackView) { + TaskStackView stackView = (TaskStackView) child; + TaskStack stack = stackView.mStack; + ArrayList<Task> tasks = stack.getTasks(); + + // Get the first task in the stack + if (!tasks.isEmpty()) { + Task task = tasks.get(tasks.size() - 1); + TaskView tv = null; + + // Try and use the first child task view as the source of the launch animation + if (stackView.getChildCount() > 0) { + TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1); + if (stv.getTask() == task) { + tv = stv; + } } + onTaskLaunched(stackView, tv, stack, task); + return true; } - onTaskLaunched(stackView, tv, stack, task); - return true; } } return false; } + /** Creates and adds the search bar */ + void createSearchBar() { + // Create a temporary search bar + mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false); + mSearchBar.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onSearchTriggered(); + } + }); + addView(mSearchBar); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); @@ -120,16 +155,26 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure"); - // We measure our stack views sans the status bar. It will handle the nav bar itself. + // Get the search bar bounds so that we can account for its height in the children + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), + searchBarSpaceBounds, searchBarBounds); + if (mSearchBar != null) { + mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode), + MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode)); + } + + // We measure our stack views sans the status bar. It will handle the nav bar itself. int childWidth = width - config.systemInsets.right; - int childHeight = height - config.systemInsets.top; + int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height(); // Measure each child int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { + View child = getChildAt(i); + if (child instanceof TaskStackView && child.getVisibility() != GONE) { child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode), MeasureSpec.makeMeasureSpec(childHeight, heightMode)); } @@ -145,18 +190,30 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout"); - // We offset our stack views by the status bar height. It will handle the nav bar itself. + // Get the search bar bounds so that we can account for its height in the children + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); RecentsConfiguration config = RecentsConfiguration.getInstance(); - top += config.systemInsets.top; + config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), + searchBarSpaceBounds, searchBarBounds); + if (mSearchBar != null) { + mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left, + config.systemInsets.top + searchBarSpaceBounds.top, + config.systemInsets.left + mSearchBar.getMeasuredWidth(), + config.systemInsets.top + mSearchBar.getMeasuredHeight()); + } + + // We offset our stack views by the status bar height. It will handle the nav bar itself. + top += config.systemInsets.top + searchBarSpaceBounds.height(); // Layout each child // XXX: Based on the space node for that task view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - final int width = child.getMeasuredWidth(); - final int height = child.getMeasuredHeight(); + View child = getChildAt(i); + if (child instanceof TaskStackView && child.getVisibility() != GONE) { + int width = child.getMeasuredWidth(); + int height = child.getMeasuredHeight(); child.layout(left, top, left + width, top + height); } } @@ -188,9 +245,12 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Get the first stack view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - TaskStackView stackView = (TaskStackView) getChildAt(i); - if (stackView.closeOpenInfoPanes()) { - return true; + View child = getChildAt(i); + if (child instanceof TaskStackView) { + TaskStackView stackView = (TaskStackView) child; + if (stackView.closeOpenInfoPanes()) { + return true; + } } } } @@ -266,7 +326,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV b, offsetX, offsetY); } - if (task.isActive) { // Bring an active task to the foreground RecentsTaskLoader.getInstance().getSystemServicesProxy() @@ -315,4 +374,24 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV TaskStackBuilder.create(getContext()) .addNextIntentWithParentStack(intent).startActivities(); } + + public void onSearchTriggered() { + // Get the search bar source bounds + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); + RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), + searchBarSpaceBounds, searchBarBounds); + + // Get the search intent and start it + Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy() + .getGlobalSearchIntent(searchBarBounds); + if (searchIntent != null) { + try { + getContext().startActivity(searchIntent); + } catch (ActivityNotFoundException anfe) { + Console.logError(getContext(), "Could not start Search activity"); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java index c9a6d67eb561..124f11e3dd4b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java @@ -31,7 +31,6 @@ class TaskBarView extends FrameLayout { Task mTask; ImageView mApplicationIcon; - ImageView mActivityIcon; TextView mActivityDescription; public TaskBarView(Context context) { @@ -54,23 +53,22 @@ class TaskBarView extends FrameLayout { protected void onFinishInflate() { // Initialize the icon and description views mApplicationIcon = (ImageView) findViewById(R.id.application_icon); - mActivityIcon = (ImageView) findViewById(R.id.activity_icon); mActivityDescription = (TextView) findViewById(R.id.activity_description); } /** Binds the bar view to the task */ void rebindToTask(Task t, boolean animate) { mTask = t; - if (t.applicationIcon != null) { + // If an activity icon is defined, then we use that as the primary icon to show in the bar, + // otherwise, we fall back to the application icon + if (t.activityIcon != null) { + mApplicationIcon.setImageDrawable(t.activityIcon); + } else if (t.applicationIcon != null) { mApplicationIcon.setImageDrawable(t.applicationIcon); - mActivityDescription.setText(t.activityLabel); - if (t.activityIcon != null) { - mActivityIcon.setImageBitmap(t.activityIcon); - mActivityIcon.setVisibility(View.VISIBLE); - } - if (animate) { - // XXX: Investigate how expensive it will be to create a second bitmap and crossfade - } + } + mActivityDescription.setText(t.activityLabel); + if (animate) { + // XXX: Investigate how expensive it will be to create a second bitmap and crossfade } } @@ -78,8 +76,6 @@ class TaskBarView extends FrameLayout { void unbindFromTask() { mTask = null; mApplicationIcon.setImageDrawable(null); - mActivityIcon.setImageBitmap(null); - mActivityIcon.setVisibility(View.INVISIBLE); mActivityDescription.setText(""); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java index 233e38c03325..a81d01c3cc59 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java @@ -70,10 +70,8 @@ class TaskInfoView extends FrameLayout { /** Updates the positions of each of the items to fit in the rect specified */ void updateContents(Rect visibleRect) { // Offset the app info button - LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams(); - lp.topMargin = visibleRect.top + - (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2; - requestLayout(); + mAppInfoButton.setTranslationY(visibleRect.top + + (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2); } /** Sets the circular clip radius on this panel */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index ee92b16c2cd2..a77e61d65164 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -395,9 +395,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return false; } - /** Returns whether the current scroll is out of bounds */ + /** Returns whether the specified scroll is out of bounds */ + boolean isScrollOutOfBounds(int scroll) { + return (scroll < mMinScroll) || (scroll > mMaxScroll); + } boolean isScrollOutOfBounds() { - return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll); + return isScrollOutOfBounds(getStackScroll()); } /** Updates the min and max virtual scroll bounds */ @@ -556,7 +559,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int smallestDimension = Math.min(width, height); int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f); - mStackRect.inset(padding, padding); + if (Constants.DebugFlags.App.EnableSearchButton) { + // Don't need to pad the top since we have some padding on the search bar already + mStackRect.left += padding; + mStackRect.right -= padding; + mStackRect.bottom -= padding; + } else { + mStackRect.inset(padding, padding); + } mStackRectSansPeek.set(mStackRect); mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height(); @@ -1275,7 +1285,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { } } if (mIsScrolling) { - mSv.setStackScroll(mSv.getStackScroll() + deltaY); + int curStackScroll = mSv.getStackScroll(); + if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) { + // Scale the touch if we are overscrolling + deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor; + } + mSv.setStackScroll(curStackScroll + deltaY); if (mSv.isScrollOutOfBounds()) { mVelocityTracker.clear(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index f2054a210f16..cf31b445c6b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -83,7 +83,7 @@ public class KeyguardBouncer { } public void onScreenTurnedOff() { - if (mKeyguardView != null && mRoot.getVisibility() == View.VISIBLE) { + if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) { mKeyguardView.onPause(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 45ac50b6f686..5d758018cf21 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -38,6 +38,7 @@ public class NotificationPanelView extends PanelView { private int[] mTempChildLocation = new int[2]; private View mNotificationParent; private boolean mTrackingSettings; + private float mExpandedHeight = -1; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -173,6 +174,8 @@ public class NotificationPanelView extends PanelView { * @param expandedHeight the new expanded height */ private void updateNotificationStackHeight(float expandedHeight) { + if (mExpandedHeight == expandedHeight) return; + mExpandedHeight = expandedHeight; mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f); float childOffset = getRelativeTop(mNotificationStackScroller) - mNotificationParent.getTranslationY(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 0266144c4242..02ef7ceebe64 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -46,7 +46,6 @@ public class PanelView extends FrameLayout { } public static final boolean BRAKES = false; - private boolean mRubberbandingEnabled = true; private float mSelfExpandVelocityPx; // classic value: 2000px/s private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up") @@ -68,14 +67,12 @@ public class PanelView extends FrameLayout { private float mExpandBrakingDistancePx = 150; // XXX Resource private float mBrakingSpeedPx = 150; // XXX Resource - private View mHandleView; private float mPeekHeight; private float mInitialOffsetOnTouch; private float mExpandedFraction = 0; private float mExpandedHeight = 0; private boolean mJustPeeked; private boolean mClosing; - private boolean mRubberbanding; private boolean mTracking; private int mTrackingPointer; private int mTouchSlop; @@ -214,7 +211,6 @@ public class PanelView extends FrameLayout { public void run() { if (mTimeAnimator != null && mTimeAnimator.isStarted()) { mTimeAnimator.end(); - mRubberbanding = false; mClosing = false; onExpandingFinished(); } @@ -227,10 +223,6 @@ public class PanelView extends FrameLayout { protected float mInitialTouchY; protected float mFinalTouchY; - public void setRubberbandingEnabled(boolean enable) { - mRubberbandingEnabled = enable; - } - protected void onExpandingFinished() { } @@ -260,12 +252,7 @@ public class PanelView extends FrameLayout { mTimeAnimator.start(); - mRubberbanding = mRubberbandingEnabled // is it enabled at all? - && mExpandedHeight > getMaxPanelHeight() // are we past the end? - && mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture? - if (mRubberbanding) { - mClosing = true; - } else if (mVel == 0) { + if (mVel == 0) { // if the panel is less than halfway open, close it mClosing = (mFinalTouchY / getMaxPanelHeight()) < 0.5f; } else { @@ -308,10 +295,6 @@ public class PanelView extends FrameLayout { float h = mExpandedHeight + mVel * dt; - if (mRubberbanding && h < fh) { - h = fh; - } - if (DEBUG) logf("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false"); setExpandedHeightInternal(h); @@ -320,7 +303,7 @@ public class PanelView extends FrameLayout { if (mVel == 0 || (mClosing && mExpandedHeight == 0) - || ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) { + || (!mClosing && mExpandedHeight == fh)) { post(mStopAnimator); } } else { @@ -358,8 +341,7 @@ public class PanelView extends FrameLayout { mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity); mPeekHeight = res.getDimension(R.dimen.peek_height) - + getPaddingBottom() // our window might have a dropshadow - - (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow + + getPaddingBottom(); // our window might have a dropshadow final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); @@ -397,10 +379,6 @@ public class PanelView extends FrameLayout { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mTracking = true; - if (mHandleView != null) { - mHandleView.setPressed(true); - postInvalidate(); // catch the press state change - } mInitialTouchY = y; initVelocityTracker(); @@ -447,10 +425,6 @@ public class PanelView extends FrameLayout { mFinalTouchY = y; mTracking = false; mTrackingPointer = -1; - if (mHandleView != null) { - mHandleView.setPressed(false); - postInvalidate(); // catch the press state change - } onTrackingStopped(); trackMovement(event); @@ -546,11 +520,6 @@ public class PanelView extends FrameLayout { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - if (mHandleView != null) { - mHandleView.setPressed(true); - // catch the press state change - postInvalidate(); - } mInitialTouchY = y; initVelocityTracker(); trackMovement(event); @@ -605,7 +574,6 @@ public class PanelView extends FrameLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - mHandleView = findViewById(R.id.handle); loadDimens(); } @@ -631,10 +599,6 @@ public class PanelView extends FrameLayout { return mViewName; } - public View getHandle() { - return mHandleView; - } - // Rubberbands the panel to hold its contents. @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -648,7 +612,7 @@ public class PanelView extends FrameLayout { if (newHeight != mMaxPanelHeight) { mMaxPanelHeight = newHeight; // If the user isn't actively poking us, let's rubberband to the content - if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted() + if (!mTracking && !mTimeAnimator.isStarted() && mExpandedHeight > 0 && mExpandedHeight != mMaxPanelHeight && mMaxPanelHeight > 0) { mExpandedHeight = mMaxPanelHeight; @@ -666,7 +630,6 @@ public class PanelView extends FrameLayout { public void setExpandedHeight(float height) { if (DEBUG) logf("setExpandedHeight(%.1f)", height); - mRubberbanding = false; if (mTimeAnimator.isStarted()) { post(mStopAnimator); } @@ -686,7 +649,7 @@ public class PanelView extends FrameLayout { float currentMaxPanelHeight = getMaxPanelHeight(); // If the user isn't actively poking us, let's update the height - if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted() + if (!mTracking && !mTimeAnimator.isStarted() && mExpandedHeight > 0 && currentMaxPanelHeight != mExpandedHeight) { setExpandedHeightInternal(currentMaxPanelHeight); } @@ -708,13 +671,13 @@ public class PanelView extends FrameLayout { } if (h < 0) h = 0; - if (!(mRubberbandingEnabled && (mTracking || mRubberbanding)) && h > fh) h = fh; + if (h > fh) h = fh; mExpandedHeight = h; if (DEBUG) { - logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, - mTracking ? "T" : "f", mRubberbanding ? "T" : "f"); + logf("setExpansion: height=%.1f fh=%.1f tracking=%s", h, fh, + mTracking ? "T" : "f"); } onHeightUpdated(mExpandedHeight); @@ -793,7 +756,6 @@ public class PanelView extends FrameLayout { mClosing = true; onExpandingStarted(); // collapse() should never be a rubberband, even if an animation is already running - mRubberbanding = false; fling(-mSelfCollapseVelocityPx, /*always=*/ true); } } @@ -817,14 +779,13 @@ public class PanelView extends FrameLayout { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s" - + " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s" + + " tracking=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s" + "]", this.getClass().getSimpleName(), getExpandedHeight(), getMaxPanelHeight(), mClosing?"T":"f", mTracking?"T":"f", - mRubberbanding?"T":"f", mJustPeeked?"T":"f", mPeekAnimator, ((mPeekAnimator!=null && mPeekAnimator.isStarted())?" (started)":""), mTimeAnimator, ((mTimeAnimator!=null && mTimeAnimator.isStarted())?" (started)":"") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index d5770702e6a5..4ad582f0e17f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -220,11 +220,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // settings QuickSettings mQS; - boolean mHasSettingsPanel, mHasFlipSettings; - SettingsPanelView mSettingsPanel; + boolean mHasQuickSettings; View mFlipSettingsView; QuickSettingsContainerView mSettingsContainer; - int mSettingsPanelGravity; // top bar View mNotificationPanelHeader; @@ -315,9 +313,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mHeaderFlipper.userSetup(userSetup); mKeyguardFlipper.userSetup(userSetup); - if (mSettingsPanel != null) { - mSettingsPanel.setEnabled(userSetup); - } if (userSetup != mUserSetup) { mUserSetup = userSetup; if (!mUserSetup && mStatusBarView != null) @@ -625,8 +620,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mClearButton.setEnabled(false); mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date); - mHasSettingsPanel = res.getBoolean(R.bool.config_hasSettingsPanel); - mHasFlipSettings = res.getBoolean(R.bool.config_hasFlipSettingsPanel); + mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings); mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime); if (mDateTimeView != null) { @@ -634,10 +628,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mDateTimeView.setEnabled(true); } - mHeaderFlipper = new FlipperButton(mNotificationPanelHeader - .findViewById(R.id.settings_button_holder)); - ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub); - mKeyguardFlipper = new FlipperButton(flipStub.inflate()); + mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper)); + mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper)); if (!mNotificationPanelIsFullScreenWidth) { mNotificationPanel.setSystemUiVisibility( @@ -715,37 +707,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // Quick Settings (where available, some restrictions apply) mNotificationPadding = mContext.getResources() .getDimensionPixelSize(R.dimen.notification_side_padding); - if (mHasSettingsPanel) { - // first, figure out where quick settings should be inflated - final View settings_stub; - if (mHasFlipSettings) { - // a version of quick settings that flips around behind the notifications - settings_stub = mStatusBarWindow.findViewById(R.id.flip_settings_stub); - if (settings_stub != null) { - mFlipSettingsView = ((ViewStub)settings_stub).inflate(); - mFlipSettingsView.setVisibility(View.GONE); - mFlipSettingsView.setVerticalScrollBarEnabled(false); - } - } else { - // full quick settings panel - settings_stub = mStatusBarWindow.findViewById(R.id.quick_settings_stub); - if (settings_stub != null) { - mSettingsPanel = (SettingsPanelView) ((ViewStub)settings_stub).inflate(); - } else { - mSettingsPanel = (SettingsPanelView) mStatusBarWindow.findViewById(R.id.settings_panel); - } - - if (mSettingsPanel != null) { - if (!ActivityManager.isHighEndGfx()) { - mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor( - R.color.notification_panel_solid_background))); - } - } - } - - // wherever you find it, Quick Settings needs a container to survive + if (mHasQuickSettings) { + // Quick Settings needs a container to survive mSettingsContainer = (QuickSettingsContainerView) mStatusBarWindow.findViewById(R.id.quick_settings_container); + mFlipSettingsView = mSettingsContainer; if (mSettingsContainer != null) { mQS = new QuickSettings(mContext, mSettingsContainer); if (!mNotificationPanelIsFullScreenWidth) { @@ -753,9 +719,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS | View.STATUS_BAR_DISABLE_SYSTEM_INFO); } - if (mSettingsPanel != null) { - mSettingsPanel.setQuickSettings(mQS); - } mQS.setService(this); mQS.setBar(mStatusBarView); mQS.setup(mNetworkController, mBluetoothController, mBatteryController, @@ -784,6 +747,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } public boolean onSettingsEvent(MotionEvent event) { + userActivity(); + if (mSettingsClosing + && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) { + return true; + } if (mSettingsTracker != null) { mSettingsTracker.addMovement(event); } @@ -851,15 +819,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } private void positionSettings(float dy) { - final int h = mFlipSettingsView.getMeasuredHeight(); - final int ph = mNotificationPanel.getMeasuredHeight(); if (mSettingsClosing) { + final int ph = mNotificationPanel.getMeasuredHeight(); dy = Math.min(Math.max(-ph, dy), 0); mFlipSettingsView.setTranslationY(dy); mStackScroller.setTranslationY(ph + dy); } else { - dy = Math.min(Math.max(0, dy), ph); - mFlipSettingsView.setTranslationY(-h + dy - mNotificationPadding * 2); + final int h = mFlipSettingsView.getBottom(); + dy = Math.min(Math.max(0, dy), h); + mFlipSettingsView.setTranslationY(-h + dy); mStackScroller.setTranslationY(dy); } } @@ -1397,8 +1365,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { + " any=" + any + " clearable=" + clearable); } - if (mHasFlipSettings - && mFlipSettingsView != null + if (mFlipSettingsView != null && mFlipSettingsView.getVisibility() == View.VISIBLE && mStackScroller.getVisibility() != View.VISIBLE) { // the flip settings panel is unequivocally showing; we should not be shown @@ -1758,7 +1725,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } mNotificationPanel.expand(); - if (mHasFlipSettings && mStackScroller.getVisibility() != View.VISIBLE) { + if (mStackScroller.getVisibility() != View.VISIBLE) { flipToNotifications(); } @@ -1771,17 +1738,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mHeaderFlipper.cancel(); mKeyguardFlipper.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); - mStackScroller.setVisibility(View.VISIBLE); final int h = mNotificationPanel.getMeasuredHeight(); final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0; final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h; mScrollViewAnim = start( - startDelay(0, interpolator(mDecelerateInterpolator, ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0) .setDuration(FLIP_DURATION) - ))); + )); mFlipSettingsViewAnim = start( setVisibilityWhenDone( interpolator(mDecelerateInterpolator, @@ -1814,14 +1779,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // Settings are not available in setup if (!mUserSetup) return; - if (mHasFlipSettings) { - mNotificationPanel.expand(); - if (mFlipSettingsView.getVisibility() != View.VISIBLE - || mFlipSettingsView.getTranslationY() < 0) { - flipToSettings(); - } - } else if (mSettingsPanel != null) { - mSettingsPanel.expand(); + mNotificationPanel.expand(); + if (mFlipSettingsView.getVisibility() != View.VISIBLE + || mFlipSettingsView.getTranslationY() < 0) { + flipToSettings(); } if (false) postStartTracing(); @@ -1879,12 +1840,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } public void flipPanels() { - if (mHasFlipSettings) { - if (mFlipSettingsView.getVisibility() != View.VISIBLE) { - flipToSettings(); - } else { - flipToNotifications(); - } + if (mFlipSettingsView.getVisibility() != View.VISIBLE) { + flipToSettings(); + } else { + flipToNotifications(); } } @@ -1907,21 +1866,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) mStatusBarView.collapseAllPanels(/*animate=*/ false); - if (mHasFlipSettings) { - // reset things to their proper state - if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); - if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mClearButtonAnim != null) mClearButtonAnim.cancel(); + // reset things to their proper state + if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); + if (mScrollViewAnim != null) mScrollViewAnim.cancel(); + if (mClearButtonAnim != null) mClearButtonAnim.cancel(); - mStackScroller.setVisibility(View.VISIBLE); - mNotificationPanel.setVisibility(View.GONE); - mFlipSettingsView.setVisibility(View.GONE); + mStackScroller.setVisibility(View.VISIBLE); + mNotificationPanel.setVisibility(View.GONE); + mFlipSettingsView.setVisibility(View.GONE); - setAreThereNotifications(); // show the clear button + setAreThereNotifications(); // show the clear button - mHeaderFlipper.reset(); - mKeyguardFlipper.reset(); - } + mHeaderFlipper.reset(); + mKeyguardFlipper.reset(); mExpandedVisible = false; if (mNavigationBarView != null) @@ -2366,12 +2323,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { pw.print (" "); mNotificationPanel.dump(fd, pw, args); } - if (mSettingsPanel != null) { - pw.println(" mSettingsPanel=" + - mSettingsPanel + " params=" + mSettingsPanel.getLayoutParams().debug("")); - pw.print (" "); - mSettingsPanel.dump(fd, pw, args); - } if (DUMPTRUCK) { synchronized (mNotificationData) { @@ -2474,13 +2425,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { lp.setMarginStart(mNotificationPanelMarginPx); mNotificationPanel.setLayoutParams(lp); - if (mSettingsPanel != null) { - lp = (FrameLayout.LayoutParams) mSettingsPanel.getLayoutParams(); - lp.gravity = mSettingsPanelGravity; - lp.setMarginEnd(mNotificationPanelMarginPx); - mSettingsPanel.setLayoutParams(lp); - } - if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) { mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx); mStackScroller.getLocationOnScreen(mStackScrollerPosition); @@ -2536,7 +2480,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() { public void onClick(View v) { - if (mHasSettingsPanel) { + if (mHasQuickSettings) { animateExpandSettingsPanel(); } else { startActivityDismissingKeyguard( @@ -2734,11 +2678,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (mNotificationPanelGravity <= 0) { mNotificationPanelGravity = Gravity.START | Gravity.TOP; } - mSettingsPanelGravity = res.getInteger(R.integer.settings_panel_layout_gravity); - Log.d(TAG, "mSettingsPanelGravity = " + mSettingsPanelGravity); - if (mSettingsPanelGravity <= 0) { - mSettingsPanelGravity = Gravity.END | Gravity.TOP; - } mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height); mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height); @@ -3039,12 +2978,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { * @return a ViewGroup that spans the entire panel which contains the quick settings */ public ViewGroup getQuickSettingsOverlayParent() { - if (mHasSettingsPanel) { - if (mHasFlipSettings) { - return mNotificationPanel; - } else { - return mSettingsPanel; - } + if (mHasQuickSettings) { + return mNotificationPanel; } else { return null; } @@ -3070,7 +3005,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button); if (mSettingsButton != null) { mSettingsButton.setOnClickListener(mSettingsButtonListener); - if (mHasSettingsPanel) { + if (mHasQuickSettings) { // the settings panel is hiding behind this button mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); mSettingsButton.setVisibility(View.VISIBLE); @@ -3080,11 +3015,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mSettingsButton.setImageResource(R.drawable.ic_notify_settings); } } - if (mHasFlipSettings) { - mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button); - if (mNotificationButton != null) { - mNotificationButton.setOnClickListener(mNotificationButtonListener); - } + mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button); + if (mNotificationButton != null) { + mNotificationButton.setOnClickListener(mNotificationButtonListener); } } @@ -3099,7 +3032,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } public void userSetup(boolean userSetup) { - if (mSettingsButton != null && mHasFlipSettings) { + if (mSettingsButton != null) { mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); } } @@ -3128,25 +3061,27 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mSettingsButtonAnim = start( setVisibilityWhenDone( ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f) - .setDuration(FLIP_DURATION), + .setDuration(FLIP_DURATION_OUT), mStackScroller, View.INVISIBLE)); mNotificationButton.setVisibility(View.VISIBLE); mNotificationButtonAnim = start( - ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) - .setDuration(FLIP_DURATION)); + startDelay(FLIP_DURATION_OUT, + ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) + .setDuration(FLIP_DURATION_IN))); } public void flipToNotifications() { mNotificationButtonAnim = start( setVisibilityWhenDone( ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f) - .setDuration(FLIP_DURATION), + .setDuration(FLIP_DURATION_OUT), mNotificationButton, View.INVISIBLE)); mSettingsButton.setVisibility(View.VISIBLE); mSettingsButtonAnim = start( - ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) - .setDuration(FLIP_DURATION)); + startDelay(FLIP_DURATION_OUT, + ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) + .setDuration(FLIP_DURATION_IN))); } public void cancel() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 583fc3e4754f..6ba18b35faa1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -38,13 +38,10 @@ public class PhoneStatusBarView extends PanelBar { PhoneStatusBar mBar; int mScrimColor; int mScrimColorKeyguard; - float mSettingsPanelDragzoneFrac; - float mSettingsPanelDragzoneMin; - boolean mFullWidthNotifications; PanelView mFadingPanel = null; PanelView mLastFullyOpenedPanel = null; - PanelView mNotificationPanel, mSettingsPanel; + PanelView mNotificationPanel; private boolean mShouldFade; private final PhoneStatusBarTransitions mBarTransitions; @@ -54,13 +51,6 @@ public class PhoneStatusBarView extends PanelBar { Resources res = getContext().getResources(); mScrimColor = res.getColor(R.color.notification_panel_scrim_color); mScrimColorKeyguard = res.getColor(R.color.notification_panel_scrim_color_keyguard); - mSettingsPanelDragzoneMin = res.getDimension(R.dimen.settings_panel_dragzone_min); - try { - mSettingsPanelDragzoneFrac = res.getFraction(R.dimen.settings_panel_dragzone_fraction, 1, 1); - } catch (NotFoundException ex) { - mSettingsPanelDragzoneFrac = 0f; - } - mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f; mBarTransitions = new PhoneStatusBarTransitions(this); } @@ -72,15 +62,8 @@ public class PhoneStatusBarView extends PanelBar { mBar = bar; } - public boolean hasFullWidthNotifications() { - return mFullWidthNotifications; - } - @Override public void onAttachedToWindow() { - for (PanelView pv : mPanels) { - pv.setRubberbandingEnabled(!mFullWidthNotifications); - } mBarTransitions.init(); } @@ -89,10 +72,7 @@ public class PhoneStatusBarView extends PanelBar { super.addPanel(pv); if (pv.getId() == R.id.notification_panel) { mNotificationPanel = pv; - } else if (pv.getId() == R.id.settings_panel){ - mSettingsPanel = pv; } - pv.setRubberbandingEnabled(!mFullWidthNotifications); } @Override @@ -117,34 +97,10 @@ public class PhoneStatusBarView extends PanelBar { @Override public PanelView selectPanelForTouch(MotionEvent touch) { - final float x = touch.getX(); - final boolean isLayoutRtl = isLayoutRtl(); - - if (mFullWidthNotifications) { - // No double swiping. If either panel is open, nothing else can be pulled down. - return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight()) - + mNotificationPanel.getExpandedHeight() > 0) - ? null - : mNotificationPanel; - } - - // We split the status bar into thirds: the left 2/3 are for notifications, and the - // right 1/3 for quick settings. If you pull the status bar down a second time you'll - // toggle panels no matter where you pull it down. - - final float w = getMeasuredWidth(); - float region = (w * mSettingsPanelDragzoneFrac); - - if (DEBUG) { - Log.v(TAG, String.format( - "w=%.1f frac=%.3f region=%.1f min=%.1f x=%.1f w-x=%.1f", - w, mSettingsPanelDragzoneFrac, region, mSettingsPanelDragzoneMin, x, (w-x))); - } - - if (region < mSettingsPanelDragzoneMin) region = mSettingsPanelDragzoneMin; - - final boolean showSettings = isLayoutRtl ? (x < region) : (w - region < x); - return showSettings ? mSettingsPanel : mNotificationPanel; + // No double swiping. If either panel is open, nothing else can be pulled down. + return mNotificationPanel.getExpandedHeight() > 0 + ? null + : mNotificationPanel; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java index 02e9c0d7ce57..c44cb0ca456d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java @@ -62,18 +62,19 @@ class QuickSettingsContainerView extends FrameLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - mScrim = new ScrimView(mContext); - addView(mScrim); - mScrim.setAlpha(sShowScrim ? 1 : 0); + if (sShowScrim) { + mScrim = new ScrimView(mContext); + addView(mScrim); + } // TODO: Setup the layout transitions LayoutTransition transitions = getLayoutTransition(); } @Override public boolean onTouchEvent(MotionEvent event) { - if (mScrim.getAlpha() == 1) { - mScrim.animate().alpha(0).setDuration(1000).start(); + if (mScrim != null) { sShowScrim = false; + removeView(mScrim); } return super.onTouchEvent(event); } @@ -144,7 +145,9 @@ class QuickSettingsContainerView extends FrameLayout { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - mScrim.bringToFront(); + if (mScrim != null) { + mScrim.bringToFront(); + } final int N = getChildCount(); final boolean isLayoutRtl = isLayoutRtl(); final int width = getWidth(); @@ -206,6 +209,7 @@ class QuickSettingsContainerView extends FrameLayout { } private static final class ScrimView extends View { + private static final int SCRIM = 0x4f000000; private static final int COLOR = 0xaf4285f4; private final Paint mLinePaint; @@ -240,6 +244,7 @@ class QuickSettingsContainerView extends FrameLayout { final int h = getMeasuredHeight(); final int f = mStrokeWidth * 3 / 4; + canvas.drawColor(SCRIM); canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint); canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java deleted file mode 100644 index c10a0d4b8e59..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.EventLog; -import android.view.MotionEvent; -import android.view.View; -import android.view.accessibility.AccessibilityEvent; - -import com.android.systemui.EventLogTags; -import com.android.systemui.R; -import com.android.systemui.statusbar.GestureRecorder; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.BluetoothController; -import com.android.systemui.statusbar.policy.LocationController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RotationLockController; - -public class SettingsPanelView extends PanelView { - public static final boolean DEBUG_GESTURES = true; - - private QuickSettings mQS; - private QuickSettingsContainerView mQSContainer; - - Drawable mHandleBar; - int mHandleBarHeight; - View mHandleView; - - public SettingsPanelView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mQSContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container); - - Resources resources = getContext().getResources(); - mHandleBar = resources.getDrawable(R.drawable.status_bar_close); - mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height); - mHandleView = findViewById(R.id.handle); - } - - public void setQuickSettings(QuickSettings qs) { - mQS = qs; - } - - @Override - public void setBar(PanelBar panelBar) { - super.setBar(panelBar); - - if (mQS != null) { - mQS.setBar(panelBar); - } - } - - public void setImeWindowStatus(boolean visible) { - if (mQS != null) { - mQS.setImeWindowStatus(visible); - } - } - - public void setup(NetworkController networkController, BluetoothController bluetoothController, - BatteryController batteryController, LocationController locationController, - RotationLockController rotationLockController) { - if (mQS != null) { - mQS.setup(networkController, bluetoothController, batteryController, - locationController, rotationLockController); - } - } - - void updateResources() { - if (mQS != null) { - mQS.updateResources(); - } - if (mQSContainer != null) { - mQSContainer.updateResources(); - } - requestLayout(); - } - - @Override - public void fling(float vel, boolean always) { - GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder(); - if (gr != null) { - gr.tag( - "fling " + ((vel > 0) ? "open" : "closed"), - "settings,v=" + vel); - } - super.fling(vel, always); - } - - public void setService(PhoneStatusBar phoneStatusBar) { - if (mQS != null) { - mQS.setService(phoneStatusBar); - } - } - - @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - event.getText() - .add(getContext().getString(R.string.accessibility_desc_quick_settings)); - return true; - } - - return super.dispatchPopulateAccessibilityEvent(event); - } - - // We draw the handle ourselves so that it's always glued to the bottom of the window. - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (changed) { - final int pl = getPaddingLeft(); - final int pr = getPaddingRight(); - mHandleBar.setBounds(pl, 0, getWidth() - pr, (int) mHandleBarHeight); - } - } - - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - final int off = (int) (getHeight() - mHandleBarHeight - getPaddingBottom()); - canvas.translate(0, off); - mHandleBar.setState(mHandleView.getDrawableState()); - mHandleBar.draw(canvas); - canvas.translate(0, -off); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (DEBUG_GESTURES) { - if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { - EventLog.writeEvent(EventLogTags.SYSUI_QUICKPANEL_TOUCH, - event.getActionMasked(), (int) event.getX(), (int) event.getY()); - } - } - return super.onTouchEvent(event); - } -} diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index bce85cee338b..724998570cb0 100644 --- a/services/core/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -106,22 +106,33 @@ public class BootReceiver extends BroadcastReceiver { .append("Kernel: ") .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n")) .append("\n").toString(); + final String bootReason = SystemProperties.get("ro.boot.bootreason", null); String recovery = RecoverySystem.handleAftermath(); if (recovery != null && db != null) { db.addText("SYSTEM_RECOVERY_LOG", headers + recovery); } + String lastKmsgFooter = ""; + if (bootReason != null) { + lastKmsgFooter = new StringBuilder(512) + .append("\n") + .append("Boot info:\n") + .append("Last boot reason: ").append(bootReason).append("\n") + .toString(); + } + if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) { String now = Long.toString(System.currentTimeMillis()); SystemProperties.set("ro.runtime.firstboot", now); if (db != null) db.addText("SYSTEM_BOOT", headers); // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile()) - addFileToDropBox(db, prefs, headers, "/proc/last_kmsg", - -LOG_SIZE, "SYSTEM_LAST_KMSG"); - addFileToDropBox(db, prefs, headers, "/sys/fs/pstore/console-ramoops", - -LOG_SIZE, "SYSTEM_LAST_KMSG"); + addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter, + "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG"); + addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter, + "/sys/fs/pstore/console-ramoops", -LOG_SIZE, + "SYSTEM_LAST_KMSG"); addFileToDropBox(db, prefs, headers, "/cache/recovery/log", -LOG_SIZE, "SYSTEM_RECOVERY_LOG"); addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console", @@ -161,6 +172,14 @@ public class BootReceiver extends BroadcastReceiver { private static void addFileToDropBox( DropBoxManager db, SharedPreferences prefs, String headers, String filename, int maxSize, String tag) throws IOException { + addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize, + tag); + } + + private static void addFileWithFootersToDropBox( + DropBoxManager db, SharedPreferences prefs, + String headers, String footers, String filename, int maxSize, + String tag) throws IOException { if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled File file = new File(filename); @@ -176,7 +195,7 @@ public class BootReceiver extends BroadcastReceiver { } Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")"); - db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n")); + db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers); } private static void addAuditErrorsToDropBox(DropBoxManager db, SharedPreferences prefs, diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 9629bd1d02df..705862ab8b97 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -153,7 +153,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private NativeDaemonConnector mConnector; - private final Handler mMainHandler = new Handler(); + private final Handler mFgHandler; private IBatteryStats mBatteryStats; @@ -203,6 +203,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub private NetworkManagementService(Context context, String socket) { mContext = context; + // make sure this is on the same looper as our NativeDaemonConnector for sync purposes + mFgHandler = new Handler(FgThread.get().getLooper()); + if ("simulator".equals(SystemProperties.get("ro.product.device"))) { return; } @@ -271,14 +274,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceStatusChanged(String iface, boolean up) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -287,14 +293,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceLinkStateChanged(String iface, boolean up) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -302,14 +311,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceAdded(String iface) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceAdded(iface); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceAdded(iface); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -322,14 +334,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub mActiveQuotas.remove(iface); final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceRemoved(iface); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceRemoved(iface); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -337,14 +352,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyLimitReached(String limitName, String iface) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).limitReached(limitName, iface); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).limitReached(limitName, iface); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -357,15 +375,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub } final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged( - Integer.toString(type), active, tsNanos); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged( + Integer.toString(type), active, tsNanos); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); boolean report = false; synchronized (mIdleTimerLock) { @@ -456,14 +477,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyAddressUpdated(String iface, LinkAddress address) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).addressUpdated(iface, address); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).addressUpdated(iface, address); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -471,14 +495,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyAddressRemoved(String iface, LinkAddress address) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).addressRemoved(iface, address); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).addressRemoved(iface, address); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -486,14 +513,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, addresses); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, + addresses); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } // @@ -509,7 +540,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mConnectedSignal.countDown(); mConnectedSignal = null; } else { - mMainHandler.post(new Runnable() { + mFgHandler.post(new Runnable() { @Override public void run() { prepareNativeDaemon(); @@ -1270,7 +1301,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (ConnectivityManager.isNetworkTypeMobile(type)) { mNetworkActive = false; } - mMainHandler.post(new Runnable() { + mFgHandler.post(new Runnable() { @Override public void run() { notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos()); } @@ -1297,7 +1328,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw e.rethrowAsParcelableException(); } mActiveIdleTimers.remove(iface); - mMainHandler.post(new Runnable() { + mFgHandler.post(new Runnable() { @Override public void run() { notifyInterfaceClassActivity(params.type, false, SystemClock.elapsedRealtimeNanos()); @@ -1880,14 +1911,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub private void reportNetworkActive() { final int length = mNetworkActivityListeners.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive(); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive(); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mNetworkActivityListeners.finishBroadcast(); } - mNetworkActivityListeners.finishBroadcast(); } /** {@inheritDoc} */ diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java new file mode 100644 index 000000000000..8a30e50c9aaf --- /dev/null +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server; + +import android.Manifest.permission; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.INetworkScoreService; +import android.net.NetworkKey; +import android.net.NetworkScorerAppManager; +import android.net.RssiCurve; +import android.net.ScoredNetwork; +import android.text.TextUtils; + +import com.android.internal.R; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +/** + * Backing service for {@link android.net.NetworkScoreManager}. + * @hide + */ +public class NetworkScoreService extends INetworkScoreService.Stub { + private static final String TAG = "NetworkScoreService"; + + /** SharedPreference bit set to true after the service is first initialized. */ + private static final String PREF_SCORING_PROVISIONED = "is_provisioned"; + + private final Context mContext; + + // TODO: Delete this temporary class once we have a real place for scores. + private final Map<NetworkKey, RssiCurve> mScoredNetworks; + + public NetworkScoreService(Context context) { + mContext = context; + mScoredNetworks = new HashMap<>(); + } + + /** Called when the system is ready to run third-party code but before it actually does so. */ + void systemReady() { + SharedPreferences prefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE); + if (!prefs.getBoolean(PREF_SCORING_PROVISIONED, false)) { + // On first run, we try to initialize the scorer to the one configured at build time. + // This will be a no-op if the scorer isn't actually valid. + String defaultPackage = mContext.getResources().getString( + R.string.config_defaultNetworkScorerPackageName); + if (!TextUtils.isEmpty(defaultPackage)) { + NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage); + } + prefs.edit().putBoolean(PREF_SCORING_PROVISIONED, true).apply(); + } + } + + @Override + public boolean updateScores(ScoredNetwork[] networks) { + if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) { + throw new SecurityException("Caller with UID " + getCallingUid() + + " is not the active scorer."); + } + + // TODO: Propagate these scores down to the network subsystem layer instead of just holding + // them in memory. + for (ScoredNetwork network : networks) { + mScoredNetworks.put(network.networkKey, network.rssiCurve); + } + + return true; + } + + @Override + public boolean clearScores() { + // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETWORKS) should + // be allowed to flush all scores. + if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) || + mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) == + PackageManager.PERMISSION_GRANTED) { + clearInternal(); + return true; + } else { + throw new SecurityException( + "Caller is neither the active scorer nor the scorer manager."); + } + } + + @Override + public boolean setActiveScorer(String packageName) { + mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG); + // Preemptively clear scores even though the set operation could fail. We do this for safety + // as scores should never be compared across apps; in practice, Settings should only be + // allowing valid apps to be set as scorers, so failure here should be rare. + clearInternal(); + return NetworkScorerAppManager.setActiveScorer(mContext, packageName); + } + + /** Clear scores. Callers are responsible for checking permissions as appropriate. */ + private void clearInternal() { + // TODO: Propagate the flush down to the network subsystem layer. + mScoredNetworks.clear(); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); + String currentScorer = NetworkScorerAppManager.getActiveScorer(mContext); + if (currentScorer == null) { + writer.println("Scoring is disabled."); + return; + } + writer.println("Current scorer: " + currentScorer); + if (mScoredNetworks.isEmpty()) { + writer.println("No networks scored."); + } else { + for (Map.Entry<NetworkKey, RssiCurve> entry : mScoredNetworks.entrySet()) { + writer.println(entry.getKey() + ": " + entry.getValue()); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 76074198070e..ecbb0d94a281 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7240,6 +7240,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (r == null) { return null; } + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } return mStackSupervisor.createActivityContainer(r, callback); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index d596472b5eb5..60adfb037524 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -139,7 +139,7 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity - ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>(); + ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>(); String stringName; // for caching of toString(). diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 8dd43170099b..0acde0950eb8 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -36,6 +36,8 @@ import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE; + import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; @@ -1066,9 +1068,9 @@ final class ActivityStack { private void setVisibile(ActivityRecord r, boolean visible) { r.visible = visible; mWindowManager.setAppVisibility(r.appToken, visible); - final ArrayList<ActivityStack> containers = r.mChildContainers; + final ArrayList<ActivityContainer> containers = r.mChildContainers; for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) { - ActivityContainer container = containers.get(containerNdx).mActivityContainer; + ActivityContainer container = containers.get(containerNdx); container.setVisible(visible); } } @@ -1270,6 +1272,7 @@ final class ActivityStack { * occurred and the activity will be notified immediately. */ void notifyActivityDrawnLocked(ActivityRecord r) { + mActivityContainer.setDrawn(); if ((r == null) || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { @@ -1336,7 +1339,8 @@ final class ActivityStack { if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(""); ActivityRecord parent = mActivityContainer.mParentActivity; - if (parent != null && parent.state != ActivityState.RESUMED) { + if ((parent != null && parent.state != ActivityState.RESUMED) || + !mActivityContainer.isAttached()) { // Do not resume this stack if its parent is not resumed. // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st. return false; @@ -2624,6 +2628,20 @@ final class ActivityStack { return r; } + void finishAllActivitiesLocked() { + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.finishing) { + continue; + } + Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r); + finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false); + } + } + } + final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode, Intent resultData) { final ActivityRecord srec = ActivityRecord.forToken(token); @@ -2862,7 +2880,6 @@ final class ActivityStack { } if (activityRemoved) { mStackSupervisor.resumeTopActivitiesLocked(); - } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 63f9d098cc14..111f010adb8c 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -96,7 +96,6 @@ import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -225,11 +224,11 @@ public final class ActivityStackSupervisor implements DisplayListener { // TODO: Add listener for removal of references. /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ - SparseArray<WeakReference<ActivityContainer>> mActivityContainers = - new SparseArray<WeakReference<ActivityContainer>>(); + SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); /** Mapping from displayId to display current state */ - private SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>(); + private final SparseArray<ActivityDisplay> mActivityDisplays = + new SparseArray<ActivityDisplay>(); InputManagerInternal mInputManagerInternal; @@ -265,7 +264,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mActivityDisplays.put(displayId, activityDisplay); } - createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); + createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY); mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); @@ -1386,7 +1385,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } // Need to create an app stack for this user. - int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY); + int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY); if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + " stackId=" + stackId); mFocusedStack = getStack(stackId); @@ -2154,14 +2153,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } ActivityStack getStack(int stackId) { - WeakReference<ActivityContainer> weakReference = mActivityContainers.get(stackId); - if (weakReference != null) { - ActivityContainer activityContainer = weakReference.get(); - if (activityContainer != null) { - return activityContainer.mStack; - } else { - mActivityContainers.remove(stackId); - } + ActivityContainer activityContainer = mActivityContainers.get(stackId); + if (activityContainer != null) { + return activityContainer.mStack; } return null; } @@ -2191,49 +2185,26 @@ public final class ActivityStackSupervisor implements DisplayListener { return null; } - ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId, - IActivityContainerCallback callback) { - ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId, - callback); - mActivityContainers.put(stackId, new WeakReference<ActivityContainer>(activityContainer)); - if (parentActivity != null) { - parentActivity.mChildContainers.add(activityContainer.mStack); - } - return activityContainer; - } - ActivityContainer createActivityContainer(ActivityRecord parentActivity, IActivityContainerCallback callback) { - return createActivityContainer(parentActivity, getNextStackId(), callback); + ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback); + mActivityContainers.put(activityContainer.mStackId, activityContainer); + parentActivity.mChildContainers.add(activityContainer); + return activityContainer; } void removeChildActivityContainers(ActivityRecord parentActivity) { - for (int ndx = mActivityContainers.size() - 1; ndx >= 0; --ndx) { - final ActivityContainer container = mActivityContainers.valueAt(ndx).get(); - if (container == null) { - mActivityContainers.removeAt(ndx); - continue; - } - if (container.mParentActivity != parentActivity) { - continue; - } - - ActivityStack stack = container.mStack; - ActivityRecord top = stack.topRunningNonDelayedActivityLocked(null); - if (top != null) { - // TODO: Make sure the next activity doesn't start up when top is destroyed. - stack.destroyActivityLocked(top, true, true, "stack parent destroyed"); - } - mActivityContainers.removeAt(ndx); - container.detachLocked(); + final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers; + for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) { + ActivityContainer container = childStacks.remove(containerNdx); + container.release(); } } void deleteActivityContainer(IActivityContainer container) { ActivityContainer activityContainer = (ActivityContainer)container; if (activityContainer != null) { - activityContainer.mStack.destroyActivitiesLocked(null, true, - "deleteActivityContainer"); + activityContainer.mStack.finishAllActivitiesLocked(); final ActivityRecord parent = activityContainer.mParentActivity; if (parent != null) { parent.mChildContainers.remove(activityContainer); @@ -2244,14 +2215,14 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) { + private int createStackOnDisplay(int stackId, int displayId) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); if (activityDisplay == null) { return -1; } - ActivityContainer activityContainer = - createActivityContainer(parentActivity, stackId, null); + ActivityContainer activityContainer = new ActivityContainer(stackId); + mActivityContainers.put(stackId, activityContainer); activityContainer.attachToDisplayLocked(activityDisplay); return stackId; } @@ -2334,9 +2305,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } boolean shutdownLocked(int timeout) { - boolean timedout = false; goingToSleepLocked(); + boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { boolean cantShutdown = false; @@ -3030,24 +3001,26 @@ public final class ActivityStackSupervisor implements DisplayListener { class ActivityContainer extends IActivityContainer.Stub { final int mStackId; - final IActivityContainerCallback mCallback; + IActivityContainerCallback mCallback = null; final ActivityStack mStack; - final ActivityRecord mParentActivity; - final String mIdString; + ActivityRecord mParentActivity = null; + String mIdString; boolean mVisible = true; /** Display this ActivityStack is currently on. Null if not attached to a Display. */ ActivityDisplay mActivityDisplay; - ActivityContainer(ActivityRecord parentActivity, int stackId, - IActivityContainerCallback callback) { + final static int CONTAINER_STATE_HAS_SURFACE = 0; + final static int CONTAINER_STATE_NO_SURFACE = 1; + final static int CONTAINER_STATE_FINISHING = 2; + int mContainerState = CONTAINER_STATE_HAS_SURFACE; + + ActivityContainer(int stackId) { synchronized (mService) { mStackId = stackId; mStack = new ActivityStack(this); - mParentActivity = parentActivity; - mCallback = callback; - mIdString = "ActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + mIdString = "ActivtyContainer{" + mStackId + "}"; if (DEBUG_STACK) Slog.d(TAG, "Creating " + this); } } @@ -3097,6 +3070,14 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + @Override + public void release() { + mContainerState = CONTAINER_STATE_FINISHING; + mStack.finishAllActivitiesLocked(); + detachLocked(); + mWindowManager.removeStack(mStackId); + } + private void detachLocked() { if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); @@ -3110,13 +3091,6 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void detachFromDisplay() { - synchronized (mService) { - detachLocked(); - } - } - - @Override public final int startActivity(Intent intent) { mService.enforceNotIsolatedCaller("ActivityContainer.startActivity"); int userId = mService.handleIncomingUser(Binder.getCallingPid(), @@ -3149,23 +3123,8 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void attachToSurface(Surface surface, int width, int height, int density) { + public void setSurface(Surface surface, int width, int height, int density) { mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface"); - - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mService) { - ActivityDisplay activityDisplay = - new ActivityDisplay(surface, width, height, density); - mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay); - attachToDisplayLocked(activityDisplay); - mStack.resumeTopActivityLocked(null); - } - if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display=" - + mActivityDisplay); - } finally { - Binder.restoreCallingIdentity(origId); - } } ActivityStackSupervisor getOuter() { @@ -3184,6 +3143,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + // TODO: Make sure every change to ActivityRecord.visible results in a call to this. void setVisible(boolean visible) { if (mVisible != visible) { mVisible = visible; @@ -3194,52 +3154,114 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + void setDrawn() { + } + @Override public String toString() { return mIdString + (mActivityDisplay == null ? "N" : "A"); } } + private class VirtualActivityContainer extends ActivityContainer { + Surface mSurface; + boolean mDrawn = false; + + VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) { + super(getNextStackId()); + mParentActivity = parent; + mCallback = callback; + mContainerState = CONTAINER_STATE_NO_SURFACE; + mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + } + + @Override + public void setSurface(Surface surface, int width, int height, int density) { + super.setSurface(surface, width, height, density); + + synchronized (mService) { + final long origId = Binder.clearCallingIdentity(); + try { + setSurfaceLocked(surface, width, height, density); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + private void setSurfaceLocked(Surface surface, int width, int height, int density) { + if (mContainerState == CONTAINER_STATE_FINISHING) { + return; + } + VirtualActivityDisplay virtualActivityDisplay = + (VirtualActivityDisplay) mActivityDisplay; + if (virtualActivityDisplay == null) { + virtualActivityDisplay = + new VirtualActivityDisplay(width, height, density); + mActivityDisplay = virtualActivityDisplay; + mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay); + attachToDisplayLocked(virtualActivityDisplay); + } + + if (mSurface != null) { + mSurface.release(); + } + + mSurface = surface; + if (surface != null) { + mStack.resumeTopActivityLocked(null); + } else { + mContainerState = CONTAINER_STATE_NO_SURFACE; + ((VirtualActivityDisplay) mActivityDisplay).setSurface(null); +// if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) { +// mStack.startPausingLocked(false, true); +// } + } + + setSurfaceIfReady(); + + if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display=" + + virtualActivityDisplay); + } + + @Override + void setDrawn() { + synchronized (mService) { + mDrawn = true; + setSurfaceIfReady(); + } + } + + private void setSurfaceIfReady() { + if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn + + " mContainerState=" + mContainerState + " mSurface=" + mSurface); + if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) { + ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface); + mContainerState = CONTAINER_STATE_HAS_SURFACE; + } + } + } + /** Exactly one of these classes per Display in the system. Capable of holding zero or more * attached {@link ActivityStack}s */ - final class ActivityDisplay { + class ActivityDisplay { /** Actual Display this object tracks. */ int mDisplayId; Display mDisplay; DisplayInfo mDisplayInfo = new DisplayInfo(); - Surface mSurface; /** All of the stacks on this display. Order matters, topmost stack is in front of all other * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>(); - /** If this display is for an ActivityView then the VirtualDisplay created for it is stored - * here. */ - VirtualDisplay mVirtualDisplay; + ActivityDisplay() { + } ActivityDisplay(int displayId) { init(mDisplayManager.getDisplay(displayId)); } - ActivityDisplay(Surface surface, int width, int height, int density) { - DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); - long ident = Binder.clearCallingIdentity(); - try { - mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, - VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface, - DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | - DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); - } finally { - Binder.restoreCallingIdentity(ident); - } - - init(mVirtualDisplay.getDisplay()); - mSurface = surface; - - mWindowManager.handleDisplayAdded(mDisplayId); - } - - private void init(Display display) { + void init(Display display) { mDisplay = display; mDisplayId = display.getDisplayId(); mDisplay.getDisplayInfo(mDisplayInfo); @@ -3255,11 +3277,6 @@ public final class ActivityStackSupervisor implements DisplayListener { if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); - if (mStacks.isEmpty() && mVirtualDisplay != null) { - mVirtualDisplay.release(); - mVirtualDisplay = null; - } - mSurface.release(); } void getBounds(Point bounds) { @@ -3270,8 +3287,42 @@ public final class ActivityStackSupervisor implements DisplayListener { @Override public String toString() { - return "ActivityDisplay={" + mDisplayId + (mVirtualDisplay == null ? "" : "V") - + " numStacks=" + mStacks.size() + "}"; + return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; + } + } + + class VirtualActivityDisplay extends ActivityDisplay { + VirtualDisplay mVirtualDisplay; + + VirtualActivityDisplay(int width, int height, int density) { + DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); + mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, VIRTUAL_DISPLAY_BASE_NAME, + width, height, density, null, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | + DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); + + init(mVirtualDisplay.getDisplay()); + + mWindowManager.handleDisplayAdded(mDisplayId); + } + + void setSurface(Surface surface) { + if (mVirtualDisplay != null) { + mVirtualDisplay.setSurface(surface); + } + } + + @Override + void detachActivitiesLocked(ActivityStack stack) { + super.detachActivitiesLocked(stack); + if (mVirtualDisplay != null) { + mVirtualDisplay.release(); + mVirtualDisplay = null; + } + } + + @Override + public String toString() { + return "VirtualActivityDisplay={" + mDisplayId + "}"; } } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 75e5857612b8..6700895dba9a 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -26,6 +26,7 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.graphics.Rect; import android.net.Uri; import android.os.Binder; import android.os.IBinder; @@ -42,6 +43,7 @@ import android.tv.TvInputInfo; import android.tv.TvInputService; import android.util.ArrayMap; import android.util.Log; +import android.util.Slog; import android.util.SparseArray; import android.view.Surface; @@ -116,17 +118,19 @@ public final class TvInputManagerService extends SystemService { UserState userState = getUserStateLocked(userId); userState.inputList.clear(); + if (DEBUG) Slog.d(TAG, "buildTvInputList"); PackageManager pm = mContext.getPackageManager(); List<ResolveInfo> services = pm.queryIntentServices( new Intent(TvInputService.SERVICE_INTERFACE), PackageManager.GET_SERVICES); for (ResolveInfo ri : services) { ServiceInfo si = ri.serviceInfo; if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) { - Log.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission " + Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission " + android.Manifest.permission.BIND_TV_INPUT); continue; } TvInputInfo info = new TvInputInfo(ri); + if (DEBUG) Slog.d(TAG, "add " + info.getId()); userState.inputList.add(info); } } @@ -161,7 +165,7 @@ public final class TvInputManagerService extends SystemService { try { state.session.release(); } catch (RemoteException e) { - Log.e(TAG, "error in release", e); + Slog.e(TAG, "error in release", e); } } } @@ -173,7 +177,7 @@ public final class TvInputManagerService extends SystemService { try { serviceState.service.unregisterCallback(serviceState.callback); } catch (RemoteException e) { - Log.e(TAG, "error in unregisterCallback", e); + Slog.e(TAG, "error in unregisterCallback", e); } } serviceState.clients.clear(); @@ -244,7 +248,7 @@ public final class TvInputManagerService extends SystemService { return; } if (DEBUG) { - Log.i(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId + Slog.d(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId + ")"); } Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(name); @@ -255,7 +259,7 @@ public final class TvInputManagerService extends SystemService { // This means that the service is already connected but its state indicates that we have // nothing to do with it. Then, disconnect the service. if (DEBUG) { - Log.i(TAG, "unbindService(name=" + name.getClassName() + ")"); + Slog.d(TAG, "unbindService(name=" + name.getClassName() + ")"); } mContext.unbindService(serviceState.connection); userState.serviceStateMap.remove(name); @@ -267,7 +271,7 @@ public final class TvInputManagerService extends SystemService { final SessionState sessionState = getUserStateLocked(userId).sessionStateMap.get(sessionToken); if (DEBUG) { - Log.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName() + Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName() + ")"); } // Set up a callback to send the session token. @@ -275,7 +279,7 @@ public final class TvInputManagerService extends SystemService { @Override public void onSessionCreated(ITvInputSession session) { if (DEBUG) { - Log.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")"); + Slog.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")"); } synchronized (mLock) { sessionState.session = session; @@ -295,7 +299,7 @@ public final class TvInputManagerService extends SystemService { try { service.createSession(callback); } catch (RemoteException e) { - Log.e(TAG, "error in createSession", e); + Slog.e(TAG, "error in createSession", e); removeSessionStateLocked(sessionToken, userId); sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, sessionState.seq, userId); @@ -307,7 +311,7 @@ public final class TvInputManagerService extends SystemService { try { client.onSessionCreated(name, sessionToken, seq); } catch (RemoteException exception) { - Log.e(TAG, "error in onSessionCreated", exception); + Slog.e(TAG, "error in onSessionCreated", exception); } if (sessionToken == null) { @@ -396,7 +400,7 @@ public final class TvInputManagerService extends SystemService { try { serviceState.service.registerCallback(serviceState.callback); } catch (RemoteException e) { - Log.e(TAG, "error in registerCallback", e); + Slog.e(TAG, "error in registerCallback", e); } } else { updateServiceConnectionLocked(name, resolvedUserId); @@ -432,7 +436,7 @@ public final class TvInputManagerService extends SystemService { try { serviceState.service.unregisterCallback(serviceState.callback); } catch (RemoteException e) { - Log.e(TAG, "error in unregisterCallback", e); + Slog.e(TAG, "error in unregisterCallback", e); } finally { serviceState.callback = null; updateServiceConnectionLocked(name, resolvedUserId); @@ -493,7 +497,7 @@ public final class TvInputManagerService extends SystemService { try { getSessionLocked(sessionToken, callingUid, resolvedUserId).release(); } catch (RemoteException e) { - Log.e(TAG, "error in release", e); + Slog.e(TAG, "error in release", e); } removeSessionStateLocked(sessionToken, resolvedUserId); @@ -515,7 +519,7 @@ public final class TvInputManagerService extends SystemService { getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface( surface); } catch (RemoteException e) { - Log.e(TAG, "error in setSurface", e); + Slog.e(TAG, "error in setSurface", e); } } } finally { @@ -535,7 +539,7 @@ public final class TvInputManagerService extends SystemService { getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume( volume); } catch (RemoteException e) { - Log.e(TAG, "error in setVolume", e); + Slog.e(TAG, "error in setVolume", e); } } } finally { @@ -551,13 +555,10 @@ public final class TvInputManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { - SessionState sessionState = getUserStateLocked(resolvedUserId) - .sessionStateMap.get(sessionToken); - final String serviceName = sessionState.name.getClassName(); try { getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri); } catch (RemoteException e) { - Log.e(TAG, "error in tune", e); + Slog.e(TAG, "error in tune", e); return; } } @@ -565,6 +566,67 @@ public final class TvInputManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } } + + @Override + public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame, + int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "createOverlayView"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId) + .createOverlayView(windowToken, frame); + } catch (RemoteException e) { + Slog.e(TAG, "error in createOverlayView", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "relayoutOverlayView"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId) + .relayoutOverlayView(frame); + } catch (RemoteException e) { + Slog.e(TAG, "error in relayoutOverlayView", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void removeOverlayView(IBinder sessionToken, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "removeOverlayView"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId) + .removeOverlayView(); + } catch (RemoteException e) { + Slog.e(TAG, "error in removeOverlayView", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } } private static final class UserState { @@ -621,7 +683,7 @@ public final class TvInputManagerService extends SystemService { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) { - Log.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")"); + Slog.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")"); } synchronized (mLock) { ServiceState serviceState = getServiceStateLocked(name, mUserId); @@ -633,7 +695,7 @@ public final class TvInputManagerService extends SystemService { try { serviceState.service.registerCallback(serviceState.callback); } catch (RemoteException e) { - Log.e(TAG, "error in registerCallback", e); + Slog.e(TAG, "error in registerCallback", e); } } @@ -647,7 +709,7 @@ public final class TvInputManagerService extends SystemService { @Override public void onServiceDisconnected(ComponentName name) { if (DEBUG) { - Log.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")"); + Slog.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")"); } } } @@ -663,7 +725,7 @@ public final class TvInputManagerService extends SystemService { public void onAvailabilityChanged(ComponentName name, boolean isAvailable) throws RemoteException { if (DEBUG) { - Log.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable=" + Slog.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable=" + isAvailable + ")"); } synchronized (mLock) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 912ac4da5e76..f08d69f3b825 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -311,6 +311,7 @@ public final class SystemServer { NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; ConnectivityService connectivity = null; + NetworkScoreService networkScore = null; NsdService serviceDiscovery= null; IPackageManager pm = null; WindowManagerService wm = null; @@ -643,6 +644,14 @@ public final class SystemServer { } try { + Slog.i(TAG, "Network Score Service"); + networkScore = new NetworkScoreService(context); + ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore); + } catch (Throwable e) { + reportWtf("starting Network Score Service", e); + } + + try { Slog.i(TAG, "Network Service Discovery Service"); serviceDiscovery = NsdService.create(context); ServiceManager.addService( @@ -1021,6 +1030,7 @@ public final class SystemServer { final NetworkStatsService networkStatsF = networkStats; final NetworkPolicyManagerService networkPolicyF = networkPolicy; final ConnectivityService connectivityF = connectivity; + final NetworkScoreService networkScoreF = networkScore; final DockObserver dockF = dock; final WallpaperManagerService wallpaperF = wallpaper; final InputMethodManagerService immF = imm; @@ -1069,6 +1079,11 @@ public final class SystemServer { reportWtf("making Battery Service ready", e); } try { + if (networkScoreF != null) networkScoreF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Score Service ready", e); + } + try { if (networkManagementF != null) networkManagementF.systemReady(); } catch (Throwable e) { reportWtf("making Network Managment Service ready", e); |