Merge changes Ie3c8ca8d,Ia175b36d into jb-mr1-dev
* changes:
Try to free cache before giving up on install
Robustly add symlink and add for non-primary users
diff --git a/api/current.txt b/api/current.txt
index d7f4e11..5462aee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7094,7 +7094,7 @@
method public int getIndexCount();
method public int getInt(int, int);
method public int getInteger(int, int);
- method public deprecated int getLayoutDimension(int, java.lang.String);
+ method public int getLayoutDimension(int, java.lang.String);
method public int getLayoutDimension(int, int);
method public java.lang.String getNonResourceString(int);
method public java.lang.String getPositionDescription();
@@ -16151,7 +16151,7 @@
public class Looper {
method public void dump(android.util.Printer, java.lang.String);
- method public static android.os.Looper getMainLooper();
+ method public static synchronized android.os.Looper getMainLooper();
method public java.lang.Thread getThread();
method public static void loop();
method public static android.os.Looper myLooper();
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7492629..67d3930 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2809,6 +2809,15 @@
return success;
}
+ public void clearPendingBackup() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(CLEAR_PENDING_BACKUP_TRANSACTION, data, reply, 0);
+ reply.recycle();
+ data.recycle();
+ }
+
public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5f65f08..456d757 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -29,6 +29,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ProviderInfo;
@@ -2396,12 +2397,31 @@
private void handleCreateBackupAgent(CreateBackupAgentData data) {
if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data);
+ // Sanity check the requested target package's uid against ours
+ try {
+ PackageInfo requestedPackage = getPackageManager().getPackageInfo(
+ data.appInfo.packageName, 0, UserHandle.myUserId());
+ if (requestedPackage.applicationInfo.uid != Process.myUid()) {
+ Slog.w(TAG, "Asked to instantiate non-matching package "
+ + data.appInfo.packageName);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Can't reach package manager", e);
+ return;
+ }
+
// no longer idle; we have backup work to do
unscheduleGcIdler();
// instantiate the BackupAgent class named in the manifest
LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
String packageName = packageInfo.mPackageName;
+ if (packageName == null) {
+ Slog.d(TAG, "Asked to create backup agent for nonexistent package");
+ return;
+ }
+
if (mBackupAgents.get(packageName) != null) {
Slog.d(TAG, "BackupAgent " + " for " + packageName
+ " already exists");
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 97250e9..8fc1c86 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -152,6 +152,7 @@
public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
throws RemoteException;
+ public void clearPendingBackup() throws RemoteException;
public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;
public void killApplicationProcess(String processName, int uid) throws RemoteException;
@@ -619,4 +620,5 @@
int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
+ int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
}
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 201d7b2..86fd7b9 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -312,7 +312,8 @@
}
public Editor putStringSet(String key, Set<String> values) {
synchronized (this) {
- mModified.put(key, values);
+ mModified.put(key,
+ (values == null) ? null : new HashSet<String>(values));
return this;
}
}
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index bdc38d6..da5480e 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -25,7 +25,8 @@
* there is a single instance of this class that all clients share.
* Modifications to the preferences must go through an {@link Editor} object
* to ensure the preference values remain in a consistent state and control
- * when they are committed to storage.
+ * when they are committed to storage. Objects that are returned from the
+ * various <code>get</code> methods must be treated as immutable by the application.
*
* <p><em>Note: currently this class does not support use across multiple
* processes. This will be added later.</em>
@@ -226,6 +227,10 @@
/**
* Retrieve all values from the preferences.
*
+ * <p>Note that you <em>must not</em> modify the collection returned
+ * by this method, or alter any of its contents. The consistency of your
+ * stored data is not guaranteed if you do.
+ *
* @return Returns a map containing a list of pairs key/value representing
* the preferences.
*
@@ -250,6 +255,10 @@
/**
* Retrieve a set of String values from the preferences.
*
+ * <p>Note that you <em>must not</em> modify the set instance returned
+ * by this call. The consistency of the stored data is not guaranteed
+ * if you do, nor is your ability to modify the instance at all.
+ *
* @param key The name of the preference to retrieve.
* @param defValues Values to return if this preference does not exist.
*
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 7f3b6b9..2968fbb 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -469,20 +469,13 @@
* {@link android.view.ViewGroup}'s layout_width and layout_height
* attributes. This is only here for performance reasons; applications
* should use {@link #getDimensionPixelSize}.
- *
+ *
* @param index Index of the attribute to retrieve.
* @param name Textual name of attribute for error reporting.
*
* @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels.
- *
- * @throws RuntimeException
- * if this TypedArray does not contain an entry for <code>index</code>
- *
- * @deprecated Use {@link #getLayoutDimension(int, int)} instead.
- *
*/
- @Deprecated
public int getLayoutDimension(int index, String name) {
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 4820c5e..6c9290b 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -51,12 +51,17 @@
* an exhibition/lean-back experience.</p>
*
* <p>The Dream lifecycle is as follows:</p>
- * <ul>
- * <li>onAttachedToWindow</li>
- * <li>onDreamingStarted</li>
- * <li>onDreamingStopped</li>
- * <li>onDetachedFromWindow</li>
- * </ul>
+ * <ol>
+ * <li>{@link #onAttachedToWindow}
+ * <p>Use this for initial setup, such as calling {@link #setContentView setContentView()}.</li>
+ * <li>{@link #onDreamingStarted}
+ * <p>Your dream has started, so you should begin animations or other behaviors here.</li>
+ * <li>{@link #onDreamingStopped}
+ * <p>Use this to stop the things you started in {@link #onDreamingStarted}.</li>
+ * <li>{@link #onDetachedFromWindow}
+ * <p>Use this to dismantle resources your dream set up. For example, detach from handlers
+ * and listeners.</li>
+ * </ol>
*
* <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
* initialization and teardown should be done by overriding the hooks above.</p>
@@ -80,14 +85,40 @@
* android:resource="@xml/my_dream" />
* </service>
* </pre>
- * <p>If specified, additional information for the dream is defined using the
- * <code><{@link android.R.styleable#Dream dream}></code> element. For example:</p>
- * <pre>
- * (in res/xml/my_dream.xml)
*
+ * <p>If specified with the {@code <meta-data>} element,
+ * additional information for the dream is defined using the
+ * {@link android.R.styleable#Dream <dream>} element in a separate XML file.
+ * Currently, the only addtional
+ * information you can provide is for a settings activity that allows the user to configure
+ * the dream behavior. For example:</p>
+ * <p class="code-caption">res/xml/my_dream.xml</p>
+ * <pre>
* <dream xmlns:android="http://schemas.android.com/apk/res/android"
* android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
* </pre>
+ * <p>This makes a Settings button available alongside your dream's listing in the
+ * system settings, which when pressed opens the specified activity.</p>
+ *
+ *
+ * <p>To specify your dream layout, call {@link #setContentView}, typically during the
+ * {@link #onAttachedToWindow} callback. For example:</p>
+ * <pre>
+ * public class MyDream extends DreamService {
+ *
+ * @Override
+ * public void onAttachedToWindow() {
+ * super.onAttachedToWindow();
+ *
+ * // Exit dream upon user touch
+ * setInteractive(false);
+ * // Hide system UI
+ * setFullscreen(true);
+ * // Set the dream layout
+ * setContentView(R.layout.dream);
+ * }
+ * }
+ * </pre>
*/
public class DreamService extends Service implements Window.Callback {
private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
@@ -323,11 +354,12 @@
/**
* Sets a view to be the content view for this Dream.
- * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
+ * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity,
* including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
*
- * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
- * @param view The desired content to display.
+ * <p>Note: This requires a window, so you should usually call it during
+ * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
+ * during {@link #onCreate}).</p>
*
* @see #setContentView(int)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
@@ -339,9 +371,12 @@
/**
* Sets a view to be the content view for this Dream.
* Behaves similarly to
- * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
+ * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
+ * in an activity.
*
- * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
+ * <p>Note: This requires a window, so you should usually call it during
+ * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
+ * during {@link #onCreate}).</p>
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index 70142ce..5f5b079 100644
--- a/core/java/android/service/dreams/Sandman.java
+++ b/core/java/android/service/dreams/Sandman.java
@@ -36,9 +36,6 @@
public final class Sandman {
private static final String TAG = "Sandman";
- private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
- private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
// The component name of a special dock app that merely launches a dream.
// We don't want to launch this app when docked because it causes an unnecessary
// activity transition. We just want to start the dream.
@@ -109,14 +106,18 @@
}
private static boolean isScreenSaverEnabled(Context context) {
+ int def = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledByDefault) ? 1 : 0;
return Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
+ Settings.Secure.SCREENSAVER_ENABLED, def,
UserHandle.USER_CURRENT) != 0;
}
private static boolean isScreenSaverActivatedOnDock(Context context) {
+ int def = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault) ? 1 : 0;
return Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
- DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, def,
+ UserHandle.USER_CURRENT) != 0;
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index ec1695e..59f941d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1200,7 +1200,12 @@
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
- status = onPreDraw(dirty);
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
+ try {
+ status = onPreDraw(dirty);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
saveCount = canvas.save();
callbacks.onHardwarePreDraw(canvas);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index f692e05..26a5b26 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -20,7 +20,6 @@
import android.os.Handler;
import android.os.Message;
import android.widget.FrameLayout;
-import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -44,20 +43,20 @@
*
* <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService
* (Context.LAYOUT_INFLATER_SERVICE);</pre>
- *
+ *
* <p>
* To create a new LayoutInflater with an additional {@link Factory} for your
* own views, you can use {@link #cloneInContext} to clone an existing
* ViewFactory, and then call {@link #setFactory} on it to include your
* Factory.
- *
+ *
* <p>
* For performance reasons, view inflation relies heavily on pre-processing of
* XML files that is done at build time. Therefore, it is not currently possible
* to use LayoutInflater with an XmlPullParser over a plain XML file at runtime;
* it only works with an XmlPullParser returned from a compiled resource
* (R.<em>something</em> file.)
- *
+ *
* @see Context#getSystemService
*/
public abstract class LayoutInflater {
@@ -83,7 +82,7 @@
private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
new HashMap<String, Constructor<? extends View>>();
-
+
private HashMap<String, Boolean> mFilterMap;
private static final String TAG_MERGE = "merge";
@@ -94,36 +93,36 @@
/**
* Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed
* to be inflated.
- *
+ *
*/
public interface Filter {
/**
* Hook to allow clients of the LayoutInflater to restrict the set of Views
* that are allowed to be inflated.
- *
+ *
* @param clazz The class object for the View that is about to be inflated
- *
+ *
* @return True if this class is allowed to be inflated, or false otherwise
*/
@SuppressWarnings("unchecked")
boolean onLoadClass(Class clazz);
}
-
+
public interface Factory {
/**
* Hook you can supply that is called when inflating from a LayoutInflater.
* You can use this to customize the tag names available in your XML
* layout files.
- *
+ *
* <p>
* Note that it is good practice to prefix these custom names with your
* package (i.e., com.coolcompany.apps) to avoid conflicts with system
* names.
- *
+ *
* @param name Tag name to be inflated.
* @param context The context the view is being created in.
* @param attrs Inflation attributes as specified in XML file.
- *
+ *
* @return View Newly created view. Return null for the default
* behavior.
*/
@@ -151,14 +150,14 @@
private static class FactoryMerger implements Factory2 {
private final Factory mF1, mF2;
private final Factory2 mF12, mF22;
-
+
FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
mF1 = f1;
mF2 = f2;
mF12 = f12;
mF22 = f22;
}
-
+
public View onCreateView(String name, Context context, AttributeSet attrs) {
View v = mF1.onCreateView(name, context, attrs);
if (v != null) return v;
@@ -173,13 +172,13 @@
: mF2.onCreateView(name, context, attrs);
}
}
-
+
/**
* Create a new LayoutInflater instance associated with a particular Context.
* Applications will almost always want to use
* {@link Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link Context#LAYOUT_INFLATER_SERVICE Context.INFLATER_SERVICE}.
- *
+ *
* @param context The Context in which this LayoutInflater will create its
* Views; most importantly, this supplies the theme from which the default
* values for their attributes are retrieved.
@@ -192,7 +191,7 @@
* Create a new LayoutInflater instance that is a copy of an existing
* LayoutInflater, optionally with its Context changed. For use in
* implementing {@link #cloneInContext}.
- *
+ *
* @param original The original LayoutInflater to copy.
* @param newContext The new Context to use.
*/
@@ -203,7 +202,7 @@
mPrivateFactory = original.mPrivateFactory;
mFilter = original.mFilter;
}
-
+
/**
* Obtains the LayoutInflater from the given context.
*/
@@ -221,15 +220,15 @@
* pointing to a different Context than the original. This is used by
* {@link ContextThemeWrapper} to create a new LayoutInflater to go along
* with the new Context theme.
- *
+ *
* @param newContext The new Context to associate with the new LayoutInflater.
* May be the same as the original Context if desired.
- *
+ *
* @return Returns a brand spanking new LayoutInflater object associated with
* the given Context.
*/
public abstract LayoutInflater cloneInContext(Context newContext);
-
+
/**
* Return the context we are running in, for access to resources, class
* loader, etc.
@@ -265,7 +264,7 @@
* called on each element name as the xml is parsed. If the factory returns
* a View, that is added to the hierarchy. If it returns null, the next
* factory default {@link #onCreateView} method is called.
- *
+ *
* <p>If you have an existing
* LayoutInflater and want to add your own factory to it, use
* {@link #cloneInContext} to clone the existing instance and then you
@@ -321,13 +320,13 @@
public Filter getFilter() {
return mFilter;
}
-
+
/**
* Sets the {@link Filter} to by this LayoutInflater. If a view is attempted to be inflated
* which is not allowed by the {@link Filter}, the {@link #inflate(int, ViewGroup)} call will
* throw an {@link InflateException}. This filter will replace any previous filter set on this
* LayoutInflater.
- *
+ *
* @param filter The Filter which restricts the set of Views that are allowed to be inflated.
* This filter will replace any previous filter set on this LayoutInflater.
*/
@@ -341,7 +340,7 @@
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
- *
+ *
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy.
@@ -361,7 +360,7 @@
* reasons, view inflation relies heavily on pre-processing of XML files
* that is done at build time. Therefore, it is not currently possible to
* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
- *
+ *
* @param parser XML dom node containing the description of the view
* hierarchy.
* @param root Optional view to be the parent of the generated hierarchy.
@@ -376,7 +375,7 @@
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
- *
+ *
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy (if
@@ -408,7 +407,7 @@
* reasons, view inflation relies heavily on pre-processing of XML files
* that is done at build time. Therefore, it is not currently possible to
* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
- *
+ *
* @param parser XML dom node containing the description of the view
* hierarchy.
* @param root Optional view to be the parent of the generated hierarchy (if
@@ -443,7 +442,7 @@
}
final String name = parser.getName();
-
+
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
@@ -529,17 +528,17 @@
* Low-level function for instantiating a view by name. This attempts to
* instantiate a view class of the given <var>name</var> found in this
* LayoutInflater's ClassLoader.
- *
+ *
* <p>
* There are two things that can happen in an error case: either the
* exception describing the error will be thrown, or a null will be
* returned. You must deal with both possibilities -- the former will happen
* the first time createView() is called for a class of a particular name,
* the latter every time there-after for that class name.
- *
+ *
* @param name The full name of the class to be instantiated.
* @param attrs The XML attributes supplied for this instance.
- *
+ *
* @return View The newly instantiated view, or null.
*/
public final View createView(String name, String prefix, AttributeSet attrs)
@@ -552,7 +551,7 @@
// Class not found in the cache, see if it's real, and try to add it
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
+
if (mFilter != null && clazz != null) {
boolean allowed = mFilter.onLoadClass(clazz);
if (!allowed) {
@@ -570,7 +569,7 @@
// New class -- remember whether it is allowed
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
+
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
if (!allowed) {
@@ -633,10 +632,10 @@
* given the xml element name. Override it to handle custom view objects. If
* you override this in your subclass be sure to call through to
* super.onCreateView(name) for names you do not recognize.
- *
+ *
* @param name The fully qualified class name of the View to be create.
* @param attrs An AttributeSet of attributes to apply to the View.
- *
+ *
* @return View The View created.
*/
protected View onCreateView(String name, AttributeSet attrs)
@@ -680,7 +679,7 @@
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, mContext, attrs);
}
-
+
if (view == null) {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
@@ -727,7 +726,7 @@
}
final String name = parser.getName();
-
+
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_INCLUDE.equals(name)) {
@@ -742,7 +741,7 @@
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
- viewGroup.addView(view, params);
+ viewGroup.addView(view, params);
} else {
final View view = createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
@@ -811,14 +810,21 @@
// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
- TypedArray ta = getContext().obtainStyledAttributes(attrs,
- R.styleable.ViewGroup_Layout);
- boolean definesBothWidthAndHeight =
- ta.hasValue(R.styleable.ViewGroup_Layout_layout_width) &&
- ta.hasValue(R.styleable.ViewGroup_Layout_layout_height);
- AttributeSet attributes = definesBothWidthAndHeight ? attrs : childAttrs;
- view.setLayoutParams(group.generateLayoutParams(attributes));
- ta.recycle();
+ // During a layoutparams generation, a runtime exception is thrown
+ // if either layout_width or layout_height is missing. We catch
+ // this exception and set localParams accordingly: true means we
+ // successfully loaded layout params from the <include /> tag,
+ // false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ params = group.generateLayoutParams(attrs);
+ } catch (RuntimeException e) {
+ params = group.generateLayoutParams(childAttrs);
+ } finally {
+ if (params != null) {
+ view.setLayoutParams(params);
+ }
+ }
// Inflate all children.
rInflate(childParser, view, childAttrs, true);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b4ba871..b36db7f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10002,8 +10002,10 @@
/**
* Resolve the layout parameters depending on the resolved layout direction
+ *
+ * @hide
*/
- private void resolveLayoutParams() {
+ public void resolveLayoutParams() {
if (mLayoutParams != null) {
mLayoutParams.resolveLayoutDirection(getLayoutDirection());
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b95e1bd..dabdf5a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5362,6 +5362,19 @@
* @hide
*/
@Override
+ public void resolveLayoutParams() {
+ super.resolveLayoutParams();
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ child.resolveLayoutParams();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
public void resetRtlProperties() {
super.resetRtlProperties();
int count = getChildCount();
@@ -5611,19 +5624,15 @@
}
/**
- * Extracts the <code>width</code> and <code>height</code> layout parameters
- * from the supplied TypedArray, <code>a</code>, and assigns them
- * to the appropriate fields. If, <code>a</code>, does not contain an
- * entry for either attribute, the value, {@link ViewGroup.LayoutParams#WRAP_CONTENT},
- * is used as a default.
+ * Extracts the layout parameters from the supplied attributes.
*
* @param a the style attributes to extract the parameters from
* @param widthAttr the identifier of the width attribute
* @param heightAttr the identifier of the height attribute
*/
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
- width = a.getLayoutDimension(widthAttr, WRAP_CONTENT);
- height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
+ width = a.getLayoutDimension(widthAttr, "layout_width");
+ height = a.getLayoutDimension(heightAttr, "layout_height");
}
/**
@@ -5981,6 +5990,11 @@
*/
@Override
public void resolveLayoutDirection(int layoutDirection) {
+ // No need to resolve if it is the same layout direction as before
+ if (this.layoutDirection == layoutDirection) {
+ return;
+ }
+
setLayoutDirection(layoutDirection);
if (!isMarginRelative()) return;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 67452ec..8a82a54 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -317,6 +317,8 @@
private final int mDensity;
private final int mNoncompatDensity;
+ private int mViewLayoutDirectionInitial;
+
/**
* Consistency verifier for debugging purposes.
*/
@@ -465,6 +467,7 @@
synchronized (this) {
if (mView == null) {
mView = view;
+ mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
@@ -1186,7 +1189,10 @@
viewVisibilityChanged = false;
mLastConfiguration.setTo(host.getResources().getConfiguration());
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
- host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
+ // Set the layout direction if it has not been set before (inherit is the default)
+ if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
+ host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
+ }
host.dispatchAttachedToWindow(attachInfo, 0);
mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
host.fitSystemWindows(mFitSystemWindowsInsets);
@@ -2682,7 +2688,8 @@
final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
final int currentLayoutDirection = config.getLayoutDirection();
mLastConfiguration.setTo(config);
- if (lastLayoutDirection != currentLayoutDirection) {
+ if (lastLayoutDirection != currentLayoutDirection &&
+ mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
mView.setLayoutDirection(currentLayoutDirection);
}
mView.dispatchConfigurationChanged(config);
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 7855763c..5cdc1ed 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -99,6 +99,7 @@
public static final int ADD_STARTING_NOT_NEEDED = -6;
public static final int ADD_MULTIPLE_SINGLETON = -7;
public static final int ADD_PERMISSION_DENIED = -8;
+ public static final int ADD_INVALID_DISPLAY = -9;
private static WindowManagerGlobal sDefaultWindowManager;
private static IWindowManager sWindowManagerService;
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 45f30df..e158776 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -608,12 +608,6 @@
*/
public int gravity = -1;
- @Override
- protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
- width = a.getLayoutDimension(widthAttr, MATCH_PARENT);
- height = a.getLayoutDimension(heightAttr, MATCH_PARENT);
- }
-
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index af3365e..b71649a 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -142,6 +142,8 @@
};
private int mAnchorXoff, mAnchorYoff;
+ private boolean mPopupViewInitialLayoutDirectionInherited;
+
/**
* <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
*
@@ -968,6 +970,8 @@
} else {
mPopupView = mContentView;
}
+ mPopupViewInitialLayoutDirectionInherited =
+ (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
mPopupWidth = p.width;
mPopupHeight = p.height;
}
@@ -985,9 +989,19 @@
p.packageName = mContext.getPackageName();
}
mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
+ setLayoutDirectionFromAnchor();
mWindowManager.addView(mPopupView, p);
}
+ private void setLayoutDirectionFromAnchor() {
+ if (mAnchor != null) {
+ View anchor = mAnchor.get();
+ if (anchor != null && mPopupViewInitialLayoutDirectionInherited) {
+ mPopupView.setLayoutDirection(anchor.getLayoutDirection());
+ }
+ }
+ }
+
/**
* <p>Generate the layout parameters for the popup window.</p>
*
@@ -1304,8 +1318,9 @@
p.flags = newFlags;
update = true;
}
-
+
if (update) {
+ setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mPopupView, p);
}
}
@@ -1406,6 +1421,7 @@
}
if (update) {
+ setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mPopupView, p);
}
}
@@ -1482,7 +1498,7 @@
} else {
updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff));
}
-
+
update(p.x, p.y, width, height, x != p.x || y != p.y);
}
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 42d63b2..78d05b0 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -297,6 +297,33 @@
public LayoutParams(MarginLayoutParams source) {
super(source);
}
+
+ /**
+ * <p>Fixes the child's width to
+ * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the child's
+ * height to {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
+ * when not specified in the XML file.</p>
+ *
+ * @param a the styled attributes set
+ * @param widthAttr the width attribute to fetch
+ * @param heightAttr the height attribute to fetch
+ */
+ @Override
+ protected void setBaseAttributes(TypedArray a,
+ int widthAttr, int heightAttr) {
+
+ if (a.hasValue(widthAttr)) {
+ width = a.getLayoutDimension(widthAttr, "layout_width");
+ } else {
+ width = WRAP_CONTENT;
+ }
+
+ if (a.hasValue(heightAttr)) {
+ height = a.getLayoutDimension(heightAttr, "layout_height");
+ } else {
+ height = WRAP_CONTENT;
+ }
+ }
}
/**
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index 113299a..399b4fa 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -741,9 +741,14 @@
* @param heightAttr the height attribute to fetch
*/
@Override
- protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
+ protected void setBaseAttributes(TypedArray a,
+ int widthAttr, int heightAttr) {
this.width = MATCH_PARENT;
- this.height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
+ if (a.hasValue(heightAttr)) {
+ this.height = a.getLayoutDimension(heightAttr, "layout_height");
+ } else {
+ this.height = WRAP_CONTENT;
+ }
}
}
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index 3f8f9dae..68ffd73 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -505,8 +505,19 @@
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
- width = a.getLayoutDimension(widthAttr, MATCH_PARENT);
- height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
+ // We don't want to force users to specify a layout_width
+ if (a.hasValue(widthAttr)) {
+ width = a.getLayoutDimension(widthAttr, "layout_width");
+ } else {
+ width = MATCH_PARENT;
+ }
+
+ // We don't want to force users to specify a layout_height
+ if (a.hasValue(heightAttr)) {
+ height = a.getLayoutDimension(heightAttr, "layout_height");
+ } else {
+ height = WRAP_CONTENT;
+ }
}
}
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 7287327..c9b7cb3 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -70,6 +70,47 @@
this.key = key;
}
+ public VpnProfile(Parcel in) {
+ key = in.readString();
+ name = in.readString();
+ type = in.readInt();
+ server = in.readString();
+ username = in.readString();
+ password = in.readString();
+ dnsServers = in.readString();
+ searchDomains = in.readString();
+ routes = in.readString();
+ mppe = in.readInt() != 0;
+ l2tpSecret = in.readString();
+ ipsecIdentifier = in.readString();
+ ipsecSecret = in.readString();
+ ipsecUserCert = in.readString();
+ ipsecCaCert = in.readString();
+ ipsecServerCert = in.readString();
+ saveLogin = in.readInt() != 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(key);
+ out.writeString(name);
+ out.writeInt(type);
+ out.writeString(server);
+ out.writeString(username);
+ out.writeString(password);
+ out.writeString(dnsServers);
+ out.writeString(searchDomains);
+ out.writeString(routes);
+ out.writeInt(mppe ? 1 : 0);
+ out.writeString(l2tpSecret);
+ out.writeString(ipsecIdentifier);
+ out.writeString(ipsecSecret);
+ out.writeString(ipsecUserCert);
+ out.writeString(ipsecCaCert);
+ out.writeString(ipsecServerCert);
+ out.writeInt(saveLogin ? 1 : 0);
+ }
+
public static VpnProfile decode(String key, byte[] value) {
try {
if (key == null) {
@@ -155,17 +196,10 @@
}
}
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(key);
- out.writeByteArray(encode());
- }
-
public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
@Override
public VpnProfile createFromParcel(Parcel in) {
- final String key = in.readString();
- return decode(key, in.createByteArray());
+ return new VpnProfile(in);
}
@Override
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aa67ec2..92aa06a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2032,7 +2032,7 @@
<permission android:name="android.permission.SERIAL_PORT"
android:label="@string/permlab_serialPort"
android:description="@string/permdesc_serialPort"
- android:protectionLevel="normal" />
+ android:protectionLevel="signature|system" />
<!-- Allows the holder to access content providers from outside an ApplicationThread.
This permission is enforced by the ActivityManagerService on the corresponding APIs,
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4698002..0890a18 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -636,19 +636,12 @@
of new location providers at run-time. The new package does not
have to be explicitly listed here, however it must have a signature
that matches the signature of at least one package on this list.
- Platforms should overlay additional packages in
- config_overlay_locationProviderPackageNames, instead of overlaying
- this config, if they only want to append packages and not replace
- the entire array.
-->
<string-array name="config_locationProviderPackageNames" translatable="false">
+ <!-- The standard AOSP fused location provider -->
<item>com.android.location.fused</item>
</string-array>
- <!-- Pacakge name(s) supplied by overlay, and appended to
- config_locationProviderPackageNames. -->
- <string-array name="config_overlay_locationProviderPackageNames" translatable="false" />
-
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
@@ -902,8 +895,16 @@
<!-- Name of the wimax state tracker clas -->
<string name="config_wimaxStateTrackerClassname" translatable="false"></string>
- <!-- enable screen saver feature -->
- <bool name="config_enableDreams">true</bool>
+ <!-- Is the dreams feature supported? -->
+ <bool name="config_dreamsSupported">true</bool>
+ <!-- If supported, are dreams enabled? (by default) -->
+ <bool name="config_dreamsEnabledByDefault">true</bool>
+ <!-- If supported and enabled, are dreams activated when docked? (by default) -->
+ <bool name="config_dreamsActivatedOnDockByDefault">true</bool>
+ <!-- If supported and enabled, are dreams activated when asleep and charging? (by default) -->
+ <bool name="config_dreamsActivatedOnSleepByDefault">false</bool>
+ <!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
+ <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b3af161..8ef91df 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1475,7 +1475,6 @@
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" />
- <java-symbol type="array" name="config_overlay_locationProviderPackageNames" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />
@@ -1628,7 +1627,11 @@
<java-symbol type="style" name="Theme.Dialog.AppError" />
<java-symbol type="style" name="Theme.Toast" />
<java-symbol type="xml" name="storage_list" />
- <java-symbol type="bool" name="config_enableDreams" />
+ <java-symbol type="bool" name="config_dreamsSupported" />
+ <java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+ <java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
+ <java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+ <java-symbol type="string" name="config_dreamsDefaultComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
<java-symbol type="string" name="enable_explore_by_touch_warning_message" />
diff --git a/data/sounds/effects/ogg/VideoRecord.ogg b/data/sounds/effects/ogg/VideoRecord.ogg
index d2dee03..ca66604 100644
--- a/data/sounds/effects/ogg/VideoRecord.ogg
+++ b/data/sounds/effects/ogg/VideoRecord.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/VideoRecord_48k.ogg b/data/sounds/effects/ogg/VideoRecord_48k.ogg
new file mode 100644
index 0000000..fd9c760
--- /dev/null
+++ b/data/sounds/effects/ogg/VideoRecord_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/VideoStop.ogg b/data/sounds/effects/ogg/VideoStop.ogg
index f16ed13..2516710 100644
--- a/data/sounds/effects/ogg/VideoStop.ogg
+++ b/data/sounds/effects/ogg/VideoStop.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/VideoStop_48k.ogg b/data/sounds/effects/ogg/VideoStop_48k.ogg
new file mode 100644
index 0000000..7c40021
--- /dev/null
+++ b/data/sounds/effects/ogg/VideoStop_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/camera_click.ogg b/data/sounds/effects/ogg/camera_click.ogg
index 44b6683..130b534 100644
--- a/data/sounds/effects/ogg/camera_click.ogg
+++ b/data/sounds/effects/ogg/camera_click.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/camera_click_48k.ogg b/data/sounds/effects/ogg/camera_click_48k.ogg
new file mode 100644
index 0000000..b836e10
--- /dev/null
+++ b/data/sounds/effects/ogg/camera_click_48k.ogg
Binary files differ
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 62c054a..3cfed13 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -119,7 +119,7 @@
a {@link android.support.v4.app.DialogFragment}:</p>
<pre>
-public class FireMissilesDialog extends DialogFragment {
+public class FireMissilesDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
@@ -469,7 +469,7 @@
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- NoticeDialog.this.getDialog().cancel();
+ LoginDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
@@ -497,15 +497,15 @@
<p>When the user touches one of the dialog's action buttons or selects an item from its list,
your {@link android.support.v4.app.DialogFragment} might perform the necessary
action itself, but often you'll want to deliver the event to the activity or fragment that
-opened the dialog. To do this, define an interface with a method for each type of click event,
-then implement that interface in the host component that will
+opened the dialog. To do this, define an interface with a method for each type of click event.
+Then implement that interface in the host component that will
receive the action events from the dialog.</p>
<p>For example, here's a {@link android.support.v4.app.DialogFragment} that defines an
interface through which it delivers the events back to the host activity:</p>
<pre>
-public class NoticeDialog extends DialogFragment {
+public class NoticeDialogFragment extends DialogFragment {
/* The activity that creates an instance of this dialog fragment must
* implement this interface in order to receive event callbacks.
@@ -516,48 +516,44 @@
}
// Use this instance of the interface to deliver action events
- static NoticeDialogListener mListener;
-
- /* Call this to instantiate a new NoticeDialog.
- * @param activity The activity hosting the dialog, which must implement the
- * NoticeDialogListener to receive event callbacks.
- * @returns A new instance of NoticeDialog.
- * @throws ClassCastException if the host activity does not
- * implement NoticeDialogListener
- */
- public static NoticeDialog newInstance(Activity activity) {
+ NoticeDialogListener mListener;
+
+ // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
- // Instantiate the NoticeDialogListener so we can send events with it
+ // Instantiate the NoticeDialogListener so we can send events to the host
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
- NoticeDialog frag = new NoticeDialog();
- return frag;
}
-
...
}
</pre>
-<p>The activity hosting the dialog creates and shows an instance of the dialog
-by calling {@code NoticeDialog.newInstance()} and receives the dialog's
+<p>The activity hosting the dialog creates an instance of the dialog
+with the dialog fragment's constructor and receives the dialog's
events through an implementation of the {@code NoticeDialogListener} interface:</p>
<pre>
public class MainActivity extends FragmentActivity
- implements NoticeDialog.NoticeDialogListener{
+ implements NoticeDialogFragment.NoticeDialogListener{
...
public void showNoticeDialog() {
// Create an instance of the dialog fragment and show it
- DialogFragment dialog = NoticeDialog.newInstance(this);
- dialog.show(getSupportFragmentManager(), "NoticeDialog");
+ DialogFragment dialog = new NoticeDialogFragment();
+ dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
}
+ // The dialog fragment receives a reference to this Activity through the
+ // Fragment.onAttach() callback, which it uses to call the following methods
+ // defined by the NoticeDialogFragment.NoticeDialogListener interface
@Override
public void onDialogPositiveClick(DialogFragment dialog) {
// User touched the dialog's positive button
@@ -573,11 +569,12 @@
</pre>
<p>Because the host activity implements the {@code NoticeDialogListener}—which is
-enforced by the {@code newInstance()} method shown above—the dialog fragment can use the
+enforced by the {@link android.support.v4.app.Fragment#onAttach onAttach()}
+callback method shown above—the dialog fragment can use the
interface callback methods to deliver click events to the activity:</p>
<pre>
-public class NoticeDialog extends DialogFragment {
+public class NoticeDialogFragment extends DialogFragment {
...
@Override
@@ -588,13 +585,13 @@
.setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Send the positive button event back to the host activity
- mListener.onDialogPositiveClick(NoticeDialog.this);
+ mListener.onDialogPositiveClick(NoticeDialogFragment.this);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Send the negative button event back to the host activity
- mListener.onDialogPositiveClick(NoticeDialog.this);
+ mListener.onDialogPositiveClick(NoticeDialogFragment.this);
}
});
return builder.create();
@@ -604,8 +601,6 @@
-
-
<h2 id="ShowingADialog">Showing a Dialog</h2>
<p>When you want to show your dialog, create an instance of your {@link
@@ -621,7 +616,7 @@
<pre>
public void confirmFireMissiles() {
- DialogFragment newFragment = FireMissilesDialog.newInstance(this);
+ DialogFragment newFragment = new FireMissilesDialogFragment();
newFragment.show(getSupportFragmentManager(), "missiles");
}
</pre>
@@ -653,7 +648,7 @@
dialog or an embeddable fragment (using a layout named <code>purchase_items.xml</code>):</p>
<pre>
-public class CustomLayoutDialog extends DialogFragment {
+public class CustomDialogFragment extends DialogFragment {
/** The system calls this to get the DialogFragment's layout, regardless
of whether it's being displayed as a dialog or an embedded fragment. */
@Override
@@ -683,7 +678,7 @@
<pre>
public void showDialog() {
FragmentManager fragmentManager = getSupportFragmentManager();
- CustomLayoutDialog newFragment = new CustomLayoutDialog();
+ CustomDialogFragment newFragment = new CustomDialogFragment();
if (mIsLargeLayout) {
// The device is using a large layout, so show the fragment as a dialog
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 589d5c2..81e68bd 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -1434,7 +1434,7 @@
mHeight = height;
}
-int DisplayListRenderer::prepareDirty(float left, float top,
+status_t DisplayListRenderer::prepareDirty(float left, float top,
float right, float bottom, bool opaque) {
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2610055..e42def5 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -550,7 +550,7 @@
virtual bool isDeferred();
virtual void setViewport(int width, int height);
- virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty);
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 882e4bb..1cdc063 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -31,6 +31,7 @@
meshIndices = NULL;
meshElementCount = 0;
cacheable = true;
+ dirty = false;
textureLayer = false;
renderTarget = GL_TEXTURE_2D;
texture.width = layerWidth;
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 448e3da..e1f6a70 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -162,6 +162,14 @@
this->cacheable = cacheable;
}
+ inline bool isDirty() {
+ return dirty;
+ }
+
+ inline void setDirty(bool dirty) {
+ this->dirty = dirty;
+ }
+
inline bool isTextureLayer() {
return textureLayer;
}
@@ -287,6 +295,12 @@
bool textureLayer;
/**
+ * When set to true, this layer is dirty and should be cleared
+ * before any rendering occurs.
+ */
+ bool dirty;
+
+ /**
* Indicates the render target.
*/
GLenum renderTarget;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f2e7f66..3484d41 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -18,6 +18,8 @@
#include <ui/Rect.h>
+#include <private/hwui/DrawGlInfo.h>
+
#include "LayerCache.h"
#include "LayerRenderer.h"
#include "Matrix.h"
@@ -41,7 +43,8 @@
initViewport(width, height);
}
-int LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
+status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
+ bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
@@ -63,6 +66,20 @@
return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
}
+status_t LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+ if (mLayer->isDirty()) {
+ getCaches().disableScissor();
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ getCaches().resetScissor();
+ mLayer->setDirty(false);
+
+ return DrawGlInfo::kStatusDone;
+ }
+
+ return OpenGLRenderer::clear(left, top, right, bottom, opaque);
+}
+
void LayerRenderer::finish() {
OpenGLRenderer::finish();
@@ -201,6 +218,7 @@
layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
layer->setBlend(!isOpaque);
layer->setColorFilter(NULL);
+ layer->setDirty(true);
layer->region.clear();
GLuint previousFbo;
@@ -229,9 +247,6 @@
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
layer->getTexture(), 0);
- caches.disableScissor();
- glClear(GL_COLOR_BUFFER_BIT);
-
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
return layer;
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index acedbcc..c44abce 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -48,7 +48,8 @@
virtual ~LayerRenderer();
virtual void setViewport(int width, int height);
- virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
ANDROID_API static Layer* createTextureLayer(bool isOpaque);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b6be5b3..914516c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -165,11 +165,12 @@
mFirstSnapshot->viewport.set(0, 0, width, height);
}
-int OpenGLRenderer::prepare(bool opaque) {
+status_t OpenGLRenderer::prepare(bool opaque) {
return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
}
-int OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
+status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom,
+ bool opaque) {
mCaches.clearGarbage();
mSnapshot = new Snapshot(mFirstSnapshot,
@@ -203,15 +204,18 @@
debugOverdraw(true, true);
+ return clear(left, top, right, bottom, opaque);
+}
+
+status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
if (!opaque) {
mCaches.enableScissor();
mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
glClear(GL_COLOR_BUFFER_BIT);
return DrawGlInfo::kStatusDrew;
- } else {
- mCaches.resetScissor();
}
+ mCaches.resetScissor();
return DrawGlInfo::kStatusDone;
}
@@ -743,6 +747,7 @@
bounds.getWidth() / float(layer->getWidth()), 0.0f);
layer->setColorFilter(mColorFilter);
layer->setBlend(true);
+ layer->setDirty(false);
// Save the layer in the snapshot
mSnapshot->flags |= Snapshot::kFlagIsLayer;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index a40d69a..c5e4c8e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -94,7 +94,7 @@
* and will not be cleared. If false, the target surface
* will be cleared
*/
- ANDROID_API int prepare(bool opaque);
+ ANDROID_API status_t prepare(bool opaque);
/**
* Prepares the renderer to draw a frame. This method must be invoked
@@ -110,7 +110,7 @@
* and will not be cleared. If false, the target surface
* will be cleared in the specified dirty rectangle
*/
- virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
/**
* Indicates the end of a frame. This method must be invoked whenever
@@ -270,6 +270,11 @@
void initViewport(int width, int height);
/**
+ * Clears the underlying surface if needed.
+ */
+ virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
+
+ /**
* Call this method after updating a layer during a drawing pass.
*/
void resumeAfterLayer();
@@ -355,6 +360,10 @@
return false;
}
+ Caches& getCaches() {
+ return mCaches;
+ }
+
private:
/**
* Ensures the state of the renderer is the same as the state of
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index cb291ea..6871ee2 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -221,6 +221,18 @@
/** @hide */
public LocationRequest() { }
+ /** @hide */
+ public LocationRequest(LocationRequest src) {
+ mQuality = src.mQuality;
+ mInterval = src.mInterval;
+ mFastestInterval = src.mFastestInterval;
+ mExplicitFastestInterval = src.mExplicitFastestInterval;
+ mExpireAt = src.mExpireAt;
+ mNumUpdates = src.mNumUpdates;
+ mSmallestDisplacement = src.mSmallestDisplacement;
+ mProvider = src.mProvider;
+ }
+
/**
* Set the quality of the request.
*
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index f77cbfb..dd320a0 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -634,7 +634,8 @@
final ContentResolver cr = mContentResolver;
int ringerModeFromSettings =
- Settings.Global.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
+ Settings.Global.getInt(
+ cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
int ringerMode = ringerModeFromSettings;
// sanity check in case the settings are restored from a device with incompatible
// ringer modes
@@ -645,7 +646,7 @@
ringerMode = AudioManager.RINGER_MODE_SILENT;
}
if (ringerMode != ringerModeFromSettings) {
- Settings.Global.putInt(cr, System.MODE_RINGER, ringerMode);
+ Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
}
synchronized(mSettingsLock) {
mRingerMode = ringerMode;
@@ -3118,7 +3119,7 @@
}
private void persistRingerMode(int ringerMode) {
- Settings.Global.putInt(mContentResolver, System.MODE_RINGER, ringerMode);
+ Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
}
private void playSoundEffect(int effectType, int volume) {
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 4c57401..10b9064 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -18,7 +18,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.location.fused"
- coreApp="true">
+ coreApp="true"
+ android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -39,7 +40,7 @@
<intent-filter>
<action android:name="com.android.location.service.FusedLocationProvider" />
</intent-filter>
- <meta-data android:name="version" android:value="1" />
+ <meta-data android:name="serviceVersion" android:value="0" />
</service>
</application>
</manifest>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 9e137ce..94e2286 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -165,16 +165,6 @@
Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES -->
<integer name="def_max_dhcp_retries">9</integer>
- <!-- Dreams (screen saver) default settings -->
- <!-- Whether the feature is enabled when charging (Settings.Secure.SCREENSAVER_ENABLED) -->
- <bool name="def_screensaver_enabled">true</bool>
- <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_DOCK) -->
- <bool name="def_screensaver_activate_on_dock">true</bool>
- <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_SLEEP) -->
- <bool name="def_screensaver_activate_on_sleep">false</bool>
- <!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
- <string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
-
<!-- Default for Settings.Secure.USER_SETUP_COMPLETE -->
<bool name="def_user_setup_complete">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 0689268..b649b43 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1166,15 +1166,15 @@
stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
+ " VALUES(?,?);");
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED,
- R.bool.def_screensaver_enabled);
+ com.android.internal.R.bool.config_dreamsEnabledByDefault);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
- R.bool.def_screensaver_activate_on_dock);
+ com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
- R.bool.def_screensaver_activate_on_sleep);
- loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
- R.string.def_screensaver_component);
+ com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
- R.string.def_screensaver_component);
+ com.android.internal.R.string.config_dreamsDefaultComponent);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+ com.android.internal.R.string.config_dreamsDefaultComponent);
db.setTransactionSuccessful();
} finally {
@@ -2027,15 +2027,15 @@
}
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED,
- R.bool.def_screensaver_enabled);
+ com.android.internal.R.bool.config_dreamsEnabledByDefault);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
- R.bool.def_screensaver_activate_on_dock);
+ com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
- R.bool.def_screensaver_activate_on_sleep);
+ com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
- R.string.def_screensaver_component);
+ com.android.internal.R.string.config_dreamsDefaultComponent);
loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
- R.string.def_screensaver_component);
+ com.android.internal.R.string.config_dreamsDefaultComponent);
loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
R.bool.def_accessibility_display_magnification_enabled);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index f0e5a87..cfe70dc 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -63,7 +63,6 @@
<uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
<application
- android:name="com.android.systemui.SystemUIApplication"
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
@@ -109,7 +108,7 @@
<activity android:name=".recent.RecentsActivity"
android:label="@string/accessibility_desc_recent_apps"
- android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
+ android:theme="@style/RecentsStyle"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:exported="true">
@@ -118,6 +117,15 @@
</intent-filter>
</activity>
+ <receiver
+ android:name=".recent.RecentsPreloadReceiver"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="com.android.systemui.recent.action.PRELOAD" />
+ <action android:name="com.android.systemui.recent.action.CANCEL_PRELOAD" />
+ </intent-filter>
+ </receiver>
+
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"
diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
index 73ae9f2..1135bc0 100644
--- a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
@@ -18,7 +18,6 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true"
android:shareInterpolator="false"
android:zAdjustment="normal">
<!--scale android:fromXScale="2.0" android:toXScale="1.0"
@@ -28,9 +27,4 @@
android:fillBefore="true" android:fillAfter="true"
android:pivotX="50%p" android:pivotY="50%p"
android:duration="250" /-->
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
index becc9d0..fa28cf4 100644
--- a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
@@ -19,7 +19,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
- android:zAdjustment="normal">
+ android:zAdjustment="top">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
new file mode 100644
index 0000000..121daae
--- /dev/null
+++ b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="normal">
+ <!--scale android:fromXScale="2.0" android:toXScale="1.0"
+ android:fromYScale="2.0" android:toYScale="1.0"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:duration="250" /-->
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:duration="250"/>
+</set>
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
new file mode 100644
index 0000000..fa28cf4
--- /dev/null
+++ b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:duration="250"/>
+</set>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 18c1c34..1a59d6c 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,6 +16,24 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="RecentsStyle" parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
+ <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
+ </style>
+
+ <!-- Animations for a non-full-screen window or activity. -->
+ <style name="Animation.RecentsActivity" parent="@android:style/Animation.Activity">
+ <item name="android:activityOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+ <item name="android:activityOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+ <item name="android:taskOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+ <item name="android:taskOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+ <item name="android:taskToFrontEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+ <item name="android:taskToFrontExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+ <item name="android:wallpaperOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+ <item name="android:wallpaperOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+ <item name="android:wallpaperIntraOpenEnterAnimation">@anim/wallpaper_recents_launch_from_launcher_enter</item>
+ <item name="android:wallpaperIntraOpenExitAnimation">@anim/wallpaper_recents_launch_from_launcher_exit</item>
+ </style>
+
<style name="TextAppearance.StatusBar.IntruderAlert"
parent="@*android:style/TextAppearance.StatusBar">
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
index de005aa..d3ce30d 100644
--- a/packages/SystemUI/src/com/android/systemui/BootReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
@@ -35,7 +35,7 @@
try {
// Start the load average overlay, if activated
ContentResolver res = context.getContentResolver();
- if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
+ if (Settings.Global.getInt(res, Settings.Global.SHOW_PROCESSES, 0) != 0) {
Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
context.startService(loadavg);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 0958f70..0a7dd7c 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -109,7 +109,7 @@
private WallpaperObserver mReceiver;
Bitmap mBackground;
- int mBackgroundWidth = -1, mBackgroundHeight = -1;
+ int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
int mLastRotation = -1;
float mXOffset;
float mYOffset;
@@ -156,7 +156,7 @@
}
synchronized (mLock) {
- mBackgroundWidth = mBackgroundHeight = -1;
+ mLastSurfaceWidth = mLastSurfaceHeight = -1;
mBackground = null;
mRedrawNeeded = true;
drawFrameLocked();
@@ -172,6 +172,9 @@
public void trimMemory(int level) {
if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW &&
mBackground != null && mIsHwAccelerated) {
+ if (DEBUG) {
+ Log.d(TAG, "trimMemory");
+ }
mBackground.recycle();
mBackground = null;
mWallpaperManager.forgetLoadedWallpaper();
@@ -286,13 +289,13 @@
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
- mBackgroundWidth = mBackgroundHeight = -1;
+ mLastSurfaceWidth = mLastSurfaceHeight = -1;
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
- mBackgroundWidth = mBackgroundHeight = -1;
+ mLastSurfaceWidth = mLastSurfaceHeight = -1;
}
@Override
@@ -314,9 +317,9 @@
final int dh = frame.height();
int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)).
getDefaultDisplay().getRotation();
+ boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight;
- boolean redrawNeeded = dw != mBackgroundWidth || dh != mBackgroundHeight ||
- newRotation != mLastRotation;
+ boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation;
if (!redrawNeeded && !mOffsetsChanged) {
if (DEBUG) {
Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
@@ -327,21 +330,41 @@
mLastRotation = newRotation;
// Load bitmap if it is not yet loaded or if it was loaded at a different size
- if (mBackground == null || dw != mBackgroundWidth || dw != mBackgroundHeight) {
+ if (mBackground == null || surfaceDimensionsChanged) {
if (DEBUG) {
- Log.d(TAG, "Reloading bitmap");
+ Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
+ mBackground + ", " +
+ ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " +
+ ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " +
+ dw + ", " + dh);
}
- mWallpaperManager.forgetLoadedWallpaper();
updateWallpaperLocked();
+ if (mBackground == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Unable to load bitmap");
+ }
+ return;
+ }
+ if (DEBUG) {
+ if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) {
+ Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " +
+ dw + ", " + dh + ", " + mBackground.getWidth() + ", " +
+ mBackground.getHeight());
+ }
+ }
}
- final int availw = dw - mBackgroundWidth;
- final int availh = dh - mBackgroundHeight;
+ final int availw = dw - mBackground.getWidth();
+ final int availh = dh - mBackground.getHeight();
int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2);
int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2);
mOffsetsChanged = false;
mRedrawNeeded = false;
+ if (surfaceDimensionsChanged) {
+ mLastSurfaceWidth = dw;
+ mLastSurfaceHeight = dh;
+ }
mLastXTranslation = xPixels;
mLastYTranslation = yPixels;
if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
@@ -374,9 +397,10 @@
}
- void updateWallpaperLocked() {
+ private void updateWallpaperLocked() {
Throwable exception = null;
try {
+ mWallpaperManager.forgetLoadedWallpaper(); // force reload
mBackground = mWallpaperManager.getBitmap();
} catch (RuntimeException e) {
exception = e;
@@ -397,9 +421,6 @@
Log.w(TAG, "Unable reset to default wallpaper!", ex);
}
}
-
- mBackgroundWidth = mBackground != null ? mBackground.getWidth() : 0;
- mBackgroundHeight = mBackground != null ? mBackground.getHeight() : 0;
}
private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) {
@@ -413,7 +434,8 @@
c.translate(x, y);
if (w < 0 || h < 0) {
c.save(Canvas.CLIP_SAVE_FLAG);
- c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE);
+ c.clipRect(0, 0, mBackground.getWidth(), mBackground.getHeight(),
+ Op.DIFFERENCE);
c.drawColor(0xff000000);
c.restore();
}
@@ -429,8 +451,8 @@
private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
if (!initGL(sh)) return false;
- final float right = left + mBackgroundWidth;
- final float bottom = top + mBackgroundHeight;
+ final float right = left + mBackground.getWidth();
+ final float bottom = top + mBackground.getHeight();
final Rect frame = sh.getSurfaceFrame();
final Matrix4f ortho = new Matrix4f();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
deleted file mode 100644
index c120690..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ /dev/null
@@ -1,59 +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;
-
-import android.app.Application;
-
-import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsActivity;
-
-public class SystemUIApplication extends Application {
- private RecentTasksLoader mRecentTasksLoader;
- private boolean mWaitingForWinAnimStart;
- private RecentsActivity.WindowAnimationStartListener mWinAnimStartListener;
-
- public RecentTasksLoader getRecentTasksLoader() {
- if (mRecentTasksLoader == null) {
- mRecentTasksLoader = new RecentTasksLoader(this);
- }
- return mRecentTasksLoader;
- }
-
- public void setWaitingForWinAnimStart(boolean waiting) {
- mWaitingForWinAnimStart = waiting;
- }
-
- public void setWindowAnimationStartListener(
- RecentsActivity.WindowAnimationStartListener startListener) {
- mWinAnimStartListener = startListener;
- }
-
- public RecentsActivity.WindowAnimationStartListener getWindowAnimationListener() {
- return mWinAnimStartListener;
- }
-
- public void onWindowAnimationStart() {
- if (mWinAnimStartListener != null) {
- mWinAnimStartListener.onWindowAnimationStart();
- }
- mWaitingForWinAnimStart = false;
- }
-
- public boolean isWaitingForWindowAnimationStart() {
- return mWaitingForWinAnimStart;
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 07fd0ab..318448e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -237,9 +237,9 @@
}
final ContentResolver cr = mContext.getContentResolver();
- if (Settings.System.getInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) {
- final String soundPath = Settings.System.getString(cr,
- Settings.System.LOW_BATTERY_SOUND);
+ if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) {
+ final String soundPath = Settings.Global.getString(cr,
+ Settings.Global.LOW_BATTERY_SOUND);
if (soundPath != null) {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 7260844..9d6765a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -30,6 +30,7 @@
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Process;
+import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -52,6 +53,8 @@
private Context mContext;
private RecentsPanelView mRecentsPanel;
+
+ private Object mFirstTaskLock = new Object();
private TaskDescription mFirstTask;
private boolean mFirstTaskLoaded;
@@ -70,23 +73,16 @@
private enum State { LOADING, LOADED, CANCELLED };
private State mState = State.CANCELLED;
- public TaskDescription getFirstTask() {
- while (!mFirstTaskLoaded) {
- if (mState == State.CANCELLED) {
- loadTasksInBackground();
- }
- try {
- if (mState == State.LOADED) {
- break;
- }
- Thread.sleep(5);
- } catch (InterruptedException e) {
- }
+
+ private static RecentTasksLoader sInstance;
+ public static RecentTasksLoader getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new RecentTasksLoader(context);
}
- return mFirstTask;
+ return sInstance;
}
- public RecentTasksLoader(Context context) {
+ private RecentTasksLoader(Context context) {
mContext = context;
mHandler = new Handler();
@@ -295,8 +291,6 @@
mThumbnailLoader = null;
}
mLoadedTasks = null;
- mFirstTask = null;
- mFirstTaskLoaded = false;
if (mRecentsPanel != null) {
mRecentsPanel.onTaskLoadingCancelled();
}
@@ -304,6 +298,100 @@
mState = State.CANCELLED;
}
+ private void clearFirstTask() {
+ synchronized (mFirstTaskLock) {
+ mFirstTask = null;
+ mFirstTaskLoaded = false;
+ }
+ }
+
+ public void preloadFirstTask() {
+ Thread bgLoad = new Thread() {
+ public void run() {
+ TaskDescription first = loadFirstTask();
+ synchronized(mFirstTaskLock) {
+ if (mCancelPreloadingFirstTask) {
+ clearFirstTask();
+ } else {
+ mFirstTask = first;
+ mFirstTaskLoaded = true;
+ }
+ mPreloadingFirstTask = false;
+ }
+ }
+ };
+ synchronized(mFirstTaskLock) {
+ if (!mPreloadingFirstTask) {
+ clearFirstTask();
+ mPreloadingFirstTask = true;
+ bgLoad.start();
+ }
+ }
+ }
+
+ public void cancelPreloadingFirstTask() {
+ synchronized(mFirstTaskLock) {
+ if (mPreloadingFirstTask) {
+ mCancelPreloadingFirstTask = true;
+ } else {
+ clearFirstTask();
+ }
+ }
+ }
+
+ boolean mPreloadingFirstTask;
+ boolean mCancelPreloadingFirstTask;
+ public TaskDescription getFirstTask() {
+ while(true) {
+ synchronized(mFirstTaskLock) {
+ if (mFirstTaskLoaded) {
+ return mFirstTask;
+ } else if (!mFirstTaskLoaded && !mPreloadingFirstTask) {
+ mFirstTask = loadFirstTask();
+ mFirstTaskLoaded = true;
+ return mFirstTask;
+ }
+ }
+ try {
+ Thread.sleep(3);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ public TaskDescription loadFirstTask() {
+ final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+
+ final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(
+ 1, ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserHandle.CURRENT.getIdentifier());
+ TaskDescription item = null;
+ if (recentTasks.size() > 0) {
+ ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0);
+
+ Intent intent = new Intent(recentInfo.baseIntent);
+ if (recentInfo.origActivity != null) {
+ intent.setComponent(recentInfo.origActivity);
+ }
+
+ // Don't load the current home activity.
+ if (isCurrentHomeActivity(intent.getComponent(), null)) {
+ return null;
+ }
+
+ // Don't load ourselves
+ if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
+ return null;
+ }
+
+ item = createTaskDescription(recentInfo.id,
+ recentInfo.persistentId, recentInfo.baseIntent,
+ recentInfo.origActivity, recentInfo.description);
+ loadThumbnailAndIcon(item);
+ return item;
+ }
+ return null;
+ }
+
public void loadTasksInBackground() {
loadTasksInBackground(false);
}
@@ -367,9 +455,6 @@
// Don't load the current home activity.
if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
- if (index == 0) {
- mFirstTaskLoaded = true;
- }
continue;
}
@@ -466,10 +551,6 @@
}
loadThumbnailAndIcon(td);
- if (!mFirstTaskLoaded) {
- mFirstTask = td;
- mFirstTaskLoaded = true;
- }
publishProgress(td);
}
@@ -477,8 +558,6 @@
return null;
}
};
- mFirstTask = null;
- mFirstTaskLoaded = false;
mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index ef9f36e..676326a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -30,14 +30,18 @@
import android.view.WindowManager;
import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import java.util.List;
public class RecentsActivity extends Activity {
- public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.TOGGLE_RECENTS";
- public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.CLOSE_RECENTS";
+ public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.recent.action.TOGGLE_RECENTS";
+ public static final String PRELOAD_INTENT = "com.android.systemui.recent.action.PRELOAD";
+ public static final String CANCEL_PRELOAD_INTENT = "com.android.systemui.recent.CANCEL_PRELOAD";
+ public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.recent.action.CLOSE";
+ public static final String WINDOW_ANIMATION_START_INTENT = "com.android.systemui.recent.action.WINDOW_ANIMATION_START";
+ public static final String PRELOAD_PERMISSION = "com.android.systemui.recent.permission.PRELOAD";
+ public static final String WAITING_FOR_WINDOW_ANIMATION_PARAM = "com.android.systemui.recent.WAITING_FOR_WINDOW_ANIMATION";
private static final String WAS_SHOWING = "was_showing";
private RecentsPanelView mRecentsPanel;
@@ -48,19 +52,21 @@
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
- if (mShowing && !mForeground) {
- // Captures the case right before we transition to another activity
- mRecentsPanel.show(false);
+ if (CLOSE_RECENTS_INTENT.equals(intent.getAction())) {
+ if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
+ if (mShowing && !mForeground) {
+ // Captures the case right before we transition to another activity
+ mRecentsPanel.show(false);
+ }
+ }
+ } else if (WINDOW_ANIMATION_START_INTENT.equals(intent.getAction())) {
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onWindowAnimationStart();
}
}
}
};
- public static interface WindowAnimationStartListener {
- void onWindowAnimationStart();
- }
-
public class TouchOutsideListener implements View.OnTouchListener {
private StatusBarPanel mPanel;
@@ -107,10 +113,14 @@
}
}
+ public static boolean forceOpaqueBackground(Context context) {
+ return WallpaperManager.getInstance(context).getWallpaperInfo() != null;
+ }
+
@Override
public void onStart() {
// Hide wallpaper if it's not a static image
- if (WallpaperManager.getInstance(this).getWallpaperInfo() != null) {
+ if (forceOpaqueBackground(this)) {
updateWallpaperVisibility(false);
} else {
updateWallpaperVisibility(true);
@@ -164,25 +174,23 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- final SystemUIApplication app = (SystemUIApplication) getApplication();
- final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
-
setContentView(R.layout.status_bar_recent_panel);
mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
- mRecentsPanel.setRecentTasksLoader(recentTasksLoader);
+
+ final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
mRecentsPanel.setMinSwipeAlpha(
getResources().getInteger(R.integer.config_recent_item_min_alpha) / 100f);
if (savedInstanceState == null ||
savedInstanceState.getBoolean(WAS_SHOWING)) {
- handleIntent(getIntent());
+ handleIntent(getIntent(), (savedInstanceState == null));
}
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
+ mIntentFilter.addAction(WINDOW_ANIMATION_START_INTENT);
registerReceiver(mIntentReceiver, mIntentFilter);
- app.setWindowAnimationStartListener(mRecentsPanel);
super.onCreate(savedInstanceState);
}
@@ -193,20 +201,17 @@
@Override
protected void onDestroy() {
- final SystemUIApplication app = (SystemUIApplication) getApplication();
- final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
- recentTasksLoader.setRecentsPanel(null, mRecentsPanel);
+ RecentTasksLoader.getInstance(this).setRecentsPanel(null, mRecentsPanel);
unregisterReceiver(mIntentReceiver);
- app.setWindowAnimationStartListener(null);
super.onDestroy();
}
@Override
protected void onNewIntent(Intent intent) {
- handleIntent(intent);
+ handleIntent(intent, true);
}
- private void handleIntent(Intent intent) {
+ private void handleIntent(Intent intent, boolean checkWaitingForAnimationParam) {
super.onNewIntent(intent);
if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
@@ -214,10 +219,11 @@
if (mRecentsPanel.isShowing()) {
dismissAndGoBack();
} else {
- final SystemUIApplication app = (SystemUIApplication) getApplication();
- final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
+ boolean waitingForWindowAnimation = checkWaitingForAnimationParam &&
+ intent.getBooleanExtra(WAITING_FOR_WINDOW_ANIMATION_PARAM, false);
mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
- recentTasksLoader.isFirstScreenful());
+ recentTasksLoader.isFirstScreenful(), waitingForWindowAnimation);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 9f0bcf5..2008d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -59,7 +59,6 @@
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
@@ -68,7 +67,7 @@
import java.util.ArrayList;
public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
- StatusBarPanel, Animator.AnimatorListener, RecentsActivity.WindowAnimationStartListener {
+ StatusBarPanel, Animator.AnimatorListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
private PopupMenu mPopup;
@@ -81,6 +80,7 @@
private boolean mWaitingToShow;
private int mNumItemsWaitingForThumbnailsAndIcons;
private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
+ private boolean mWaitingForWindowAnimation;
private RecentTasksLoader mRecentTasksLoader;
private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -147,13 +147,9 @@
(ImageView) convertView.findViewById(R.id.app_thumbnail_image);
// If we set the default thumbnail now, we avoid an onLayout when we update
// the thumbnail later (if they both have the same dimensions)
- if (mRecentTasksLoader != null) {
- updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
- }
+ updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
- if (mRecentTasksLoader != null) {
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
- }
+ holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -183,8 +179,7 @@
}
if (index == 0) {
final Activity activity = (Activity) RecentsPanelView.this.getContext();
- final SystemUIApplication app = (SystemUIApplication) activity.getApplication();
- if (app.isWaitingForWindowAnimationStart()) {
+ if (mWaitingForWindowAnimation) {
if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
for (View v :
new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
@@ -247,6 +242,7 @@
defStyle, 0);
mRecentItemLayoutId = a.getResourceId(R.styleable.RecentsPanelView_recentItemLayout, 0);
+ mRecentTasksLoader = RecentTasksLoader.getInstance(context);
a.recycle();
}
@@ -280,11 +276,12 @@
}
public void show(boolean show) {
- show(show, null, false);
+ show(show, null, false, false);
}
public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
- boolean firstScreenful) {
+ boolean firstScreenful, boolean waitingForWindowAnimation) {
+ mWaitingForWindowAnimation = waitingForWindowAnimation;
if (show) {
mWaitingToShow = true;
refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
@@ -542,6 +539,7 @@
}
}
mItemToAnimateInWhenWindowAnimationIsFinished = null;
+ mWaitingForWindowAnimation = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java
new file mode 100644
index 0000000..eb5892007
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * 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.recent;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class RecentsPreloadReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (RecentsActivity.PRELOAD_INTENT.equals(intent.getAction())) {
+ RecentTasksLoader.getInstance(context).preloadRecentTasksList();
+ } else if (RecentsActivity.CANCEL_PRELOAD_INTENT.equals(intent.getAction())){
+ RecentTasksLoader.getInstance(context).cancelPreloadingRecentTasksList();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 577b1f4..fe33b02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -25,7 +25,6 @@
import com.android.systemui.R;
import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.recent.RecentsActivity;
import com.android.systemui.recent.TaskDescription;
@@ -37,7 +36,6 @@
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.PendingIntent;
-import android.app.Service;
import android.app.TaskStackBuilder;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -72,9 +70,9 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
@@ -428,10 +426,6 @@
protected abstract WindowManager.LayoutParams getSearchLayoutParams(
LayoutParams layoutParams);
- protected RecentTasksLoader getRecentTasksLoader() {
- final SystemUIApplication app = (SystemUIApplication) ((Service) mContext).getApplication();
- return app.getRecentTasksLoader();
- }
protected void updateSearchPanel() {
// Search Panel
@@ -475,8 +469,8 @@
protected void toggleRecentsActivity() {
try {
- final RecentTasksLoader recentTasksLoader = getRecentTasksLoader();
- TaskDescription firstTask = recentTasksLoader.getFirstTask();
+
+ TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
intent.setClassName("com.android.systemui",
@@ -485,11 +479,18 @@
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
if (firstTask == null) {
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_launch_from_launcher_enter,
- R.anim.recents_launch_from_launcher_exit);
- mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
- UserHandle.USER_CURRENT));
+ if (RecentsActivity.forceOpaqueBackground(mContext)) {
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_launch_from_launcher_enter,
+ R.anim.recents_launch_from_launcher_exit);
+ mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
+ UserHandle.USER_CURRENT));
+ } else {
+ // The correct window animation will be applied via the activity's style
+ mContext.startActivityAsUser(intent, new UserHandle(
+ UserHandle.USER_CURRENT));
+ }
+
} else {
Bitmap first = firstTask.getThumbnail();
final Resources res = mContext.getResources();
@@ -576,17 +577,17 @@
+ recentsItemTopPadding + thumbBgPadding + statusBarHeight);
}
- final SystemUIApplication app =
- (SystemUIApplication) ((Service) mContext).getApplication();
- app.setWaitingForWinAnimStart(true);
ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
getStatusBarView(),
first, x, y,
new ActivityOptions.OnAnimationStartedListener() {
public void onAnimationStarted() {
- app.onWindowAnimationStart();
+ Intent intent = new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
+ intent.setPackage("com.android.systemui");
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
}
});
+ intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
UserHandle.USER_CURRENT));
}
@@ -596,8 +597,49 @@
}
}
+ protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
+ // additional optimization when we have software system buttons - start loading the recent
+ // tasks on touch down
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ int action = event.getAction() & MotionEvent.ACTION_MASK;
+ if (action == MotionEvent.ACTION_DOWN) {
+ preloadRecentTasksList();
+ } else if (action == MotionEvent.ACTION_CANCEL) {
+ cancelPreloadingRecentTasksList();
+ } else if (action == MotionEvent.ACTION_UP) {
+ if (!v.isPressed()) {
+ cancelPreloadingRecentTasksList();
+ }
+
+ }
+ return false;
+ }
+ };
+
+ protected void preloadRecentTasksList() {
+ if (DEBUG) Slog.d(TAG, "preloading recents");
+ Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.recent.RecentsPreloadReceiver");
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+ RecentTasksLoader.getInstance(mContext).preloadFirstTask();
+ }
+
+ protected void cancelPreloadingRecentTasksList() {
+ if (DEBUG) Slog.d(TAG, "cancel preloading recents");
+ Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.recent.RecentsPreloadReceiver");
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+ RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
+ Intent intent;
switch (m.what) {
case MSG_TOGGLE_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "toggle recents panel");
@@ -605,17 +647,15 @@
break;
case MSG_CLOSE_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "closing recents panel");
- Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+ intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
intent.setPackage("com.android.systemui");
mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
break;
case MSG_PRELOAD_RECENT_APPS:
- if (DEBUG) Slog.d(TAG, "preloading recents");
- getRecentTasksLoader().preloadRecentTasksList();
+ preloadRecentTasksList();
break;
case MSG_CANCEL_PRELOAD_RECENT_APPS:
- if (DEBUG) Slog.d(TAG, "cancel preloading recents");
- getRecentTasksLoader().cancelPreloadingRecentTasksList();
+ cancelPreloadingRecentTasksList();
break;
case MSG_OPEN_SEARCH_PANEL:
if (DEBUG) Slog.d(TAG, "opening search panel");
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 27a4db5..5bb9378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -40,7 +40,6 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.NinePatchDrawable;
import android.inputmethodservice.InputMethodService;
import android.os.Handler;
import android.os.IBinder;
@@ -753,7 +752,7 @@
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
- mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader());
+ mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
updateSearchPanel();
}
@@ -1487,6 +1486,7 @@
mFlipSettingsView.setVisibility(View.VISIBLE);
mSettingsButton.setVisibility(View.GONE);
mScrollView.setVisibility(View.GONE);
+ mScrollView.setScaleX(0f);
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButton.setAlpha(1f);
mClearButton.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 97451ae..86c247a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -60,8 +60,6 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
-import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsPanelView;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DoNotDisturb;
@@ -353,7 +351,7 @@
mWindowManager.addView(mCompatModePanel, lp);
- mRecentButton.setOnTouchListener(getRecentTasksLoader());
+ mRecentButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
mPile.removeAllViews();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 24ce9bc..10b11bc 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1912,15 +1912,15 @@
Intent service = new Intent();
service.setClassName(mContext, "com.android.server.LoadAverageService");
ContentResolver res = mContext.getContentResolver();
- boolean shown = Settings.System.getInt(
- res, Settings.System.SHOW_PROCESSES, 0) != 0;
+ boolean shown = Settings.Global.getInt(
+ res, Settings.Global.SHOW_PROCESSES, 0) != 0;
if (!shown) {
mContext.startService(service);
} else {
mContext.stopService(service);
}
- Settings.System.putInt(
- res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
+ Settings.Global.putInt(
+ res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
return -1;
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 9f01eca..f241c80 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1474,6 +1474,7 @@
if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName);
removeEverBackedUp(packageName);
set.remove(packageName);
+ mPendingBackups.remove(packageName);
}
}
@@ -1625,6 +1626,7 @@
} catch (InterruptedException e) {
// just bail
if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
+ mActivityManager.clearPendingBackup();
return null;
}
}
@@ -1632,6 +1634,7 @@
// if we timed out with no connect, abort and move on
if (mConnecting == true) {
Slog.w(TAG, "Timeout waiting for agent " + app);
+ mActivityManager.clearPendingBackup();
return null;
}
if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 63eeeb3..37dee19 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -23,8 +23,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.location.Address;
@@ -90,10 +93,13 @@
private static final String WAKELOCK_KEY = TAG;
private static final String THREAD_NAME = TAG;
- private static final String ACCESS_FINE_LOCATION =
- android.Manifest.permission.ACCESS_FINE_LOCATION;
- private static final String ACCESS_COARSE_LOCATION =
- android.Manifest.permission.ACCESS_COARSE_LOCATION;
+ // Location resolution level: no location data whatsoever
+ private static final int RESOLUTION_LEVEL_NONE = 0;
+ // Location resolution level: coarse location data only
+ private static final int RESOLUTION_LEVEL_COARSE = 1;
+ // Location resolution level: fine location data
+ private static final int RESOLUTION_LEVEL_FINE = 2;
+
private static final String ACCESS_MOCK_LOCATION =
android.Manifest.permission.ACCESS_MOCK_LOCATION;
private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
@@ -246,6 +252,74 @@
updateProvidersLocked();
}
+ private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
+ PackageManager pm = mContext.getPackageManager();
+ String systemPackageName = mContext.getPackageName();
+ ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
+
+ List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
+ new Intent(FUSED_LOCATION_SERVICE_ACTION),
+ PackageManager.GET_META_DATA, mCurrentUserId);
+ for (ResolveInfo rInfo : rInfos) {
+ String packageName = rInfo.serviceInfo.packageName;
+
+ // Check that the signature is in the list of supported sigs. If it's not in
+ // this list the standard provider binding logic won't bind to it.
+ try {
+ PackageInfo pInfo;
+ pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
+ Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
+ ", but has wrong signature, ignoring");
+ continue;
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "missing package: " + packageName);
+ continue;
+ }
+
+ // Get the version info
+ if (rInfo.serviceInfo.metaData == null) {
+ Log.w(TAG, "Found fused provider without metadata: " + packageName);
+ continue;
+ }
+
+ int version = rInfo.serviceInfo.metaData.getInt(
+ ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
+ if (version == 0) {
+ // This should be the fallback fused location provider.
+
+ // Make sure it's in the system partition.
+ if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
+ continue;
+ }
+
+ // Check that the fallback is signed the same as the OS
+ // as a proxy for coreApp="true"
+ if (pm.checkSignatures(systemPackageName, packageName)
+ != PackageManager.SIGNATURE_MATCH) {
+ if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
+ + packageName);
+ continue;
+ }
+
+ // Found a valid fallback.
+ if (D) Log.d(TAG, "Found fallback provider: " + packageName);
+ return;
+ } else {
+ if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
+ }
+ }
+
+ throw new IllegalStateException("Unable to find a fused location provider that is in the "
+ + "system partition with version 0 and signed with the platform certificate. "
+ + "Such a package is needed to provide a default fused location provider in the "
+ + "event that no other fused location provider has been installed or is currently "
+ + "available. For example, coreOnly boot mode when decrypting the data "
+ + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
+ }
+
private void loadProvidersLocked() {
// create a passive location provider, which is always enabled
PassiveProvider passiveProvider = new PassiveProvider(this);
@@ -275,14 +349,13 @@
*/
Resources resources = mContext.getResources();
ArrayList<String> providerPackageNames = new ArrayList<String>();
- String[] pkgs1 = resources.getStringArray(
+ String[] pkgs = resources.getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames);
- String[] pkgs2 = resources.getStringArray(
- com.android.internal.R.array.config_overlay_locationProviderPackageNames);
- if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
- if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
- if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
- if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
+ if (D) Log.d(TAG, "certificates for location providers pulled from: " +
+ Arrays.toString(pkgs));
+ if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
+
+ ensureFallbackFusedProviderPresentLocked(providerPackageNames);
// bind to network provider
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
@@ -347,7 +420,7 @@
final int mUid; // uid of receiver
final int mPid; // pid of receiver
final String mPackageName; // package name of receiver
- final String mPermission; // best permission that receiver has
+ final int mAllowedResolutionLevel; // resolution level allowed to receiver
final ILocationListener mListener;
final PendingIntent mPendingIntent;
@@ -366,7 +439,7 @@
} else {
mKey = intent;
}
- mPermission = checkPermission();
+ mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
mUid = uid;
mPid = pid;
mPackageName = packageName;
@@ -440,7 +513,7 @@
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
- mPermission);
+ getResolutionPermission(mAllowedResolutionLevel));
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -474,7 +547,7 @@
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
- mPermission);
+ getResolutionPermission(mAllowedResolutionLevel));
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -512,7 +585,7 @@
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
- mPermission);
+ getResolutionPermission(mAllowedResolutionLevel));
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -609,51 +682,76 @@
}
/**
- * Returns the best permission available to the caller.
+ * Returns the permission string associated with the specified resolution level.
+ *
+ * @param resolutionLevel the resolution level
+ * @return the permission string
*/
- private String getBestCallingPermission() {
- if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
- PackageManager.PERMISSION_GRANTED) {
- return ACCESS_FINE_LOCATION;
- } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
- PackageManager.PERMISSION_GRANTED) {
- return ACCESS_COARSE_LOCATION;
+ private String getResolutionPermission(int resolutionLevel) {
+ switch (resolutionLevel) {
+ case RESOLUTION_LEVEL_FINE:
+ return android.Manifest.permission.ACCESS_FINE_LOCATION;
+ case RESOLUTION_LEVEL_COARSE:
+ return android.Manifest.permission.ACCESS_COARSE_LOCATION;
+ default:
+ return null;
}
- return null;
}
/**
- * Throw SecurityException if caller has neither COARSE or FINE.
- * Otherwise, return the best permission.
+ * Returns the resolution level allowed to the given PID/UID pair.
+ *
+ * @param pid the PID
+ * @param uid the UID
+ * @return resolution level allowed to the pid/uid pair
*/
- private String checkPermission() {
- String perm = getBestCallingPermission();
- if (perm == null) {
- throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
- " ACCESS_FINE_LOCATION permission");
+ private int getAllowedResolutionLevel(int pid, int uid) {
+ if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
+ pid, uid) == PackageManager.PERMISSION_GRANTED) {
+ return RESOLUTION_LEVEL_FINE;
+ } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ pid, uid) == PackageManager.PERMISSION_GRANTED) {
+ return RESOLUTION_LEVEL_COARSE;
+ } else {
+ return RESOLUTION_LEVEL_NONE;
}
- return perm;
}
/**
- * Throw SecurityException if caller lacks permission to use Geofences.
+ * Returns the resolution level allowed to the caller
+ *
+ * @return resolution level allowed to caller
*/
- private void checkGeofencePermission() {
- if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
+ private int getCallerAllowedResolutionLevel() {
+ return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
+ }
+
+ /**
+ * Throw SecurityException if specified resolution level is insufficient to use geofences.
+ *
+ * @param allowedResolutionLevel resolution level allowed to caller
+ */
+ private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
}
}
- private String getMinimumPermissionForProvider(String provider) {
+ /**
+ * Return the minimum resolution level required to use the specified location provider.
+ *
+ * @param provider the name of the location provider
+ * @return minimum resolution level required for provider
+ */
+ private int getMinimumResolutionLevelForProviderUse(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider) ||
LocationManager.PASSIVE_PROVIDER.equals(provider)) {
// gps and passive providers require FINE permission
- return ACCESS_FINE_LOCATION;
+ return RESOLUTION_LEVEL_FINE;
} else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
LocationManager.FUSED_PROVIDER.equals(provider)) {
// network and fused providers are ok with COARSE or FINE
- return ACCESS_COARSE_LOCATION;
+ return RESOLUTION_LEVEL_COARSE;
} else {
// mock providers
LocationProviderInterface lp = mMockProviders.get(provider);
@@ -662,41 +760,38 @@
if (properties != null) {
if (properties.mRequiresSatellite) {
// provider requiring satellites require FINE permission
- return ACCESS_FINE_LOCATION;
+ return RESOLUTION_LEVEL_FINE;
} else if (properties.mRequiresNetwork || properties.mRequiresCell) {
// provider requiring network and or cell require COARSE or FINE
- return ACCESS_COARSE_LOCATION;
+ return RESOLUTION_LEVEL_COARSE;
}
}
}
}
-
- return null;
+ return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
}
- private boolean isPermissionSufficient(String perm, String minPerm) {
- if (ACCESS_FINE_LOCATION.equals(minPerm)) {
- return ACCESS_FINE_LOCATION.equals(perm);
- } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
- return ACCESS_FINE_LOCATION.equals(perm) ||
- ACCESS_COARSE_LOCATION.equals(perm);
- } else {
- return false;
- }
- }
-
- private void checkPermissionForProvider(String perm, String provider) {
- String minPerm = getMinimumPermissionForProvider(provider);
- if (!isPermissionSufficient(perm, minPerm)) {
- if (ACCESS_FINE_LOCATION.equals(minPerm)) {
- throw new SecurityException("Location provider \"" + provider +
- "\" requires ACCESS_FINE_LOCATION permission.");
- } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
- throw new SecurityException("Location provider \"" + provider +
- "\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
- } else {
- throw new SecurityException("Insufficient permission for location provider \"" +
- provider + "\".");
+ /**
+ * Throw SecurityException if specified resolution level is insufficient to use the named
+ * location provider.
+ *
+ * @param allowedResolutionLevel resolution level allowed to caller
+ * @param providerName the name of the location provider
+ */
+ private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
+ String providerName) {
+ int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
+ if (allowedResolutionLevel < requiredResolutionLevel) {
+ switch (requiredResolutionLevel) {
+ case RESOLUTION_LEVEL_FINE:
+ throw new SecurityException("\"" + providerName + "\" location provider " +
+ "requires ACCESS_FINE_LOCATION permission.");
+ case RESOLUTION_LEVEL_COARSE:
+ throw new SecurityException("\"" + providerName + "\" location provider " +
+ "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
+ default:
+ throw new SecurityException("Insufficient permission for \"" + providerName +
+ "\" location provider.");
}
}
}
@@ -731,8 +826,8 @@
*/
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
ArrayList<String> out;
- String perm = getBestCallingPermission();
int callingUserId = UserHandle.getCallingUserId();
long identity = Binder.clearCallingIdentity();
try {
@@ -743,7 +838,7 @@
if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue;
}
- if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) {
+ if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
continue;
}
@@ -803,8 +898,6 @@
@Override
public boolean providerMeetsCriteria(String provider, Criteria criteria) {
- checkPermission();
-
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
@@ -1010,33 +1103,41 @@
return receiver;
}
- private String checkPermissionAndRequest(LocationRequest request) {
- String perm = getBestCallingPermission();
- String provider = request.getProvider();
- checkPermissionForProvider(perm, provider);
-
- if (ACCESS_COARSE_LOCATION.equals(perm)) {
- switch (request.getQuality()) {
+ /**
+ * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
+ * and consistency requirements.
+ *
+ * @param request the LocationRequest from which to create a sanitized version
+ * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
+ * constraints
+ * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
+ * @return a version of request that meets the given resolution and consistency requirements
+ * @hide
+ */
+ private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
+ LocationRequest sanitizedRequest = new LocationRequest(request);
+ if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
+ switch (sanitizedRequest.getQuality()) {
case LocationRequest.ACCURACY_FINE:
- request.setQuality(LocationRequest.ACCURACY_BLOCK);
+ sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
break;
case LocationRequest.POWER_HIGH:
- request.setQuality(LocationRequest.POWER_LOW);
+ sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
break;
}
// throttle
- if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
- request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
+ if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+ sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
}
- if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
- request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
+ if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+ sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
}
}
// make getFastestInterval() the minimum of interval and fastest interval
- if (request.getFastestInterval() > request.getInterval()) {
+ if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
request.setFastestInterval(request.getInterval());
}
- return perm;
+ return sanitizedRequest;
}
private void checkPackageName(String packageName) {
@@ -1079,7 +1180,10 @@
PendingIntent intent, String packageName) {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
checkPackageName(packageName);
- checkPermissionAndRequest(request);
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
+ request.getProvider());
+ LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -1089,7 +1193,7 @@
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
+ requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1132,7 +1236,7 @@
public void removeUpdates(ILocationListener listener, PendingIntent intent,
String packageName) {
checkPackageName(packageName);
- checkPermission();
+
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
@@ -1188,8 +1292,11 @@
public Location getLastLocation(LocationRequest request, String packageName) {
if (D) Log.d(TAG, "getLastLocation: " + request);
if (request == null) request = DEFAULT_LOCATION_REQUEST;
- String perm = checkPermissionAndRequest(request);
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkPackageName(packageName);
+ checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
+ request.getProvider());
+ // no need to sanitize this request, as only the provider name is used
long identity = Binder.clearCallingIdentity();
try {
@@ -1213,13 +1320,13 @@
if (location == null) {
return null;
}
- if (ACCESS_FINE_LOCATION.equals(perm)) {
- return location;
- } else {
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
if (noGPSLocation != null) {
return mLocationFudger.getOrCreate(noGPSLocation);
}
+ } else {
+ return location;
}
}
return null;
@@ -1232,18 +1339,21 @@
public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
String packageName) {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
- checkGeofencePermission();
- checkPermissionAndRequest(request);
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
checkPendingIntent(intent);
checkPackageName(packageName);
+ checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
+ request.getProvider());
+ LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
- if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
+ if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
// geo-fence manager uses the public location API, need to clear identity
int uid = Binder.getCallingUid();
long identity = Binder.clearCallingIdentity();
try {
- mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
+ mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1251,7 +1361,7 @@
@Override
public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
- checkGeofencePermission();
+ checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
checkPendingIntent(intent);
checkPackageName(packageName);
@@ -1272,10 +1382,8 @@
if (mGpsStatusProvider == null) {
return false;
}
- if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
- }
+ checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+ LocationManager.GPS_PROVIDER);
try {
mGpsStatusProvider.addGpsStatusListener(listener);
@@ -1303,8 +1411,9 @@
// throw NullPointerException to remain compatible with previous implementation
throw new NullPointerException();
}
+ checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+ provider);
- checkPermission();
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) {
@@ -1344,7 +1453,8 @@
return null;
}
- checkPermissionForProvider(getBestCallingPermission(), provider);
+ checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+ provider);
LocationProviderInterface p;
synchronized (mLock) {
@@ -1357,7 +1467,8 @@
@Override
public boolean isProviderEnabled(String provider) {
- checkPermissionForProvider(getBestCallingPermission(), provider);
+ checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+ provider);
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
long identity = Binder.clearCallingIdentity();
@@ -1522,10 +1633,10 @@
}
Location notifyLocation = null;
- if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
- notifyLocation = lastLocation; // use fine location
+ if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+ notifyLocation = coarseLocation; // use coarse location
} else {
- notifyLocation = coarseLocation; // use coarse location if available
+ notifyLocation = lastLocation; // use fine location
}
if (notifyLocation != null) {
Location lastLoc = r.mLastFixBroadcast;
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java
index 5598b0a..2e7c6d1 100644
--- a/services/java/com/android/server/ServiceWatcher.java
+++ b/services/java/com/android/server/ServiceWatcher.java
@@ -43,7 +43,7 @@
*/
public class ServiceWatcher implements ServiceConnection {
private static final boolean D = false;
- private static final String EXTRA_VERSION = "version";
+ public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
private final String mTag;
private final Context mContext;
@@ -58,9 +58,27 @@
// all fields below synchronized on mLock
private IBinder mBinder; // connected service
private String mPackageName; // current best package
- private int mVersion; // current best version
+ private int mVersion = Integer.MIN_VALUE; // current best version
private int mCurrentUserId;
+ public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
+ List<String> initialPackageNames) {
+ PackageManager pm = context.getPackageManager();
+ ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
+ for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
+ String pkg = initialPackageNames.get(i);
+ try {
+ HashSet<Signature> set = new HashSet<Signature>();
+ Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
+ set.addAll(Arrays.asList(sigs));
+ sigSets.add(set);
+ } catch (NameNotFoundException e) {
+ Log.w("ServiceWatcher", pkg + " not found");
+ }
+ }
+ return sigSets;
+ }
+
public ServiceWatcher(Context context, String logTag, String action,
List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
mContext = context;
@@ -71,20 +89,7 @@
mHandler = handler;
mCurrentUserId = userId;
- mSignatureSets = new ArrayList<HashSet<Signature>>();
- for (int i=0; i < initialPackageNames.size(); i++) {
- String pkg = initialPackageNames.get(i);
- HashSet<Signature> set = new HashSet<Signature>();
- try {
- Signature[] sigs =
- mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
- set.addAll(Arrays.asList(sigs));
- mSignatureSets.add(set);
- } catch (NameNotFoundException e) {
- Log.w(logTag, pkg + " not found");
- }
- }
-
+ mSignatureSets = getSignatureSets(context, initialPackageNames);
}
public boolean start() {
@@ -132,15 +137,16 @@
// check version
int version = 0;
if (rInfo.serviceInfo.metaData != null) {
- version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0);
+ version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION, 0);
}
+
if (version > mVersion) {
bestVersion = version;
bestPackage = packageName;
}
}
- if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s",
+ if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
rInfos.size(),
(bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
@@ -174,7 +180,8 @@
| Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
}
- private boolean isSignatureMatch(Signature[] signatures) {
+ public static boolean isSignatureMatch(Signature[] signatures,
+ List<HashSet<Signature>> sigSets) {
if (signatures == null) return false;
// build hashset of input to test against
@@ -184,7 +191,7 @@
}
// test input against each of the signature sets
- for (HashSet<Signature> referenceSet : mSignatureSets) {
+ for (HashSet<Signature> referenceSet : sigSets) {
if (referenceSet.equals(inputSet)) {
return true;
}
@@ -192,6 +199,10 @@
return false;
}
+ private boolean isSignatureMatch(Signature[] signatures) {
+ return isSignatureMatch(signatures, mSignatureSets);
+ }
+
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
/**
* Called when package has been reinstalled
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eaaf33f..e46afd3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -737,7 +737,7 @@
}
if (context.getResources().getBoolean(
- com.android.internal.R.bool.config_enableDreams)) {
+ com.android.internal.R.bool.config_dreamsSupported)) {
try {
Slog.i(TAG, "Dreams Service");
// Dreams (interactive idle-time views, a/k/a screen savers)
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index caf37b7..482bff5 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -40,6 +40,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Property;
import android.util.Slog;
import android.view.Display;
@@ -71,6 +72,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Locale;
/**
* This class handles the screen magnification when accessibility is enabled.
@@ -174,6 +176,8 @@
private PointerCoords[] mTempPointerCoords;
private PointerProperties[] mTempPointerProperties;
+ private long mDelegatingStateDownTime;
+
public ScreenMagnifier(Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -263,10 +267,15 @@
private void handleMotionEventStateDelegating(MotionEvent event,
MotionEvent rawEvent, int policyFlags) {
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
- if (mDetectingStateHandler.mDelayedEventQueue == null) {
- transitionToState(STATE_DETECTING);
- }
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ mDelegatingStateDownTime = event.getDownTime();
+ } break;
+ case MotionEvent.ACTION_UP: {
+ if (mDetectingStateHandler.mDelayedEventQueue == null) {
+ transitionToState(STATE_DETECTING);
+ }
+ } break;
}
if (mNext != null) {
// If the event is within the magnified portion of the screen we have
@@ -293,6 +302,13 @@
coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
event.getFlags());
}
+ // We cache some events to see if the user wants to trigger magnification.
+ // If no magnification is triggered we inject these events with adjusted
+ // time and down time to prevent subsequent transformations being confused
+ // by stale events. After the cached events, which always have a down, are
+ // injected we need to also update the down time of all subsequent non cached
+ // events. All delegated events cached and non-cached are delivered here.
+ event.setDownTime(mDelegatingStateDownTime);
mNext.onMotionEvent(event, rawEvent, policyFlags);
}
}
@@ -1000,45 +1016,44 @@
mViewport.recomputeBounds(mMagnificationController.isMagnifying());
} break;
}
- } else {
- switch (transition) {
- case WindowManagerPolicy.TRANSIT_ENTER:
- case WindowManagerPolicy.TRANSIT_SHOW: {
- if (!magnifying || !isScreenMagnificationAutoUpdateEnabled(mContext)) {
- break;
- }
- final int type = info.type;
- switch (type) {
- // TODO: Are these all the windows we want to make
- // visible when they appear on the screen?
- // Do we need to take some of them out?
- case WindowManager.LayoutParams.TYPE_APPLICATION:
- case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
- case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
- case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
- case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
- case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
- case WindowManager.LayoutParams.TYPE_PHONE:
- case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
- case WindowManager.LayoutParams.TYPE_TOAST:
- case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
- case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
- case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
- case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
- case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
- case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
- case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
- case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
- Rect magnifiedRegionBounds = mMagnificationController
- .getMagnifiedRegionBounds();
- Rect touchableRegion = info.touchableRegion;
- if (!magnifiedRegionBounds.intersect(touchableRegion)) {
- ensureRectangleInMagnifiedRegionBounds(
- magnifiedRegionBounds, touchableRegion);
- }
- } break;
- } break;
+ }
+ switch (transition) {
+ case WindowManagerPolicy.TRANSIT_ENTER:
+ case WindowManagerPolicy.TRANSIT_SHOW: {
+ if (!magnifying || !isScreenMagnificationAutoUpdateEnabled(mContext)) {
+ break;
}
+ final int type = info.type;
+ switch (type) {
+ // TODO: Are these all the windows we want to make
+ // visible when they appear on the screen?
+ // Do we need to take some of them out?
+ case WindowManager.LayoutParams.TYPE_APPLICATION:
+ case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
+ case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
+ case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
+ case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
+ case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
+ case WindowManager.LayoutParams.TYPE_PHONE:
+ case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
+ case WindowManager.LayoutParams.TYPE_TOAST:
+ case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+ case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
+ case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
+ case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
+ case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
+ case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
+ case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
+ case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
+ Rect magnifiedRegionBounds = mMagnificationController
+ .getMagnifiedRegionBounds();
+ Rect touchableRegion = info.touchableRegion;
+ if (!magnifiedRegionBounds.intersect(touchableRegion)) {
+ ensureRectangleInMagnifiedRegionBounds(
+ magnifiedRegionBounds, touchableRegion);
+ }
+ } break;
+ } break;
}
}
} finally {
@@ -1067,7 +1082,12 @@
final float scrollX;
final float scrollY;
if (rectangle.width() > magnifiedRegionBounds.width()) {
- scrollX = rectangle.left - magnifiedRegionBounds.left;
+ final int direction = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
+ if (direction == View.LAYOUT_DIRECTION_LTR) {
+ scrollX = rectangle.left - magnifiedRegionBounds.left;
+ } else {
+ scrollX = rectangle.right - magnifiedRegionBounds.right;
+ }
} else if (rectangle.left < magnifiedRegionBounds.left) {
scrollX = rectangle.left - magnifiedRegionBounds.left;
} else if (rectangle.right > magnifiedRegionBounds.right) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7132e1e..5722326 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7251,11 +7251,11 @@
// care about.
if (persistent) {
final ContentResolver resolver = mContext.getContentResolver();
- Settings.System.putString(
- resolver, Settings.System.DEBUG_APP,
+ Settings.Global.putString(
+ resolver, Settings.Global.DEBUG_APP,
packageName);
- Settings.System.putInt(
- resolver, Settings.System.WAIT_FOR_DEBUGGER,
+ Settings.Global.putInt(
+ resolver, Settings.Global.WAIT_FOR_DEBUGGER,
waitForDebugger ? 1 : 0);
}
@@ -7317,9 +7317,9 @@
enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
"setAlwaysFinish()");
- Settings.System.putInt(
+ Settings.Global.putInt(
mContext.getContentResolver(),
- Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
+ Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
synchronized (this) {
mAlwaysFinishActivities = enabled;
@@ -7596,12 +7596,12 @@
private void retrieveSettings() {
final ContentResolver resolver = mContext.getContentResolver();
- String debugApp = Settings.System.getString(
- resolver, Settings.System.DEBUG_APP);
- boolean waitForDebugger = Settings.System.getInt(
- resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
- boolean alwaysFinishActivities = Settings.System.getInt(
- resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+ String debugApp = Settings.Global.getString(
+ resolver, Settings.Global.DEBUG_APP);
+ boolean waitForDebugger = Settings.Global.getInt(
+ resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
+ boolean alwaysFinishActivities = Settings.Global.getInt(
+ resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
Configuration configuration = new Configuration();
Settings.System.getConfiguration(resolver, configuration);
@@ -11119,8 +11119,8 @@
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
- if (DEBUG_BACKUP) Slog.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
- enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
+ if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + app + " mode=" + backupMode);
+ enforceCallingPermission("android.permission.BACKUP", "bindBackupAgent");
synchronized(this) {
// !!! TODO: currently no check here that we're already bound
@@ -11181,6 +11181,17 @@
return true;
}
+ @Override
+ public void clearPendingBackup() {
+ if (DEBUG_BACKUP) Slog.v(TAG, "clearPendingBackup");
+ enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
+
+ synchronized (this) {
+ mBackupTarget = null;
+ mBackupAppName = null;
+ }
+ }
+
// A backup agent has just come up
public void backupAgentCreated(String agentPackageName, IBinder agent) {
if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName
@@ -11217,32 +11228,34 @@
}
synchronized(this) {
- if (mBackupAppName == null) {
- Slog.w(TAG, "Unbinding backup agent with no active backup");
- return;
- }
-
- if (!mBackupAppName.equals(appInfo.packageName)) {
- Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
- return;
- }
-
- ProcessRecord proc = mBackupTarget.app;
- mBackupTarget = null;
- mBackupAppName = null;
-
- // Not backing this app up any more; reset its OOM adjustment
- updateOomAdjLocked(proc);
-
- // If the app crashed during backup, 'thread' will be null here
- if (proc.thread != null) {
- try {
- proc.thread.scheduleDestroyBackupAgent(appInfo,
- compatibilityInfoForPackageLocked(appInfo));
- } catch (Exception e) {
- Slog.e(TAG, "Exception when unbinding backup agent:");
- e.printStackTrace();
+ try {
+ if (mBackupAppName == null) {
+ Slog.w(TAG, "Unbinding backup agent with no active backup");
+ return;
}
+
+ if (!mBackupAppName.equals(appInfo.packageName)) {
+ Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
+ return;
+ }
+
+ // Not backing this app up any more; reset its OOM adjustment
+ final ProcessRecord proc = mBackupTarget.app;
+ updateOomAdjLocked(proc);
+
+ // If the app crashed during backup, 'thread' will be null here
+ if (proc.thread != null) {
+ try {
+ proc.thread.scheduleDestroyBackupAgent(appInfo,
+ compatibilityInfoForPackageLocked(appInfo));
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception when unbinding backup agent:");
+ e.printStackTrace();
+ }
+ }
+ } finally {
+ mBackupTarget = null;
+ mBackupAppName = null;
}
}
}
diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/java/com/android/server/display/DisplayAdapter.java
index abc1d32..b411a0d 100644
--- a/services/java/com/android/server/display/DisplayAdapter.java
+++ b/services/java/com/android/server/display/DisplayAdapter.java
@@ -42,6 +42,7 @@
public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2;
public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3;
+ // Called with SyncRoot lock held.
public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, String name) {
mSyncRoot = syncRoot;
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index 7ec537f..919733d 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -29,6 +29,7 @@
final class HeadlessDisplayAdapter extends DisplayAdapter {
private static final String TAG = "HeadlessDisplayAdapter";
+ // Called with SyncRoot lock held.
public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
super(syncRoot, context, handler, listener, TAG);
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index fe38d7f..d6c5248 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -44,21 +44,21 @@
private final SparseArray<LocalDisplayDevice> mDevices =
new SparseArray<LocalDisplayDevice>();
- private final HotplugDisplayEventReceiver mHotplugReceiver;
+ private HotplugDisplayEventReceiver mHotplugReceiver;
private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
+ // Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
super(syncRoot, context, handler, listener, TAG);
- mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper());
}
@Override
public void registerLocked() {
- // TODO: listen for notifications from Surface Flinger about
- // built-in displays being added or removed and rescan as needed.
super.registerLocked();
+
+ mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
scanDisplaysLocked();
}
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index dfacf2a..937ebcf 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -64,6 +64,7 @@
new ArrayList<OverlayDisplayHandle>();
private String mCurrentOverlaySetting = "";
+ // Called with SyncRoot lock held.
public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, Handler uiHandler) {
super(syncRoot, context, handler, listener, TAG);
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index 66eac88..f9d58af 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -73,8 +73,8 @@
private final boolean mSupportsProtectedBuffers;
private final NotificationManager mNotificationManager;
- private final PendingIntent mSettingsPendingIntent;
- private final PendingIntent mDisconnectPendingIntent;
+ private PendingIntent mSettingsPendingIntent;
+ private PendingIntent mDisconnectPendingIntent;
private WifiDisplayController mDisplayController;
private WifiDisplayDevice mDisplayDevice;
@@ -90,6 +90,7 @@
private boolean mPendingStatusChangeBroadcast;
private boolean mPendingNotificationUpdate;
+ // Called with SyncRoot lock held.
public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener,
PersistentDataStore persistentDataStore) {
@@ -100,20 +101,6 @@
com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
mNotificationManager = (NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
-
- Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
- settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mSettingsPendingIntent = PendingIntent.getActivityAsUser(
- context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
-
- Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
- mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
- context, 0, disconnectIntent, 0, UserHandle.CURRENT);
-
- context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
- new IntentFilter(ACTION_DISCONNECT), null, mHandler);
}
@Override
@@ -153,6 +140,9 @@
public void run() {
mDisplayController = new WifiDisplayController(
getContext(), getHandler(), mWifiDisplayListener);
+
+ getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+ new IntentFilter(ACTION_DISCONNECT), null, mHandler);
}
});
}
@@ -366,12 +356,31 @@
isConnected = (mDisplayDevice != null);
}
+ // Cancel the old notification if there is one.
mNotificationManager.cancelAsUser(null,
R.string.wifi_display_notification_title, UserHandle.ALL);
if (isConnected) {
Context context = getContext();
+ // Initialize pending intents for the notification outside of the lock because
+ // creating a pending intent requires a call into the activity manager.
+ if (mSettingsPendingIntent == null) {
+ Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+ settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mSettingsPendingIntent = PendingIntent.getActivityAsUser(
+ context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
+ }
+
+ if (mDisconnectPendingIntent == null) {
+ Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
+ mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
+ context, 0, disconnectIntent, 0, UserHandle.CURRENT);
+ }
+
+ // Post the notification.
Resources r = context.getResources();
Notification notification = new Notification.Builder(context)
.setContentTitle(r.getString(
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 77e6c03..072dd33 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -62,6 +62,8 @@
private static final String LOG_TAG = "UserManagerService";
+ private static final boolean DBG = false;
+
private static final String TAG_NAME = "name";
private static final String ATTR_FLAGS = "flags";
private static final String ATTR_ICON_PATH = "icon";
@@ -97,6 +99,9 @@
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
+ // This resets on a reboot. Otherwise it keeps incrementing so that user ids are
+ // not reused in quick succession
+ private int mNextUserId = MIN_USER_ID;
private static UserManagerService sInstance;
@@ -199,7 +204,8 @@
*/
private UserInfo getUserInfoLocked(int userId) {
UserInfo ui = mUsers.get(userId);
- if (ui != null && ui.partial) {
+ // If it is partial and not in the process of being removed, return as unknown user.
+ if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
@@ -668,6 +674,7 @@
long now = System.currentTimeMillis();
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
userInfo.partial = true;
+ Environment.getUserSystemDirectory(userInfo.id).mkdirs();
mUsers.put(userId, userInfo);
writeUserListLocked();
writeUserLocked(userInfo);
@@ -709,7 +716,7 @@
user.partial = true;
writeUserLocked(user);
}
-
+ if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
int res;
try {
res = ActivityManagerNative.getDefault().stopUser(userHandle,
@@ -730,12 +737,13 @@
}
void finishRemoveUser(int userHandle) {
+ if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
removeUserStateLocked(userHandle);
}
}
-
+ if (DBG) Slog.i(LOG_TAG, "Removed user " + userHandle + ", sending broadcast");
// Let other services shutdown any activity
long ident = Binder.clearCallingIdentity();
try {
@@ -804,10 +812,11 @@
num++;
}
}
- int[] newUsers = new int[num];
+ final int[] newUsers = new int[num];
+ int n = 0;
for (int i = 0; i < mUsers.size(); i++) {
if (!mUsers.valueAt(i).partial) {
- newUsers[i] = mUsers.keyAt(i);
+ newUsers[n++] = mUsers.keyAt(i);
}
}
mUserIds = newUsers;
@@ -840,13 +849,14 @@
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
- int i = MIN_USER_ID;
+ int i = mNextUserId;
while (i < Integer.MAX_VALUE) {
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
break;
}
i++;
}
+ mNextUserId = i + 1;
return i;
}
}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 1561dba..661b949 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -128,28 +128,33 @@
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
// Light sensor event rate in microseconds.
- private static final int LIGHT_SENSOR_RATE = 1000000;
+ private static final int LIGHT_SENSOR_RATE = 500 * 1000;
// Brightness animation ramp rate in brightness units per second.
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
- private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
+ private static final int BRIGHTNESS_RAMP_RATE_SLOW = 30;
- // Filter time constant in milliseconds for computing a moving
- // average of light samples. Different constants are used
- // to calculate the average light level when adapting to brighter or
- // dimmer environments.
- // This parameter only controls the filtering of light samples.
- private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 600;
- private static final long DIMMING_LIGHT_TIME_CONSTANT = 4000;
+ // IIR filter time constants in milliseconds for computing two moving averages of
+ // the light samples. One is a long-term average and the other is a short-term average.
+ // We can use these filters to assess trends in ambient brightness.
+ // The short term average gives us a filtered but relatively low latency measurement.
+ // The long term average informs us about the overall trend.
+ private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
+ private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 8000;
// Stability requirements in milliseconds for accepting a new brightness
// level. This is used for debouncing the light sensor. Different constants
- // are used to debounce the light sensor when adapting to brighter or dimmer
- // environments.
+ // are used to debounce the light sensor when adapting to brighter or darker environments.
// This parameter controls how quickly brightness changes occur in response to
- // an observed change in light level.
- private static final long BRIGHTENING_LIGHT_DEBOUNCE = 2500;
- private static final long DIMMING_LIGHT_DEBOUNCE = 10000;
+ // an observed change in light level following a previous change in the opposite direction.
+ private static final long BRIGHTENING_LIGHT_DEBOUNCE = 5000;
+ private static final long DARKENING_LIGHT_DEBOUNCE = 15000;
+
+ // Hysteresis constraints for brightening or darkening.
+ // The recent lux must have changed by at least this fraction relative to the
+ // current ambient lux before a change will be considered.
+ private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
+ private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
private final Object mLock = new Object();
@@ -284,39 +289,28 @@
// The time when the light sensor was enabled.
private long mLightSensorEnableTime;
- // The currently accepted average light sensor value.
- private float mLightMeasurement;
+ // The currently accepted nominal ambient light level.
+ private float mAmbientLux;
- // True if the light sensor measurement is valid.
- private boolean mLightMeasurementValid;
+ // True if mAmbientLux holds a valid value.
+ private boolean mAmbientLuxValid;
- // The number of light sensor samples that have been collected since the
- // last time a light sensor reading was accepted.
- private int mRecentLightSamples;
-
- // The moving average of recent light sensor values.
- private float mRecentLightAverage;
-
- // True if recent light samples are getting brighter than the previous
- // stable light measurement.
- private boolean mRecentLightBrightening;
-
- // The time constant to use for filtering based on whether the
- // light appears to be brightening or dimming.
- private long mRecentLightTimeConstant;
+ // The time when the ambient lux was last brightened or darkened.
+ private long mLastAmbientBrightenTime;
+ private long mLastAmbientDarkenTime;
// The most recent light sample.
- private float mLastLightSample;
+ private float mLastObservedLux;
// The time of the most light recent sample.
- private long mLastLightSampleTime;
+ private long mLastObservedLuxTime;
- // The time when we accumulated the first recent light sample into mRecentLightSamples.
- private long mFirstRecentLightSampleTime;
+ // The number of light samples collected since the light sensor was enabled.
+ private int mRecentLightSamples;
- // The upcoming debounce light sensor time.
- // This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
- private long mPendingLightSensorDebounceTime;
+ // The long-term and short-term filtered light measurements.
+ private float mRecentShortTermAverageLux;
+ private float mRecentLongTermAverageLux;
// The screen brightness level that has been chosen by the auto-brightness
// algorithm. The actual brightness should ramp towards this value.
@@ -873,7 +867,8 @@
} else {
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
- mLightMeasurementValid = false;
+ mAmbientLuxValid = false;
+ mRecentLightSamples = 0;
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mLightSensorListener);
}
@@ -884,114 +879,99 @@
}
private void handleLightSensorEvent(long time, float lux) {
- // Take the first few readings during the warm-up period and apply them
- // immediately without debouncing.
- if (!mLightMeasurementValid
- || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
- mLightMeasurement = lux;
- mLightMeasurementValid = true;
- mRecentLightSamples = 0;
- updateAutoBrightness(true);
- }
-
- // Update our moving average.
- if (lux != mLightMeasurement && (mRecentLightSamples == 0
- || (lux < mLightMeasurement && mRecentLightBrightening)
- || (lux > mLightMeasurement && !mRecentLightBrightening))) {
- // If the newest light sample doesn't seem to be going in the
- // same general direction as recent samples, then start over.
- setRecentLight(time, lux, lux > mLightMeasurement);
- } else if (mRecentLightSamples >= 1) {
- // Add the newest light sample to the moving average.
- accumulateRecentLight(time, lux);
- }
- if (DEBUG) {
- Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
- + ", mLightMeasurementValid=" + mLightMeasurementValid
- + ", mLightMeasurement=" + mLightMeasurement
- + ", mRecentLightSamples=" + mRecentLightSamples
- + ", mRecentLightAverage=" + mRecentLightAverage
- + ", mRecentLightBrightening=" + mRecentLightBrightening
- + ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
- + ", mFirstRecentLightSampleTime="
- + TimeUtils.formatUptime(mFirstRecentLightSampleTime)
- + ", mPendingLightSensorDebounceTime="
- + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
- }
-
- // Debounce.
- mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
- debounceLightSensor();
- }
-
- private void setRecentLight(long time, float lux, boolean brightening) {
- mRecentLightBrightening = brightening;
- mRecentLightTimeConstant = brightening ?
- BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
- mRecentLightSamples = 1;
- mRecentLightAverage = lux;
- mLastLightSample = lux;
- mLastLightSampleTime = time;
- mFirstRecentLightSampleTime = time;
- mPendingLightSensorDebounceTime = time + (brightening ?
- BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE);
- }
-
- private void accumulateRecentLight(long time, float lux) {
- final long timeDelta = time - mLastLightSampleTime;
+ // Update our filters.
mRecentLightSamples += 1;
- mRecentLightAverage += (lux - mRecentLightAverage) *
- timeDelta / (mRecentLightTimeConstant + timeDelta);
- mLastLightSample = lux;
- mLastLightSampleTime = time;
+ if (mRecentLightSamples == 1) {
+ mRecentShortTermAverageLux = lux;
+ mRecentLongTermAverageLux = lux;
+ } else {
+ final long timeDelta = time - mLastObservedLuxTime;
+ mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
+ * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
+ mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
+ * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
+ }
+
+ // Remember this sample value.
+ mLastObservedLux = lux;
+ mLastObservedLuxTime = time;
+
+ // Update the ambient lux level.
+ mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
+ updateAmbientLux(time);
}
- private void debounceLightSensor() {
- if (mLightMeasurementValid && mRecentLightSamples >= 1) {
- final long now = SystemClock.uptimeMillis();
- if (mPendingLightSensorDebounceTime <= now) {
- accumulateRecentLight(now, mLastLightSample);
- mLightMeasurement = mRecentLightAverage;
+ private void updateAmbientLux(long time) {
+ // If the light sensor was just turned on then immediately update our initial
+ // estimate of the current ambient light level.
+ if (!mAmbientLuxValid
+ || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Initializing, "
+ + "mAmbientLux=" + (mAmbientLuxValid ? mAmbientLux : -1)
+ + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+ + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
+ }
+ mAmbientLux = mRecentShortTermAverageLux;
+ mAmbientLuxValid = true;
+ mLastAmbientBrightenTime = time;
+ mLastAmbientDarkenTime = time;
+ updateAutoBrightness(true);
+ return;
+ }
+ // Determine whether the ambient environment appears to be brightening.
+ float minAmbientLux = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
+ if (mRecentShortTermAverageLux > minAmbientLux
+ && mRecentLongTermAverageLux > minAmbientLux) {
+ long debounceTime = mLastAmbientDarkenTime + BRIGHTENING_LIGHT_DEBOUNCE;
+ if (time >= debounceTime) {
if (DEBUG) {
- Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
- + mLightMeasurement + " after "
- + (now - mFirstRecentLightSampleTime) + " ms based on "
- + mRecentLightSamples + " recent samples.");
+ Slog.d(TAG, "updateAmbientLux: Brightened: "
+ + "mAmbientLux=" + mAmbientLux
+ + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+ + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
}
-
+ mLastAmbientBrightenTime = time;
+ mAmbientLux = mRecentShortTermAverageLux;
updateAutoBrightness(true);
-
- // Now that we have debounced the light sensor data, we have the
- // option of either leaving the sensor in a debounced state or
- // restarting the debounce cycle by setting mRecentLightSamples to 0.
- //
- // If we leave the sensor debounced, then new average light measurements
- // may be accepted immediately as long as they are trending in the same
- // direction as they were before. If the measurements start
- // jittering or trending in the opposite direction then the debounce
- // cycle will automatically be restarted. The benefit is that the
- // auto-brightness control can be more responsive to changes over a
- // broad range.
- //
- // For now, we choose to be more responsive and leave the following line
- // commented out.
- //
- // mRecentLightSamples = 0;
} else {
- Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
+ mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
+ }
+ return;
+ }
+
+ // Determine whether the ambient environment appears to be darkening.
+ float maxAmbientLux = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
+ if (mRecentShortTermAverageLux < maxAmbientLux
+ && mRecentLongTermAverageLux < maxAmbientLux) {
+ long debounceTime = mLastAmbientBrightenTime + DARKENING_LIGHT_DEBOUNCE;
+ if (time >= debounceTime) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Darkened: "
+ + "mAmbientLux=" + mAmbientLux
+ + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+ + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
+ }
+ mLastAmbientDarkenTime = time;
+ mAmbientLux = mRecentShortTermAverageLux;
+ updateAutoBrightness(true);
+ } else {
+ mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
}
}
}
+ private void debounceLightSensor() {
+ updateAmbientLux(SystemClock.uptimeMillis());
+ }
+
private void updateAutoBrightness(boolean sendUpdate) {
- if (!mLightMeasurementValid) {
+ if (!mAmbientLuxValid) {
return;
}
- float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
+ float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
float gamma = 1.0f;
if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
@@ -1031,7 +1011,7 @@
}
int newScreenAutoBrightness = clampScreenBrightness(
- (int)Math.round(value * PowerManager.BRIGHTNESS_ON));
+ Math.round(value * PowerManager.BRIGHTNESS_ON));
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
@@ -1152,19 +1132,18 @@
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
pw.println(" mLightSensorEnableTime="
+ TimeUtils.formatUptime(mLightSensorEnableTime));
- pw.println(" mLightMeasurement=" + mLightMeasurement);
- pw.println(" mLightMeasurementValid=" + mLightMeasurementValid);
- pw.println(" mLastLightSample=" + mLastLightSample);
- pw.println(" mLastLightSampleTime="
- + TimeUtils.formatUptime(mLastLightSampleTime));
+ pw.println(" mAmbientLux=" + mAmbientLux);
+ pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
+ pw.println(" mLastAmbientBrightenTime="
+ + TimeUtils.formatUptime(mLastAmbientBrightenTime));
+ pw.println(" mLastAmbientDimTime="
+ + TimeUtils.formatUptime(mLastAmbientDarkenTime));
+ pw.println(" mLastObservedLux=" + mLastObservedLux);
+ pw.println(" mLastObservedLuxTime="
+ + TimeUtils.formatUptime(mLastObservedLuxTime));
pw.println(" mRecentLightSamples=" + mRecentLightSamples);
- pw.println(" mRecentLightAverage=" + mRecentLightAverage);
- pw.println(" mRecentLightBrightening=" + mRecentLightBrightening);
- pw.println(" mRecentLightTimeConstant=" + mRecentLightTimeConstant);
- pw.println(" mFirstRecentLightSampleTime="
- + TimeUtils.formatUptime(mFirstRecentLightSampleTime));
- pw.println(" mPendingLightSensorDebounceTime="
- + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
+ pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
+ pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
diff --git a/services/java/com/android/server/power/PhotonicModulator.java b/services/java/com/android/server/power/PhotonicModulator.java
index c9b5d90..648c0c5 100644
--- a/services/java/com/android/server/power/PhotonicModulator.java
+++ b/services/java/com/android/server/power/PhotonicModulator.java
@@ -16,6 +16,8 @@
package com.android.server.power;
+import android.util.Slog;
+
import com.android.server.LightsService;
import java.util.concurrent.Executor;
@@ -27,6 +29,9 @@
* setting the backlight brightness is especially slow.
*/
final class PhotonicModulator {
+ private static final String TAG = "PhotonicModulator";
+ private static final boolean DEBUG = false;
+
private static final int UNKNOWN_LIGHT_VALUE = -1;
private final Object mLock = new Object();
@@ -58,6 +63,9 @@
synchronized (mLock) {
if (lightValue != mPendingLightValue) {
mPendingLightValue = lightValue;
+ if (DEBUG) {
+ Slog.d(TAG, "Enqueuing request to change brightness to " + lightValue);
+ }
if (!mPendingChange) {
mPendingChange = true;
mSuspendBlocker.acquire();
@@ -91,6 +99,9 @@
}
mActualLightValue = newLightValue;
}
+ if (DEBUG) {
+ Slog.d(TAG, "Setting brightness to " + newLightValue);
+ }
mLight.setBrightness(newLightValue);
}
}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index b94bceb..bf81a90 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -280,6 +280,15 @@
// True if dreams are supported on this device.
private boolean mDreamsSupportedConfig;
+ // Default value for dreams enabled
+ private boolean mDreamsEnabledByDefaultConfig;
+
+ // Default value for dreams activate-on-sleep
+ private boolean mDreamsActivatedOnSleepByDefaultConfig;
+
+ // Default value for dreams activate-on-dock
+ private boolean mDreamsActivatedOnDockByDefaultConfig;
+
// True if dreams are enabled by the user.
private boolean mDreamsEnabledSetting;
@@ -490,20 +499,29 @@
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
mDreamsSupportedConfig = resources.getBoolean(
- com.android.internal.R.bool.config_enableDreams);
+ com.android.internal.R.bool.config_dreamsSupported);
+ mDreamsEnabledByDefaultConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledByDefault);
+ mDreamsActivatedOnSleepByDefaultConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
+ mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
}
private void updateSettingsLocked() {
final ContentResolver resolver = mContext.getContentResolver();
mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
- Settings.Secure.SCREENSAVER_ENABLED, 0,
+ Settings.Secure.SCREENSAVER_ENABLED,
+ mDreamsEnabledByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
- Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
- Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 0,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 3898ebc..68cdbfc 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -66,14 +66,17 @@
int mBaseDisplayWidth = 0;
int mBaseDisplayHeight = 0;
int mBaseDisplayDensity = 0;
- final DisplayInfo mDisplayInfo = new DisplayInfo();
- final Display mDisplay;
+ private final DisplayInfo mDisplayInfo = new DisplayInfo();
+ private final Display mDisplay;
// Accessed directly by all users.
boolean layoutNeeded;
int pendingLayoutChanges;
final boolean isDefaultDisplay;
+ /**
+ * @param display May not be null.
+ */
DisplayContent(Display display) {
mDisplay = display;
mDisplayId = display.getDisplayId();
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 545fce5..72fc180 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -190,9 +190,11 @@
}
final WindowList windows = mService.getWindowListLocked(mDisplay);
- final int N = windows.size();
- for (int i = 0; i < N; i++) {
- sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
+ if (windows != null) {
+ final int N = windows.size();
+ for (int i = 0; i < N; i++) {
+ sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
+ }
}
}
@@ -393,6 +395,9 @@
final int y = (int) yf;
final WindowList windows = mService.getWindowListLocked(mDisplay);
+ if (windows == null) {
+ return null;
+ }
final int N = windows.size();
for (int i = N - 1; i >= 0; i--) {
WindowState child = windows.get(i);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index fa450ae..52992a1 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2092,6 +2092,11 @@
throw new IllegalStateException("Display has not been initialialized");
}
+ final DisplayContent displayContent = getDisplayContentLocked(displayId);
+ if (displayContent == null) {
+ return WindowManagerGlobal.ADD_INVALID_DISPLAY;
+ }
+
if (mWindowMap.containsKey(client.asBinder())) {
Slog.w(TAG, "Window " + client + " is already added");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
@@ -2174,7 +2179,6 @@
}
}
- final DisplayContent displayContent = getDisplayContentLocked(displayId);
win = new WindowState(this, session, client, token,
attachedWindow, seq, attrs, viewVisibility, displayContent);
if (win.mDeathRecipient == null) {
@@ -2420,6 +2424,7 @@
final WindowList windows = win.getWindowList();
windows.remove(win);
mPendingRemove.remove(win);
+ mResizingWindows.remove(win);
mWindowsChanged = true;
if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
@@ -3384,8 +3389,15 @@
} else {
// Exiting app
if (scaleUp) {
- // noop animation
- a = new AlphaAnimation(1, 0);
+ if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN) {
+ // Fade out while bringing up selected activity. This keeps the
+ // current activity from showing through a launching wallpaper
+ // activity.
+ a = new AlphaAnimation(1, 0);
+ } else {
+ // noop animation
+ a = new AlphaAnimation(1, 1);
+ }
a.setDuration(duration);
} else {
float scaleW = thumbWidth / displayInfo.appWidth;
@@ -5704,6 +5716,7 @@
* @param width the width of the target bitmap
* @param height the height of the target bitmap
*/
+ @Override
public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height) {
if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
"screenshotApplications()")) {
@@ -5723,6 +5736,9 @@
long ident = Binder.clearCallingIdentity();
final DisplayContent displayContent = getDisplayContentLocked(displayId);
+ if (displayContent == null) {
+ return null;
+ }
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
dw = displayInfo.logicalWidth;
dh = displayInfo.logicalHeight;
@@ -6465,6 +6481,7 @@
return success;
}
+ @Override
public void addDisplayContentChangeListener(int displayId,
IDisplayContentChangeListener listener) {
if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
@@ -6473,14 +6490,17 @@
}
synchronized(mWindowMap) {
DisplayContent displayContent = getDisplayContentLocked(displayId);
- if (displayContent.mDisplayContentChangeListeners == null) {
- displayContent.mDisplayContentChangeListeners =
- new RemoteCallbackList<IDisplayContentChangeListener>();
- displayContent.mDisplayContentChangeListeners.register(listener);
+ if (displayContent != null) {
+ if (displayContent.mDisplayContentChangeListeners == null) {
+ displayContent.mDisplayContentChangeListeners =
+ new RemoteCallbackList<IDisplayContentChangeListener>();
+ displayContent.mDisplayContentChangeListeners.register(listener);
+ }
}
}
}
+ @Override
public void removeDisplayContentChangeListener(int displayId,
IDisplayContentChangeListener listener) {
if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
@@ -6489,11 +6509,13 @@
}
synchronized(mWindowMap) {
DisplayContent displayContent = getDisplayContentLocked(displayId);
- if (displayContent.mDisplayContentChangeListeners != null) {
- displayContent.mDisplayContentChangeListeners.unregister(listener);
- if (displayContent.mDisplayContentChangeListeners
- .getRegisteredCallbackCount() == 0) {
- displayContent.mDisplayContentChangeListeners = null;
+ if (displayContent != null) {
+ if (displayContent.mDisplayContentChangeListeners != null) {
+ displayContent.mDisplayContentChangeListeners.unregister(listener);
+ if (displayContent.mDisplayContentChangeListeners
+ .getRegisteredCallbackCount() == 0) {
+ displayContent.mDisplayContentChangeListeners = null;
+ }
}
}
}
@@ -7149,7 +7171,6 @@
synchronized(mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final Display display = displayContent.getDisplay();
readForcedDisplaySizeAndDensityLocked(displayContent);
mDisplayReady = true;
@@ -7173,24 +7194,25 @@
}
}
- public void displayReady(int displayId) {
+ private void displayReady(int displayId) {
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
- final DisplayInfo displayInfo;
- mAnimator.addDisplayLocked(displayId);
- synchronized(displayContent.mDisplaySizeLock) {
- // Bootstrap the default logical display from the display manager.
- displayInfo = displayContent.getDisplayInfo();
- DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
- if (newDisplayInfo != null) {
- displayInfo.copyFrom(newDisplayInfo);
+ if (displayContent != null) {
+ mAnimator.addDisplayLocked(displayId);
+ synchronized(displayContent.mDisplaySizeLock) {
+ // Bootstrap the default logical display from the display manager.
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
+ if (newDisplayInfo != null) {
+ displayInfo.copyFrom(newDisplayInfo);
+ }
+ displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
+ displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
+ displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
+ displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
+ displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
+ displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
}
- displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
- displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
- displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
- displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
- displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
- displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
}
}
}
@@ -7831,12 +7853,15 @@
// TODO(cmautner): Access to DisplayContent should be locked on mWindowMap. Doing that
// could lead to deadlock since this is called from ActivityManager.
final DisplayContent displayContent = getDisplayContentLocked(displayId);
- synchronized(displayContent.mDisplaySizeLock) {
- size.x = displayContent.mInitialDisplayWidth;
- size.y = displayContent.mInitialDisplayHeight;
+ if (displayContent != null) {
+ synchronized(displayContent.mDisplaySizeLock) {
+ size.x = displayContent.mInitialDisplayWidth;
+ size.y = displayContent.mInitialDisplayHeight;
+ }
}
}
+ @Override
public void setForcedDisplaySize(int displayId, int width, int height) {
synchronized(mWindowMap) {
// Set some sort of reasonable bounds on the size of the display that we
@@ -7845,14 +7870,15 @@
final int MIN_HEIGHT = 200;
final int MAX_SCALE = 2;
final DisplayContent displayContent = getDisplayContentLocked(displayId);
-
- width = Math.min(Math.max(width, MIN_WIDTH),
- displayContent.mInitialDisplayWidth * MAX_SCALE);
- height = Math.min(Math.max(height, MIN_HEIGHT),
- displayContent.mInitialDisplayHeight * MAX_SCALE);
- setForcedDisplaySizeLocked(displayContent, width, height);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
+ if (displayContent != null) {
+ width = Math.min(Math.max(width, MIN_WIDTH),
+ displayContent.mInitialDisplayWidth * MAX_SCALE);
+ height = Math.min(Math.max(height, MIN_HEIGHT),
+ displayContent.mInitialDisplayHeight * MAX_SCALE);
+ setForcedDisplaySizeLocked(displayContent, width, height);
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
+ }
}
}
@@ -7895,6 +7921,7 @@
}
}
+ // displayContent must not be null
private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
Slog.i(TAG, "Using new display size: " + width + "x" + height);
@@ -7905,25 +7932,32 @@
reconfigureDisplayLocked(displayContent);
}
+ @Override
public void clearForcedDisplaySize(int displayId) {
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
- setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
- displayContent.mInitialDisplayHeight);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_SIZE_FORCED, "");
+ if (displayContent != null) {
+ setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
+ displayContent.mInitialDisplayHeight);
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.DISPLAY_SIZE_FORCED, "");
+ }
}
}
+ @Override
public void setForcedDisplayDensity(int displayId, int density) {
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
- setForcedDisplayDensityLocked(displayContent, density);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
+ if (displayContent != null) {
+ setForcedDisplayDensityLocked(displayContent, density);
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
+ }
}
}
+ // displayContent must not be null
private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
Slog.i(TAG, "Using new display density: " + density);
@@ -7933,15 +7967,19 @@
reconfigureDisplayLocked(displayContent);
}
+ @Override
public void clearForcedDisplayDensity(int displayId) {
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
- setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_DENSITY_FORCED, "");
+ if (displayContent != null) {
+ setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.DISPLAY_DENSITY_FORCED, "");
+ }
}
}
+ // displayContent must not be null
private void reconfigureDisplayLocked(DisplayContent displayContent) {
// TODO: Multidisplay: for now only use with default display.
mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
@@ -9711,7 +9749,9 @@
for (int i = 0; i < count; ++i) {
final DisplayContent displayContent =
getDisplayContentLocked(pendingLayouts.keyAt(i));
- displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
+ if (displayContent != null) {
+ displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
+ }
}
mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
@@ -10837,11 +10877,20 @@
mDisplayContents.put(display.getDisplayId(), displayContent);
}
+ /**
+ * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
+ * there is a Display for the displayId.
+ * @param displayId The display the caller is interested in.
+ * @return The DisplayContent associated with displayId or null if there is no Display for it.
+ */
public DisplayContent getDisplayContentLocked(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
- displayContent = new DisplayContent(mDisplayManager.getDisplay(displayId));
- mDisplayContents.put(displayId, displayContent);
+ final Display display = mDisplayManager.getDisplay(displayId);
+ if (display != null) {
+ displayContent = new DisplayContent(display);
+ mDisplayContents.put(displayId, displayContent);
+ }
}
return displayContent;
}
@@ -10927,6 +10976,7 @@
}
}
+ // There is an inherent assumption that this will never return null.
public DisplayContent getDefaultDisplayContentLocked() {
return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
}
@@ -10939,8 +10989,14 @@
return getDefaultDisplayContentLocked().getDisplayInfo();
}
+ /**
+ * Return the list of WindowStates associated on the passed display.
+ * @param display The screen to return windows from.
+ * @return The list of WindowStates on the screen, or null if the there is no screen.
+ */
public WindowList getWindowListLocked(final Display display) {
- return getDisplayContentLocked(display.getDisplayId()).getWindowList();
+ final DisplayContent displayContent = getDisplayContentLocked(display.getDisplayId());
+ return displayContent != null ? displayContent.getWindowList() : null;
}
@Override
@@ -10949,8 +11005,11 @@
}
private void handleDisplayAddedLocked(int displayId) {
- createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
- displayReady(displayId);
+ final Display display = mDisplayManager.getDisplay(displayId);
+ if (display != null) {
+ createDisplayContentLocked(display);
+ displayReady(displayId);
+ }
}
@Override
@@ -10960,11 +11019,13 @@
private void handleDisplayRemovedLocked(int displayId) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
- mDisplayContents.delete(displayId);
- WindowList windows = displayContent.getWindowList();
- while (!windows.isEmpty()) {
- final WindowState win = windows.get(windows.size() - 1);
- removeWindowLocked(win.mSession, win);
+ if (displayContent != null) {
+ mDisplayContents.delete(displayId);
+ WindowList windows = displayContent.getWindowList();
+ while (!windows.isEmpty()) {
+ final WindowState win = windows.get(windows.size() - 1);
+ removeWindowLocked(win.mSession, win);
+ }
}
mAnimator.removeDisplayLocked(displayId);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index a235ec3..803849f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -21,9 +21,12 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.InputStream;
/**
@@ -38,14 +41,21 @@
public static XmlPullParser create(File f)
throws XmlPullParserException, FileNotFoundException {
- KXmlParser parser = instantiateParser(f.getName());
- parser.setInput(new FileInputStream(f), ENCODING);
- return parser;
+ InputStream stream = new FileInputStream(f);
+ return create(stream, f.getName(), f.length());
}
public static XmlPullParser create(InputStream stream, String name)
+ throws XmlPullParserException {
+ return create(stream, name, -1);
+ }
+
+ private static XmlPullParser create(InputStream stream, String name, long size)
throws XmlPullParserException {
KXmlParser parser = instantiateParser(name);
+
+ stream = readAndClose(stream, name, size);
+
parser.setInput(stream, ENCODING);
return parser;
}
@@ -61,6 +71,61 @@
return parser;
}
+ private static InputStream readAndClose(InputStream stream, String name, long size)
+ throws XmlPullParserException {
+ // just a sanity check. It's doubtful we'll have such big files!
+ if (size > Integer.MAX_VALUE) {
+ throw new XmlPullParserException("File " + name + " is too big to be parsed");
+ }
+ int intSize = (int) size;
+
+ // create a buffered reader to facilitate reading.
+ BufferedInputStream bufferedStream = new BufferedInputStream(stream);
+ try {
+ int avail;
+ if (intSize != -1) {
+ avail = intSize;
+ } else {
+ // get the size to read.
+ avail = bufferedStream.available();
+ }
+
+ // create the initial buffer and read it.
+ byte[] buffer = new byte[avail];
+ int read = stream.read(buffer);
+
+ // this is the easy case.
+ if (read == intSize) {
+ return new ByteArrayInputStream(buffer);
+ }
+
+ // check if there is more to read (read() does not necessarily read all that
+ // available() returned!)
+ while ((avail = bufferedStream.available()) > 0) {
+ if (read + avail > buffer.length) {
+ // just allocate what is needed. We're mostly reading small files
+ // so it shouldn't be too problematic.
+ byte[] moreBuffer = new byte[read + avail];
+ System.arraycopy(buffer, 0, moreBuffer, 0, read);
+ buffer = moreBuffer;
+ }
+
+ read += stream.read(buffer, read, avail);
+ }
+
+ // return a new stream encapsulating this buffer.
+ return new ByteArrayInputStream(buffer);
+
+ } catch (IOException e) {
+ throw new XmlPullParserException("Failed to read " + name, null, e);
+ } finally {
+ try {
+ bufferedStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
private static class CustomParser extends KXmlParser {
private final String mName;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 196bf2e..fd76fc8d 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -359,8 +359,12 @@
static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111;
/* P2p commands */
+ /* We are ok with no response here since we wont do much with it anyway */
public static final int CMD_ENABLE_P2P = BASE + 131;
- public static final int CMD_DISABLE_P2P = BASE + 132;
+ /* In order to shut down supplicant cleanly, we wait till p2p has
+ * been disabled */
+ public static final int CMD_DISABLE_P2P_REQ = BASE + 132;
+ public static final int CMD_DISABLE_P2P_RSP = BASE + 133;
private static final int CONNECT_MODE = 1;
private static final int SCAN_ONLY_MODE = 2;
@@ -458,6 +462,11 @@
private State mDriverStartingState = new DriverStartingState();
/* Driver started */
private State mDriverStartedState = new DriverStartedState();
+ /* Wait until p2p is disabled
+ * This is a special state which is entered right after we exit out of DriverStartedState
+ * before transitioning to another state.
+ */
+ private State mWaitForP2pDisableState = new WaitForP2pDisableState();
/* Driver stopping */
private State mDriverStoppingState = new DriverStoppingState();
/* Driver stopped */
@@ -699,6 +708,7 @@
addState(mDisconnectingState, mConnectModeState);
addState(mDisconnectedState, mConnectModeState);
addState(mWpsRunningState, mConnectModeState);
+ addState(mWaitForP2pDisableState, mSupplicantStartedState);
addState(mDriverStoppingState, mSupplicantStartedState);
addState(mDriverStoppedState, mSupplicantStartedState);
addState(mSupplicantStoppingState, mDefaultState);
@@ -2433,7 +2443,11 @@
WifiConfiguration config;
switch(message.what) {
case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
- transitionTo(mSupplicantStoppingState);
+ if (mP2pSupported) {
+ transitionTo(mWaitForP2pDisableState);
+ } else {
+ transitionTo(mSupplicantStoppingState);
+ }
break;
case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
loge("Connection lost, restart supplicant");
@@ -2443,7 +2457,11 @@
handleNetworkDisconnect();
sendSupplicantConnectionChangedBroadcast(false);
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
- transitionTo(mDriverLoadedState);
+ if (mP2pSupported) {
+ transitionTo(mWaitForP2pDisableState);
+ } else {
+ transitionTo(mDriverLoadedState);
+ }
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
break;
case WifiMonitor.SCAN_RESULTS_EVENT:
@@ -2838,8 +2856,12 @@
}
mWakeLock.acquire();
mWifiNative.stopDriver();
- transitionTo(mDriverStoppingState);
mWakeLock.release();
+ if (mP2pSupported) {
+ transitionTo(mWaitForP2pDisableState);
+ } else {
+ transitionTo(mDriverStoppingState);
+ }
break;
case CMD_START_PACKET_FILTERING:
if (message.arg1 == MULTICAST_V6) {
@@ -2885,8 +2907,63 @@
mIsRunning = false;
updateBatteryWorkSource(null);
mScanResults = new ArrayList<ScanResult>();
+ }
+ }
- if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
+ class WaitForP2pDisableState extends State {
+ private State mTransitionToState;
+ @Override
+ public void enter() {
+ if (DBG) log(getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ switch (getCurrentMessage().what) {
+ case WifiMonitor.SUP_DISCONNECTION_EVENT:
+ mTransitionToState = mDriverLoadedState;
+ break;
+ case CMD_DELAYED_STOP_DRIVER:
+ mTransitionToState = mDriverStoppingState;
+ break;
+ case CMD_STOP_SUPPLICANT:
+ mTransitionToState = mSupplicantStoppingState;
+ break;
+ default:
+ mTransitionToState = mDriverStoppingState;
+ break;
+ }
+ mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString() + "\n");
+ switch(message.what) {
+ case WifiStateMachine.CMD_DISABLE_P2P_RSP:
+ transitionTo(mTransitionToState);
+ break;
+ /* Defer wifi start/shut and driver commands */
+ case CMD_LOAD_DRIVER:
+ case CMD_UNLOAD_DRIVER:
+ case CMD_START_SUPPLICANT:
+ case CMD_STOP_SUPPLICANT:
+ case CMD_START_AP:
+ case CMD_STOP_AP:
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case CMD_SET_SCAN_MODE:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_COUNTRY_CODE:
+ case CMD_SET_FREQUENCY_BAND:
+ case CMD_START_PACKET_FILTERING:
+ case CMD_STOP_PACKET_FILTERING:
+ case CMD_START_SCAN:
+ case CMD_DISCONNECT:
+ case CMD_REASSOCIATE:
+ case CMD_RECONNECT:
+ deferMessage(message);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
}
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 4b90901..f0aef92 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -134,6 +134,9 @@
private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
private static int mGroupCreatingTimeoutIndex = 0;
+ private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
+ private static int mDisableP2pTimeoutIndex = 0;
+
/* Set a two minute discover timeout to avoid STA scans from being blocked */
private static final int DISCOVER_TIMEOUT_S = 120;
@@ -153,6 +156,8 @@
private static final int DROP_WIFI_USER_ACCEPT = BASE + 4;
/* User wants to keep his wifi connection and drop p2p */
private static final int DROP_WIFI_USER_REJECT = BASE + 5;
+ /* Delayed message to timeout p2p disable */
+ public static final int DISABLE_P2P_TIMED_OUT = BASE + 6;
/* Commands to the WifiStateMachine */
@@ -574,19 +579,25 @@
case WifiMonitor.P2P_DEVICE_LOST_EVENT:
case WifiMonitor.P2P_FIND_STOPPED_EVENT:
case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
- case WifiStateMachine.CMD_ENABLE_P2P:
- case WifiStateMachine.CMD_DISABLE_P2P:
case PEER_CONNECTION_USER_ACCEPT:
case PEER_CONNECTION_USER_REJECT:
case DISCONNECT_WIFI_RESPONSE:
case DROP_WIFI_USER_ACCEPT:
case DROP_WIFI_USER_REJECT:
case GROUP_CREATING_TIMED_OUT:
+ case DISABLE_P2P_TIMED_OUT:
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
case DhcpStateMachine.CMD_POST_DHCP_ACTION:
case DhcpStateMachine.CMD_ON_QUIT:
case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
break;
+ case WifiStateMachine.CMD_ENABLE_P2P:
+ // Enable is lazy and has no response
+ break;
+ case WifiStateMachine.CMD_DISABLE_P2P_REQ:
+ // If we end up handling in default, p2p is not enabled
+ mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
+ break;
/* unexpected group created, remove */
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
@@ -689,6 +700,13 @@
class P2pDisablingState extends State {
@Override
+ public void enter() {
+ if (DBG) logd(getName());
+ sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
+ ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
+ }
+
+ @Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
@@ -697,14 +715,25 @@
transitionTo(mP2pDisabledState);
break;
case WifiStateMachine.CMD_ENABLE_P2P:
- case WifiStateMachine.CMD_DISABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P_REQ:
deferMessage(message);
break;
+ case DISABLE_P2P_TIMED_OUT:
+ if (mGroupCreatingTimeoutIndex == message.arg1) {
+ loge("P2p disable timed out");
+ transitionTo(mP2pDisabledState);
+ }
+ break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
+
+ @Override
+ public void exit() {
+ mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
+ }
}
class P2pDisabledState extends State {
@@ -728,9 +757,6 @@
mWifiMonitor.startMonitoring();
transitionTo(mP2pEnablingState);
break;
- case WifiStateMachine.CMD_DISABLE_P2P:
- //Nothing to do
- break;
default:
return NOT_HANDLED;
}
@@ -757,7 +783,7 @@
transitionTo(mP2pDisabledState);
break;
case WifiStateMachine.CMD_ENABLE_P2P:
- case WifiStateMachine.CMD_DISABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P_REQ:
deferMessage(message);
break;
default:
@@ -788,7 +814,7 @@
case WifiStateMachine.CMD_ENABLE_P2P:
//Nothing to do
break;
- case WifiStateMachine.CMD_DISABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P_REQ:
if (mPeers.clear()) sendP2pPeersChangedBroadcast();
if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
@@ -1439,6 +1465,12 @@
if (mGroup.isGroupOwner()) {
setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
}
+
+ // In case of a negotiation group, connection changed is sent
+ // after a client joins. For autonomous, send now
+ if (mAutonomousGroup) {
+ sendP2pConnectionChangedBroadcast();
+ }
}
@Override
@@ -1453,7 +1485,11 @@
deviceAddress.equals(mSavedProvDiscDevice.deviceAddress)) {
mSavedProvDiscDevice = null;
}
- mGroup.addClient(mPeers.get(deviceAddress));
+ if (mPeers.get(deviceAddress) != null) {
+ mGroup.addClient(mPeers.get(deviceAddress));
+ } else {
+ mGroup.addClient(deviceAddress);
+ }
mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
if (DBG) logd(getName() + " ap sta connected");
sendP2pPeersChangedBroadcast();
@@ -1534,7 +1570,7 @@
}
// Do the regular device lost handling
return NOT_HANDLED;
- case WifiStateMachine.CMD_DISABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P_REQ:
sendMessage(WifiP2pManager.REMOVE_GROUP);
deferMessage(message);
break;