Merge "Keep selection handles in edit fields."
diff --git a/Android.mk b/Android.mk
index 9c51fc6..cacdee9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -132,6 +132,8 @@
core/java/android/os/IRemoteCallback.aidl \
core/java/android/os/IUpdateLock.aidl \
core/java/android/os/IVibratorService.aidl \
+ core/java/android/service/dreams/IDreamManager.aidl \
+ core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
core/java/android/service/wallpaper/IWallpaperEngine.aidl \
core/java/android/service/wallpaper/IWallpaperService.aidl \
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 415d58a..85f7aa5 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -154,7 +154,7 @@
/**
* Flag for {@link #requestedPermissionsFlags}: the requested permission
* is required for the application to run; the user can not optionally
- * disable it.
+ * disable it. Currently all permissions are required.
*/
public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 7571993..b6ebbdf 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -989,14 +989,16 @@
// that may change.
String name = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
+ /* Not supporting optional permissions yet.
boolean required = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
+ */
sa.recycle();
if (name != null && !pkg.requestedPermissions.contains(name)) {
pkg.requestedPermissions.add(name.intern());
- pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+ pkg.requestedPermissionsRequired.add(Boolean.TRUE);
}
XmlUtils.skipCurrentTag(parser);
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
new file mode 100644
index 0000000..83464c9
--- /dev/null
+++ b/core/java/android/service/dreams/Dream.java
@@ -0,0 +1,392 @@
+/**
+ *
+ */
+package android.service.dreams;
+
+import com.android.internal.policy.PolicyManager;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import android.view.ActionMode;
+import android.view.IWindowManager;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager.LayoutParams;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+/**
+ * @hide
+ *
+ */
+public class Dream extends Service implements Window.Callback {
+ private final static boolean DEBUG = true;
+ private final static String TAG = "Dream";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_WALLPAPER} permission so
+ * that other applications can not abuse it.
+ */
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.service.dreams.Dream";
+
+ private Window mWindow;
+
+ private WindowManager mWindowManager;
+ private IDreamManager mSandman;
+
+ private boolean mInteractive;
+
+ final Handler mHandler = new Handler();
+
+ boolean mFinished = false;
+
+ // begin Window.Callback methods
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (!mInteractive) {
+ finish();
+ return true;
+ }
+ return mWindow.superDispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ if (!mInteractive) {
+ finish();
+ return true;
+ }
+ return mWindow.superDispatchKeyShortcutEvent(event);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (!mInteractive) {
+ finish();
+ return true;
+ }
+ return mWindow.superDispatchTouchEvent(event);
+ }
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent event) {
+ if (!mInteractive) {
+ finish();
+ return true;
+ }
+ return mWindow.superDispatchTrackballEvent(event);
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if (!mInteractive) {
+ finish();
+ return true;
+ }
+ return mWindow.superDispatchGenericMotionEvent(event);
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ return false;
+ }
+
+ @Override
+ public View onCreatePanelView(int featureId) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreatePanelMenu(int featureId, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onPreparePanel(int featureId, View view, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onMenuOpened(int featureId, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public void onWindowAttributesChanged(LayoutParams attrs) {
+
+ }
+
+ @Override
+ public void onContentChanged() {
+
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ mWindow.addFlags(
+ WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ );
+ lightsOut();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ }
+
+ @Override
+ public void onPanelClosed(int featureId, Menu menu) {
+ }
+
+ @Override
+ public boolean onSearchRequested() {
+ return false;
+ }
+
+ @Override
+ public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) {
+ return null;
+ }
+
+ @Override
+ public void onActionModeStarted(ActionMode mode) {
+ }
+
+ @Override
+ public void onActionModeFinished(ActionMode mode) {
+ }
+ // end Window.Callback methods
+
+ public WindowManager getWindowManager() {
+ return mWindowManager;
+ }
+
+ public Window getWindow() {
+ return mWindow;
+ }
+
+ /**
+ * Called when this Dream is constructed. Place your initialization here.
+ *
+ * Subclasses must call through to the superclass implementation.
+ */
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ if (DEBUG) Slog.v(TAG, "Dream created on thread " + Thread.currentThread().getId());
+
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
+ }
+
+ /**
+ * Called when this Dream is started. Place your initialization here.
+ *
+ * Subclasses must call through to the superclass implementation.
+ *
+ * XXX(dsandler) Might want to make this final and have a different method for clients to override
+ */
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ /**
+ * Inflate a layout resource and set it to be the content view for this Dream.
+ * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
+ *
+ * @param layoutResID Resource ID to be inflated.
+ *
+ * @see #setContentView(android.view.View)
+ * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
+ */
+ public void setContentView(int layoutResID) {
+ getWindow().setContentView(layoutResID);
+ }
+
+ /**
+ * Set a view to be the content view for this Dream.
+ * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
+ * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
+ *
+ * @param view The desired content to display.
+ *
+ * @see #setContentView(int)
+ * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
+ */
+ public void setContentView(View view) {
+ getWindow().setContentView(view);
+ }
+
+ /**
+ * Set 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)}.
+ *
+ * @param view The desired content to display.
+ * @param params Layout parameters for the view.
+ *
+ * @see #setContentView(android.view.View)
+ * @see #setContentView(int)
+ */
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ getWindow().setContentView(view, params);
+ }
+
+ /**
+ * Add a view to the Dream's window, leaving other content views in place.
+ *
+ * @param view The desired content to display.
+ * @param params Layout parameters for the view.
+ */
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ getWindow().addContentView(view, params);
+ }
+
+ /**
+ * @param mInteractive the mInteractive to set
+ */
+ public void setInteractive(boolean mInteractive) {
+ this.mInteractive = mInteractive;
+ }
+
+ /**
+ * @return the mInteractive
+ */
+ public boolean isInteractive() {
+ return mInteractive;
+ }
+
+ /** Convenience method for setting View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. */
+ protected void lightsOut() {
+ // turn the lights down low
+ final View v = mWindow.getDecorView();
+ if (v != null) {
+ v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ }
+ }
+
+ /**
+ * Finds a view that was identified by the id attribute from the XML that
+ * was processed in {@link #onCreate}.
+ *
+ * @return The view if found or null otherwise.
+ */
+ public View findViewById(int id) {
+ return getWindow().findViewById(id);
+ }
+
+ /**
+ * Called when this Dream is being removed from the screen and stopped.
+ */
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mWindowManager.removeView(mWindow.getDecorView());
+ }
+
+ /**
+ * Creates a new dream window, attaches the current content view, and shows it.
+ *
+ * @param windowToken Binder to attach to the window to allow access to the correct window type.
+ * @hide
+ */
+ final /*package*/ void attach(IBinder windowToken) {
+ if (DEBUG) Slog.v(TAG, "Dream attached on thread " + Thread.currentThread().getId());
+
+ mWindow = PolicyManager.makeNewWindow(this);
+ mWindow.setCallback(this);
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+ mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
+
+ if (DEBUG) Slog.v(TAG, "attaching window token: " + windowToken
+ + " to window of type " + WindowManager.LayoutParams.TYPE_DREAM);
+
+ WindowManager.LayoutParams lp = mWindow.getAttributes();
+ lp.type = WindowManager.LayoutParams.TYPE_DREAM;
+ lp.token = windowToken;
+ lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
+
+ //WindowManagerImpl.getDefault().addView(mWindow.getDecorView(), lp);
+
+ if (DEBUG) Slog.v(TAG, "created and attached window: " + mWindow);
+
+ mWindow.setWindowManager(null, windowToken, "dream", true);
+ mWindowManager = mWindow.getWindowManager();
+
+ // now make it visible
+ mHandler.post(new Runnable(){
+ @Override
+ public void run() {
+ if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId());
+
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ }});
+ }
+
+ /**
+ * Stop the dream and wake up.
+ *
+ * After this method is called, the service will be stopped.
+ */
+ public void finish() {
+ if (mFinished) return;
+ try {
+ mSandman.awaken(); // assuming we were started by the DreamManager
+ stopSelf(); // if launched via any other means
+ mFinished = true;
+ } catch (RemoteException ex) {
+ // sigh
+ }
+ }
+
+ class IDreamServiceWrapper extends IDreamService.Stub {
+ public IDreamServiceWrapper() {
+ }
+
+ public void attach(IBinder windowToken) {
+ Dream.this.attach(windowToken);
+ }
+ }
+
+ /**
+ * Implement to return the implementation of the internal accessibility
+ * service interface. Subclasses should not override.
+ */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IDreamServiceWrapper();
+ }
+}
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
new file mode 100644
index 0000000..8712fa2
--- /dev/null
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -0,0 +1,182 @@
+package android.service.dreams;
+
+import static android.provider.Settings.Secure.SCREENSAVER_COMPONENT;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import com.android.internal.view.IInputMethod;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+
+/**
+ *
+ * @hide
+ *
+ */
+
+public class DreamManagerService
+ extends IDreamManager.Stub
+ implements ServiceConnection
+{
+ private static final boolean DEBUG = true;
+ private static final String TAG = "DreamManagerService";
+
+ final Object mLock = new Object[0];
+
+ private Context mContext;
+ private IWindowManager mIWindowManager;
+
+ private ComponentName mCurrentDreamComponent;
+ private IDreamService mCurrentDream;
+ private Binder mCurrentDreamToken;
+
+ public DreamManagerService(Context context) {
+ if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
+ mContext = context;
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ }
+
+ private void checkPermission(String permission) {
+ if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
+ }
+ }
+
+ // IDreamManager method
+ public void dream() {
+ ComponentName name = getDreamComponent();
+ if (name != null) {
+ synchronized (mLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindDreamComponentL(name, false);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+ }
+
+ // IDreamManager method
+ public void setDreamComponent(ComponentName name) {
+ Settings.Secure.putString(mContext.getContentResolver(), SCREENSAVER_COMPONENT, name.flattenToString());
+ }
+
+ // IDreamManager method
+ public ComponentName getDreamComponent() {
+ // TODO(dsandler) don't load this every time, watch the value
+ String component = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENT);
+ if (component == null) {
+ component = mContext.getResources().getString(
+ com.android.internal.R.string.config_defaultDreamComponent);
+ }
+ if (component != null) {
+ return ComponentName.unflattenFromString(component);
+ } else {
+ return null;
+ }
+ }
+
+ // IDreamManager method
+ public void testDream(ComponentName name) {
+ if (DEBUG) Slog.v(TAG, "startDream name=" + name
+ + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+// checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
+ synchronized (mLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindDreamComponentL(name, true);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ // IDreamManager method
+ public void awaken() {
+ if (DEBUG) Slog.v(TAG, "awaken()");
+ synchronized (mLock) {
+ if (mCurrentDream != null) {
+ mContext.unbindService(this);
+ }
+ }
+ }
+
+ public void bindDreamComponentL(ComponentName componentName, boolean test) {
+ if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName
+ + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+
+ Intent intent = new Intent(Intent.ACTION_MAIN)
+ .setComponent(componentName)
+ .addFlags(
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ )
+ .putExtra("android.dreams.TEST", test);
+
+ if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+ Slog.w(TAG, "unable to bind service: " + componentName);
+ return;
+ }
+ mCurrentDreamComponent = componentName;
+ mCurrentDreamToken = new Binder();
+ try {
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
+ + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
+ mIWindowManager.addWindowToken(mCurrentDreamToken,
+ WindowManager.LayoutParams.TYPE_DREAM);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to add window token. Proceed at your own risk.");
+ }
+
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Slog.v(TAG, "connected to dream: " + name + " binder=" + service + " thread=" + Thread.currentThread().getId());
+
+ mCurrentDream = IDreamService.Stub.asInterface(service);
+ try {
+ if (DEBUG) Slog.v(TAG, "attaching with token:" + mCurrentDreamToken);
+ mCurrentDream.attach(mCurrentDreamToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Unable to send window token to dream:" + ex);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream);
+ mCurrentDream = null;
+ mCurrentDreamToken = null;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Dreamland:");
+ pw.print(" component="); pw.println(mCurrentDreamComponent);
+ pw.print(" token="); pw.println(mCurrentDreamToken);
+ pw.print(" dream="); pw.println(mCurrentDream);
+ }
+
+ public void systemReady() {
+ if (DEBUG) Slog.v(TAG, "ready to dream!");
+ }
+
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
new file mode 100644
index 0000000..7225013
--- /dev/null
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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 android.service.dreams;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.content.ComponentName;
+
+/** @hide */
+interface IDreamManager {
+ void dream();
+ void awaken();
+ void setDreamComponent(in ComponentName componentName);
+ ComponentName getDreamComponent();
+ void testDream(in ComponentName componentName);
+}
\ No newline at end of file
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
new file mode 100644
index 0000000..1bb241a
--- /dev/null
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 android.service.dreams;
+
+/**
+ * @hide
+ */
+oneway interface IDreamService {
+ void attach(IBinder windowToken);
+}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index ae9042c..0f8efd1 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -50,6 +50,8 @@
public SpannableStringBuilder(CharSequence text, int start, int end) {
int srclen = end - start;
+ if (srclen < 0) throw new StringIndexOutOfBoundsException();
+
int len = ArrayUtils.idealCharArraySize(srclen + 1);
mText = new char[len];
mGapStart = srclen;
@@ -87,7 +89,7 @@
if (en > end - start)
en = end - start;
- setSpan(spans[i], st, en, fl);
+ setSpan(false, spans[i], st, en, fl);
}
}
}
@@ -149,7 +151,7 @@
if (where == mGapStart)
return;
- boolean atend = (where == length());
+ boolean atEnd = (where == length());
if (where < mGapStart) {
int overlap = mGapStart - where;
@@ -171,7 +173,7 @@
else if (start == where) {
int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
- if (flag == POINT || (atend && flag == PARAGRAPH))
+ if (flag == POINT || (atEnd && flag == PARAGRAPH))
start += mGapLength;
}
@@ -182,7 +184,7 @@
else if (end == where) {
int flag = (mSpanFlags[i] & END_MASK);
- if (flag == POINT || (atend && flag == PARAGRAPH))
+ if (flag == POINT || (atEnd && flag == PARAGRAPH))
end += mGapLength;
}
@@ -284,7 +286,7 @@
}
if (st != ost || en != oen)
- setSpan(mSpans[i], st, en, mSpanFlags[i]);
+ setSpan(false, mSpans[i], st, en, mSpanFlags[i]);
}
}
@@ -305,28 +307,6 @@
TextUtils.getChars(tb, tbstart, tbend, mText, start);
- if (tb instanceof Spanned) {
- Spanned sp = (Spanned) tb;
- Object[] spans = sp.getSpans(tbstart, tbend, Object.class);
-
- for (int i = 0; i < spans.length; i++) {
- int st = sp.getSpanStart(spans[i]);
- int en = sp.getSpanEnd(spans[i]);
-
- if (st < tbstart)
- st = tbstart;
- if (en > tbend)
- en = tbend;
-
- if (getSpanStart(spans[i]) < 0) {
- setSpan(false, spans[i],
- st - tbstart + start,
- en - tbstart + start,
- sp.getSpanFlags(spans[i]));
- }
- }
- }
-
if (end > start) {
// no need for span fixup on pure insertion
boolean atEnd = (mGapStart + mGapLength == mText.length);
@@ -358,6 +338,25 @@
}
}
}
+
+ if (tb instanceof Spanned) {
+ Spanned sp = (Spanned) tb;
+ Object[] spans = sp.getSpans(tbstart, tbend, Object.class);
+
+ for (int i = 0; i < spans.length; i++) {
+ int st = sp.getSpanStart(spans[i]);
+ int en = sp.getSpanEnd(spans[i]);
+
+ if (st < tbstart) st = tbstart;
+ if (en > tbend) en = tbend;
+
+ // Add span only if this object is not yet used as a span in this string
+ if (getSpanStart(spans[i]) < 0) {
+ setSpan(false, spans[i], st - tbstart + start, en - tbstart + start,
+ sp.getSpanFlags(spans[i]));
+ }
+ }
+ }
}
private void removeSpan(int i) {
@@ -389,7 +388,7 @@
// Documentation from interface
public SpannableStringBuilder replace(final int start, final int end,
- CharSequence tb, int tbstart, int tbend) {
+ CharSequence tb, int tbstart, int tbend) {
int filtercount = mFilters.length;
for (int i = 0; i < filtercount; i++) {
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -411,53 +410,26 @@
TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
sendBeforeTextChanged(textWatchers, start, origLen, newLen);
- if (origLen == 0 || newLen == 0) {
- change(start, end, tb, tbstart, tbend);
- } else {
- int selstart = Selection.getSelectionStart(this);
- int selend = Selection.getSelectionEnd(this);
+ // Try to keep the cursor / selection at the same relative position during
+ // a text replacement. If replaced or replacement text length is zero, this
+ // is already taken care of.
+ boolean adjustSelection = origLen != 0 && newLen != 0;
+ int selstart = 0;
+ int selend = 0;
+ if (adjustSelection) {
+ selstart = Selection.getSelectionStart(this);
+ selend = Selection.getSelectionEnd(this);
+ }
- // XXX just make the span fixups in change() do the right thing
- // instead of this madness!
+ checkRange("replace", start, end);
- checkRange("replace", start, end);
- moveGapTo(end);
+ change(start, end, tb, tbstart, tbend);
- if (mGapLength < 2)
- resizeFor(length() + 1);
-
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpanStarts[i] == mGapStart)
- mSpanStarts[i]++;
-
- if (mSpanEnds[i] == mGapStart)
- mSpanEnds[i]++;
- }
-
- mText[mGapStart] = ' ';
- mGapStart++;
- mGapLength--;
-
- if (mGapLength < 1) {
- new Exception("mGapLength < 1").printStackTrace();
- }
-
- change(start + 1, start + 1, tb, tbstart, tbend);
- change(start, start + 1, "", 0, 0);
- change(start + newLen, start + newLen + origLen, "", 0, 0);
-
- /*
- * Special case to keep the cursor in the same position
- * if it was somewhere in the middle of the replaced region.
- * If it was at the start or the end or crossing the whole
- * replacement, it should already be where it belongs.
- * TODO: Is there some more general mechanism that could
- * accomplish this?
- */
+ if (adjustSelection) {
if (selstart > start && selstart < end) {
long off = selstart - start;
- off = off * newLen / (end - start);
+ off = off * newLen / origLen;
selstart = (int) off + start;
setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -466,7 +438,7 @@
if (selend > start && selend < end) {
long off = selend - start;
- off = off * newLen / (end - start);
+ off = off * newLen / origLen;
selend = (int) off + start;
setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
@@ -489,12 +461,10 @@
}
private void setSpan(boolean send, Object what, int start, int end, int flags) {
- int nstart = start;
- int nend = end;
-
checkRange("setSpan", start, end);
- if ((flags & START_MASK) == (PARAGRAPH << START_SHIFT)) {
+ int flagsStart = (flags & START_MASK) >> START_SHIFT;
+ if (flagsStart == PARAGRAPH) {
if (start != 0 && start != length()) {
char c = charAt(start - 1);
@@ -503,7 +473,8 @@
}
}
- if ((flags & END_MASK) == PARAGRAPH) {
+ int flagsEnd = flags & END_MASK;
+ if (flagsEnd == PARAGRAPH) {
if (end != 0 && end != length()) {
char c = charAt(end - 1);
@@ -512,26 +483,33 @@
}
}
- if (flags == Spanned.SPAN_EXCLUSIVE_EXCLUSIVE && start == end) {
- throw new IllegalArgumentException(
- "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+ // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ if (flagsStart == POINT && flagsEnd == MARK && start == end) {
+ if (send) {
+ throw new IllegalArgumentException(
+ "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+ } else {
+ // Silently ignore invalid spans when they are created from this class.
+ // This avoids the duplication of the above test code before all the
+ // calls to setSpan that are done in this class
+ return;
+ }
}
+ int nstart = start;
+ int nend = end;
+
if (start > mGapStart) {
start += mGapLength;
} else if (start == mGapStart) {
- int flag = (flags & START_MASK) >> START_SHIFT;
-
- if (flag == POINT || (flag == PARAGRAPH && start == length()))
+ if (flagsStart == POINT || (flagsStart == PARAGRAPH && start == length()))
start += mGapLength;
}
if (end > mGapStart) {
end += mGapLength;
} else if (end == mGapStart) {
- int flag = (flags & END_MASK);
-
- if (flag == POINT || (flag == PARAGRAPH && end == length()))
+ if (flagsEnd == POINT || (flagsEnd == PARAGRAPH && end == length()))
end += mGapLength;
}
@@ -1231,6 +1209,7 @@
private int mSpanCount;
// TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
+ private static final int MARK = 1;
private static final int POINT = 2;
private static final int PARAGRAPH = 3;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b0399fd..aa0ac74 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1394,6 +1394,11 @@
destroyResources(view);
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+
+ if (needsContext) {
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
}
}
@@ -1434,6 +1439,9 @@
} else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
}
+
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
}
private static void usePbufferSurface(EGLContext eglContext) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f3ef329..bc310b0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -423,6 +423,12 @@
public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
/**
+ * Window type: Dreams (screen saver) window, just above keyguard.
+ * @hide
+ */
+ public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 491cd67..66bdc5d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1049,6 +1049,31 @@
public void lockNow();
/**
+ * Check to see if a screensaver should be run instead of powering off the screen on timeout.
+ *
+ * @return true if the screensaver should run, false if the screen should turn off.
+ *
+ * @hide
+ */
+ public boolean isScreenSaverEnabled();
+
+ /**
+ * Start the screensaver (if it is enabled and not yet running).
+ *
+ * @return Whether the screensaver was successfully started.
+ *
+ * @hide
+ */
+ public boolean startScreenSaver();
+
+ /**
+ * Stop the screensaver if it is running.
+ *
+ * @hide
+ */
+ public void stopScreenSaver();
+
+ /**
* Print the WindowManagerPolicy's state into the given stream.
*
* @param prefix Text to print at the front of each line.
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index ab6ac1d..f496c4e 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -461,6 +461,7 @@
selectionStart = Math.min(selectionStart, editable.length());
selectionEnd = Math.min(selectionEnd, editable.length());
setSelection(selectionStart, selectionEnd);
+ finishComposingText();
}
public void replaceSelection(CharSequence text) {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index e6184d5..b409e26 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -490,13 +490,7 @@
// Development permissions are only shown to the user if they are already
// granted to the app -- if we are installing an app and they are not
// already granted, they will not be granted as part of the install.
- // Note we also need the app to have specified this permission is not
- // required -- this is not technically needed, but it helps various things
- // if we ensure apps always mark development permissions as option, so that
- // even not knowing what a permission is we can still know whether it will
- // be granted to the app when it is installed.
if ((existingReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
- && (newReqFlags&PackageInfo.REQUESTED_PERMISSION_REQUIRED) == 0
&& (pInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
return true;
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 9afaee3..c725b64 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -227,8 +227,7 @@
for (int i = 0; i < length; i++) {
final SpellParser spellParser = mSpellParsers[i];
if (spellParser.isFinished()) {
- spellParser.init(start, end);
- spellParser.parse();
+ spellParser.parse(start, end);
return;
}
}
@@ -240,8 +239,7 @@
SpellParser spellParser = new SpellParser();
mSpellParsers[length] = spellParser;
- spellParser.init(start, end);
- spellParser.parse();
+ spellParser.parse(start, end);
}
private void spellCheck() {
@@ -421,8 +419,11 @@
private class SpellParser {
private Object mRange = new Object();
- public void init(int start, int end) {
- setRangeSpan((Editable) mTextView.getText(), start, end);
+ public void parse(int start, int end) {
+ if (end > start) {
+ setRangeSpan((Editable) mTextView.getText(), start, end);
+ parse();
+ }
}
public boolean isFinished() {
diff --git a/core/java/com/android/internal/policy/IFaceLockInterface.aidl b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
index 3958cda..017801b 100644
--- a/core/java/com/android/internal/policy/IFaceLockInterface.aidl
+++ b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
@@ -20,7 +20,8 @@
/** {@hide} */
interface IFaceLockInterface {
- void startUi(IBinder containingWindowToken, int x, int y, int width, int height);
+ void startUi(IBinder containingWindowToken, int x, int y, int width, int height,
+ boolean useLiveliness);
void stopUi();
void registerCallback(IFaceLockCallback cb);
void unregisterCallback(IFaceLockCallback cb);
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index e00fe9f..af67d55 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -340,8 +340,12 @@
final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
+ final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
+ (ActionMenuItemView) child : null;
+ final boolean hasText = itemView != null && itemView.hasText();
+
int cellsUsed = 0;
- if (cellsRemaining > 0) {
+ if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) {
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
cellSize * cellsRemaining, MeasureSpec.AT_MOST);
child.measure(childWidthSpec, childHeightSpec);
@@ -349,11 +353,10 @@
final int measuredWidth = child.getMeasuredWidth();
cellsUsed = measuredWidth / cellSize;
if (measuredWidth % cellSize != 0) cellsUsed++;
+ if (hasText && cellsUsed < 2) cellsUsed = 2;
}
- final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
- (ActionMenuItemView) child : null;
- final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText();
+ final boolean expandable = !lp.isOverflowButton && hasText;
lp.expandable = expandable;
lp.cellsUsed = cellsUsed;
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 5483867..9c6c7de 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -178,7 +178,7 @@
static jint jni_getInitCount(JNIEnv *_env, jobject _clazz, jobject display) {
EGLDisplay dpy = getDisplay(_env, display);
- egl_display_t* eglDisplay = get_display(dpy);
+ egl_display_t* eglDisplay = get_display_nowake(dpy);
return eglDisplay ? eglDisplay->getRefsCount() : 0;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 00faa41..3ee2377 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1082,7 +1082,7 @@
<!-- Configure an application for debugging. -->
<permission android:name="android.permission.SET_DEBUG_APP"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature|system|development"
android:label="@string/permlab_setDebugApp"
android:description="@string/permdesc_setDebugApp" />
@@ -1090,7 +1090,7 @@
application processes that can be running. -->
<permission android:name="android.permission.SET_PROCESS_LIMIT"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature|system|development"
android:label="@string/permlab_setProcessLimit"
android:description="@string/permdesc_setProcessLimit" />
@@ -1098,14 +1098,14 @@
finished when put in the background. -->
<permission android:name="android.permission.SET_ALWAYS_FINISH"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature|system|development"
android:label="@string/permlab_setAlwaysFinish"
android:description="@string/permdesc_setAlwaysFinish" />
<!-- Allow an application to request that a signal be sent to all persistent processes -->
<permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature|system|development"
android:label="@string/permlab_signalPersistentProcesses"
android:description="@string/permdesc_signalPersistentProcesses" />
diff --git a/core/res/res/anim/slow_fade_in.xml b/core/res/res/anim/slow_fade_in.xml
new file mode 100644
index 0000000..21a2c78
--- /dev/null
+++ b/core/res/res/anim/slow_fade_in.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_in.xml
+**
+** 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.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@interpolator/decelerate_quad"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="1000" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d414c7f..0ac2ad74 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -948,8 +948,9 @@
permission, and it must always be granted when it is installed.
If you set this to false, then in some cases the application may
be installed with it being granted the permission, and it will
- need to request the permission later if it needs it. -->
+ need to request the permission later if it needs it.
<attr name="required" format="boolean" />
+ -->
</declare-styleable>
<!-- The <code>uses-configuration</code> tag specifies
@@ -992,7 +993,7 @@
don't support it. If you set this to false, then this will
not impose a restriction on where the application can be
installed. -->
- <attr name="required" />
+ <attr name="required" format="boolean" />
</declare-styleable>
<!-- The <code>uses-sdk</code> tag describes the SDK features that the
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4fde018..e80e30a 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -837,6 +837,8 @@
<!-- Name of the wimax state tracker clas -->
<string name="config_wimaxStateTrackerClassname" translatable="false"></string>
+ <!-- enable screen saver feature -->
+ <bool name="config_enableDreams">false</bool>
<!-- Name of screensaver components to look for if none has been chosen by the user -->
<string name="config_defaultDreamComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ca0e913..cbfc1a4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1110,6 +1110,7 @@
<java-symbol type="style" name="Animation.PopupWindow" />
<java-symbol type="style" name="Animation.TypingFilter" />
<java-symbol type="style" name="Animation.TypingFilterRestore" />
+ <java-symbol type="style" name="Animation.Dream" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.Alert" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
<java-symbol type="style" name="Theme.Dialog.Alert" />
@@ -1262,7 +1263,6 @@
<java-symbol type="layout" name="screen_title_icons" />
<java-symbol type="string" name="abbrev_wday_month_day_no_year" />
<java-symbol type="string" name="android_upgrading_title" />
- <java-symbol type="string" name="config_defaultDreamComponent" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_action_power_off" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
@@ -1480,6 +1480,8 @@
<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="string" name="config_defaultDreamComponent" />
<!-- From SystemUI -->
<java-symbol type="anim" name="push_down_in" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index baeb9cc..18ee2f8 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -219,6 +219,12 @@
<item name="windowExitAnimation">@anim/fade_out</item>
</style>
+ <!-- Window animations for screen savers. {@hide} -->
+ <style name="Animation.Dream">
+ <item name="windowEnterAnimation">@anim/slow_fade_in</item>
+ <item name="windowExitAnimation">@anim/fast_fade_out</item>
+ </style>
+
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBar">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
@@ -1158,6 +1164,7 @@
<item name="android:minWidth">@android:dimen/action_button_min_width</item>
<item name="android:minHeight">?android:attr/actionBarSize</item>
<item name="android:gravity">center</item>
+ <item name="android:maxLines">2</item>
</style>
<style name="Widget.ActionButton.Overflow">
@@ -1861,6 +1868,7 @@
<item name="android:paddingLeft">12dip</item>
<item name="android:paddingRight">12dip</item>
<item name="android:scaleType">center</item>
+ <item name="android:maxLines">2</item>
</style>
<style name="Widget.Holo.ActionButton.Overflow">
diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd
new file mode 100644
index 0000000..49ea81d
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/index.jd
@@ -0,0 +1,49 @@
+page.title=Supporting Different Devices
+
+trainingnavtop=true
+startpage=true
+next.title=Supporting Multiple Languages
+next.link=languages.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 1.6 or higher</li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/resources/index.html">Application Resources</a></li>
+ <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>Android devices come in many shapes and sizes all around the world. With a wide range of device
+types, you have an opportunity to reach a huge audience with your app. In order to be as successful
+as possible on Android, your app needs to adapt to various device configurations. Some of the
+important variations that you should consider include different languages, screen sizes, and
+versions of the Android platform.</p>
+
+<p>This class teaches you how to use basic platform features that leverage alternative
+resources and other features so your app can provide an optimized user experience on a
+variety of Android-compatible devices, using a single application package (APK).</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt><b><a href="languages.html">Supporting Different Languages</a></b></dt>
+ <dd>Learn how to support multiple languages with alternative string resources.</dd>
+ <dt><b><a href="screens.html">Supporting Different Screens</a></b></dt>
+ <dd>Learn how to optimize the user experience for different screen sizes and densities.</dd>
+ <dt><b><a href="platforms.html">Supporting Different Platform Versions</a></b></dt>
+ <dd>Learn how to use APIs available in new versions of Android while continuing to support
+older versions of Android.</dd>
+</dl>
+
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
new file mode 100644
index 0000000..fcc95c2
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -0,0 +1,134 @@
+page.title=Supporting Different Languages
+parent.title=Supporting Different Devices
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Supporting Different Screens
+next.link=screens.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This class teaches you to</h2>
+ <ol>
+ <li><a href="#CreateDirs">Create Locale Directories and String Files</a></li>
+ <li><a href="#UseString">Use the String Resources</a></li>
+ </ol>
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/resources/localization.html">Localization</a></li>
+ </ul>
+ </div>
+</div>
+
+<p>It’s always a good practice to extract UI strings from your app code and keep them
+in an external file. Android makes this easy with a resources directory in each Android
+project.</p>
+
+<p>If you created your project using the Android SDK
+Tools (read <a href="{@docRoot}training/basics/firstapp/creating-project.html">Creating an
+Android Project</a>), the tools create a <code>res/</code> directory in the top level of
+the project. Within this <code>res/</code> directory are subdirectories for various resource
+types. There are also a few default files such as <code>res/values/strings.xml</code>, which holds
+your string values.</p>
+
+
+<h2 id="CreateDirs">Create Locale Directories and String Files</h2>
+
+<p>To add support for more languages, create additional <code>values</code> directories inside
+<code>res/</code> that include a hyphen and the ISO country code at the end of the
+directory name. For example, <code>values-es/</code> is the directory containing simple
+resourcess for the Locales with the language code "es". Android loads the appropriate resources
+according to the locale settings of the device at run time.</p>
+
+<p>Once you’ve decided on the languages you will support, create the resource subdirectories and
+string resource files. For example:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ values/
+ strings.xml
+ values-es/
+ strings.xml
+ values-fr/
+ strings.xml
+</pre>
+
+<p>Add the string values for each locale into the appropriate file.</p>
+
+<p>At runtime, the Android system uses the appropriate set of string resources based on the
+locale currently set for the user's device.</p>
+
+<p>For example, the following are some different string resource files for different languages.</p>
+
+
+<p>English (default locale), <code>/values/strings.xml</code>:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title">My Application</string>
+ <string name="hello_world">Hello World!</string>
+</resources>
+</pre>
+
+
+<p>Spanish, <code>/values-es/strings.xml</code>:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title">Mi Aplicación</string>
+ <string name="hello_world">Hola Mundo!</string>
+</resources>
+</pre>
+
+
+<p>French, <code>/values-fr/strings.xml</code>:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title">Ma Application</string>
+ <string name="hello_world">Bonjour tout le Monde!</string>
+</resources>
+</pre>
+
+
+<h2 id="UseString">Use the String Resources</h2>
+
+<p>You can reference your string resources in your source code and other XML files using the
+resource name defined by the {@code <string>} element's {@code name} attribute.</p>
+
+<p>In your source code, you can refer to a string resource with the syntax {@code
+R.string.<string_name>}. There are a variety of methods that accept a string resource this
+way.</p>
+
+<p>For example:</p>
+
+<pre>
+// Get a string resource from your app's {@link android.content.res.Resources}
+String hello = {@link android.content.Context#getResources()}.getString(R.string.hello_world);
+
+// Or supply a string resource to a method that requires a string
+TextView textView = new TextView(this);
+textView.setText(R.string.hello_world);
+</pre>
+
+<p>In other XML files, you can refer to a string resource with the syntax {@code
+@string/<string_name>} whenever the XML attribute accepts a string value.</p>
+
+<p>For example:</p>
+
+<pre>
+<TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hello_world" />
+</pre>
+
+
+
diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd
new file mode 100644
index 0000000..0d4e7d9
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/platforms.jd
@@ -0,0 +1,138 @@
+page.title=Supporting Different Platform Versions
+parent.title=Supporting Different Devices
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Supporting Different Screens
+previous.link=screens.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#sdk-versions">Specify Minimum and Target API Levels</a></li>
+ <li><a href="#version-codes">Check System Version at Runtime</a></li>
+ <li><a href="#style-themes">Use Platform Styles and Themes</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a></li>
+ <li><a
+href="{@docRoot}sdk/compatibility-library.html">Android Support Library</a></li>
+ </ul>
+ </div>
+</div>
+
+<p>While the latest versions of Android often provide great APIs for your app, you should continue
+to support older versions of Android until more devices get updated. This
+lesson shows you how to take advantage of the latest APIs while continuing to support older
+versions as well.</p>
+
+<p>The dashboard for <a
+href="http://developer.android.com/resources/dashboard/platform-versions.html">Platform Versions</a>
+is updated regularly to show the distribution of active
+devices running each version of Android, based on the number of devices that visit the Google Play
+Store. Generally, it’s a good practice to support about 90% of the active devices, while
+targeting your app to the latest version.</p>
+
+<p class="note"><strong>Tip:</strong> In order to provide the best features and
+functionality across several Android versions, you should use the <a
+href="{@docRoot}sdk/compatibility-library.html">Android Support Library</a> in your app,
+which allows you to use several recent platform APIs on older versions.</p>
+
+
+
+<h2 id="sdk-versions">Specify Minimum and Target API Levels</h2>
+
+<p>The <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a> file
+describes details about your app and
+identifies which versions of Android it supports. Specifically, the <code>minSdkVersion</code>
+and <code>targetSdkVersion</code> attributes for the <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code <uses-sdk}</a> element
+identify the lowest API level with which your app is compatible and the highest API level against
+which you’ve designed and tested your app.</p>
+
+<p>For example:</p>
+
+<pre>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />
+ ...
+</manifest>
+</pre>
+
+<p>As new versions of Android are released, some style and behaviors may change.
+To allow your app to take advantage of these changes and ensure that your app fits the style of
+each user's device, you should set the
+<a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+value to match the latest Android version
+available.</p>
+
+
+
+<h2 id="version-codes">Check System Version at Runtime</h2>
+
+<p>Android provides a unique code for each platform version in the {@link android.os.Build}
+constants class. Use these codes within your app to build conditions that ensure the code that
+depends on higher API levels is executed only when those APIs are available on the system.</p>
+
+<pre>
+private void setUpActionBar() {
+ // Make sure we're running on Honeycomb or higher to use ActionBar APIs
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+}
+</pre>
+
+
+
+<p class="note"><strong>Note:</strong> When parsing XML resources, Android ignores XML
+attributes that aren’t supported by the current device. So you can safely use XML attributes that
+are only supported by newer versions without worrying about older versions breaking when they
+encounter that code. For example, if you set the
+<code>targetSdkVersion="11"</code>, your app includes the {@link android.app.ActionBar} by default
+on Android 3.0 and higher. To then add menu items to the action bar, you need to set
+<code>android:showAsAction="ifRoom"</code> in your menu resource XML. It's safe to do this
+in a cross-version XML file, because the older versions of Android simply ignore the
+<code>showAsAction</code> attribute (that is, you <em>do not</em> need a separate
+version in <code>res/menu-v11/</code>).</p>
+
+
+
+<h2 id="style-themes">Use Platform Styles and Themes</h2>
+
+<p>Android provides user experience themes that give apps the look and feel of the
+underlying operating system. These themes can be applied to your app within the
+manifest file. By using these built in styles and themes, your app will
+naturally follow the latest look and feel of Android with each new release.</p>
+
+<p>To make your activity look like a dialog box:</p>
+
+<pre><activity android:theme="@android:style/Theme.Dialog"></pre>
+
+<p>To make your activity have a transparent background:</p>
+
+<pre><activity android:theme="@android:style/Theme.Translucent"></pre>
+
+<p>To apply your own custom theme defined in <code>/res/values/styles.xml</code>:</p>
+
+<pre><activity android:theme="@style/CustomTheme"></pre>
+
+<p>To apply a theme to your entire app (all activities), add the <code>android:theme</code>
+attribute
+to the <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+<application>}</a> element:</p>
+
+<pre><application android:theme="@style/CustomTheme"></pre>
+
+<p>For more about creating and using themes, read the <a
+href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> guide.</p>
+
diff --git a/docs/html/training/basics/supporting-devices/screens.jd b/docs/html/training/basics/supporting-devices/screens.jd
new file mode 100644
index 0000000..8697cd5
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/screens.jd
@@ -0,0 +1,180 @@
+page.title=Supporting Different Screens
+parent.title=Supporting Different Devices
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Supporting Different Languages
+previous.link=languages.html
+next.title=Supporting Different Platform Versions
+next.link=platforms.html
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#create-layouts">Create Different Layouts</a></li>
+ <li><a href="#create-bitmaps">Create Different Bitmaps</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple
+Screens</a></li>
+ <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a></li>
+ <li><a href="{@docRoot}design/style/iconography.html">Iconography design guide</a></li>
+ </ul>
+ </div>
+</div>
+
+<p>Android categorizes device screens using two general properties: size and density. You should
+expect that your app will be installed on devices with screens that range in both size
+and density. As such, you should include some alternative resources that optimize your app’s
+appearance for different screen sizes and densities.</p>
+
+<ul>
+ <li>There are four generalized sizes: small, normal, large, xlarge</li>
+ <li>And four generalized densities: low (ldpi), medium (mdpi), high (hdpi), extra high
+(xhdpi)</li>
+</ul>
+
+<p>To declare different layouts and bitmaps you'd like to use for different screens, you must place
+these alternative resources in separate directories, similar to how you do for different language
+strings.</p>
+
+<p>Also be aware that the screens orientation (landscape or portrait) is considered a variation of
+screen size, so many apps should revise the layout to optimize the user experience in each
+orientation.</p>
+
+
+<h2 id="create-layouts">Create Different Layouts</h2>
+
+<p>To optimize your user experience on different screen sizes, you should create a unique layout XML
+file for each screen size you want to support. Each layout should be
+saved into the appropriate resources directory, named with a <code>-<screen_size></code>
+suffix. For example, a unique layout for large screens should be saved under
+<code>res/layout-large/</code>.</p>
+
+<p class="note"><strong>Note:</strong> Android automatically scales your layout in order to
+properly fit the screen. Thus, your layouts for different screen sizes don't
+need to worry about the absolute size of UI elements but instead focus on the layout structure that
+affects the user experience (such as the size or position of important views relative to sibling
+views).</p>
+
+<p>For example, this project includes a default layout and an alternative layout for <em>large</em>
+screens:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ layout/
+ main.xml
+ layout-large/
+ main.xml
+</pre>
+
+<p>The file names must be exactly the same, but their contents are different in order to provide
+an optimized UI for the corresponding screen size.</p>
+
+<p>Simply reference the layout file in your app as usual:</p>
+
+<pre>
+@Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+}
+</pre>
+
+<p>The system loads the layout file from the appropriate layout directory based on screen size of
+the device on which your app is running. More information about how Android selects the
+appropriate resource is available in the <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">Providing Resources</a>
+guide.</p>
+
+<p>As another example, here's a project with an alternative layout for landscape orientation:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ layout/
+ main.xml
+ layout-land/
+ main.xml
+</pre>
+
+<p>By default, the <code>layout/main.xml</code> file is used for portrait orientation.</p>
+
+<p>If you want a provide a special layout for landscape, including while on large screens, then
+you need to use both the <code>large</code> and <code>land</code> qualifier:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ layout/ # default (portrait)
+ main.xml
+ layout-land/ # landscape
+ main.xml
+ layout-large/ # large (portrait)
+ main.xml
+ layout-large-land/ # large landscape
+ main.xml
+</pre>
+
+<p class="note"><strong>Note:</strong> Android 3.2 and above supports an advanced method of
+defining screen sizes that allows you to specify resources for screen sizes based on
+the minimum width and height in terms of density-independent pixels. This lesson does not cover
+this new technique. For more information, read <a
+href="{@docRoot}training/multiscreen/index.html">Designing for Multiple
+Screens</a>.</p>
+
+
+
+<h2 id="create-bitmaps">Create Different Bitmaps</h2>
+
+<p>You should always provide bitmap resources that are properly scaled to each of the generalized
+density buckets: low, medium, high and extra-high density. This helps you achieve good graphical
+quality and performance on all screen densities.</p>
+
+<p>To generate these images, you should start with your raw resource in vector format and generate
+the images for each density using the following size scale:</p>
+<ul>
+<li>xhdpi: 2.0</li>
+<li>hdpi: 1.5</li>
+<li>mdpi: 1.0 (baseline)</li>
+<li>ldpi: 0.75</li>
+</ul>
+
+<p>This means that if you generate a 200x200 image for xhdpi devices, you should generate the same
+resource in 150x150 for hdpi, 100x100 for mdpi, and 75x75 for ldpi devices.</p>
+
+<p>Then, place the files in the appropriate drawable resource directory:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ drawable-xhdpi/
+ awesomeimage.png
+ drawable-hdpi/
+ awesomeimage.png
+ drawable-mdpi/
+ awesomeimage.png
+ drawable-ldpi/
+ awesomeimage.png
+</pre>
+
+<p>Any time you reference <code>@drawable/awesomeimage</code>, the system selects the
+appropriate bitmap based on the screen's density.</p>
+
+<p class="note"><strong>Note:</strong> Low-density (ldpi) resources aren’t always necessary. When
+you provide hdpi assets, the system scales them down by one half to properly fit ldpi
+screens.</p>
+
+<p>For more tips and guidelines about creating icon assets for your app, see the
+<a href="{@docRoot}design/style/iconography.html">Iconography design guide</a>.</p>
+
+
+
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
index 2ae99e6..985dcd3 100644
--- a/policy/src/com/android/internal/policy/impl/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -291,7 +291,8 @@
if (!mServiceRunning) {
if (DEBUG) Log.d(TAG, "Starting FaceLock");
try {
- mService.startUi(windowToken, x, y, w, h);
+ mService.startUi(windowToken, x, y, w, h,
+ mLockPatternUtils.isBiometricWeakLivelinessEnabled());
} catch (RemoteException e) {
Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
return;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 5697284..d150b5c 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -65,6 +65,7 @@
import com.android.internal.telephony.ITelephony;
import com.android.internal.widget.PointerLocationView;
+import android.service.dreams.IDreamManager;
import android.speech.RecognizerIntent;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -108,6 +109,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
@@ -202,26 +204,28 @@
// responsible for power management when displayed.
static final int KEYGUARD_LAYER = 11;
static final int KEYGUARD_DIALOG_LAYER = 12;
- static final int STATUS_BAR_SUB_PANEL_LAYER = 13;
- static final int STATUS_BAR_LAYER = 14;
- static final int STATUS_BAR_PANEL_LAYER = 15;
+ // used for Dreams (screensavers with TYPE_DREAM windows)
+ static final int SCREENSAVER_LAYER = 13;
+ static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
+ static final int STATUS_BAR_LAYER = 15;
+ static final int STATUS_BAR_PANEL_LAYER = 16;
// the on-screen volume indicator and controller shown when the user
// changes the device volume
- static final int VOLUME_OVERLAY_LAYER = 16;
+ static final int VOLUME_OVERLAY_LAYER = 17;
// things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 17;
+ static final int SYSTEM_OVERLAY_LAYER = 18;
// the navigation bar, if available, shows atop most things
- static final int NAVIGATION_BAR_LAYER = 18;
+ static final int NAVIGATION_BAR_LAYER = 19;
// system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 19;
+ static final int SYSTEM_ERROR_LAYER = 20;
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- static final int DRAG_LAYER = 20;
- static final int SECURE_SYSTEM_OVERLAY_LAYER = 21;
- static final int BOOT_PROGRESS_LAYER = 22;
+ static final int DRAG_LAYER = 21;
+ static final int SECURE_SYSTEM_OVERLAY_LAYER = 22;
+ static final int BOOT_PROGRESS_LAYER = 23;
// the (mouse) pointer layer
- static final int POINTER_LAYER = 23;
- static final int HIDDEN_NAV_CONSUMER_LAYER = 24;
+ static final int POINTER_LAYER = 24;
+ static final int HIDDEN_NAV_CONSUMER_LAYER = 25;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -453,6 +457,7 @@
boolean mLockScreenTimerActive;
// visual screen saver support
+ boolean mScreenSaverFeatureAvailable;
int mScreenSaverTimeout = 0;
boolean mScreenSaverEnabledByUser = false;
boolean mScreenSaverMayRun = true; // false if a wakelock is held
@@ -1076,6 +1081,10 @@
updateRotation = true;
}
+ // dreams
+ mScreenSaverFeatureAvailable = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableDreams);
+
mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver,
Settings.Secure.SCREENSAVER_ENABLED, 1);
@@ -1091,7 +1100,6 @@
mScreenSaverTimeout -= 5000;
}
}
- updateScreenSaverTimeoutLocked();
}
if (updateRotation) {
updateRotation(true);
@@ -1179,6 +1187,7 @@
// this... should introduce a token to let the system
// monitor/control what they are doing.
break;
+ case TYPE_DREAM:
case TYPE_INPUT_METHOD:
case TYPE_WALLPAPER:
// The window manager will check these.
@@ -1309,6 +1318,8 @@
return BOOT_PROGRESS_LAYER;
case TYPE_HIDDEN_NAV_CONSUMER:
return HIDDEN_NAV_CONSUMER_LAYER;
+ case TYPE_DREAM:
+ return SCREENSAVER_LAYER;
}
Log.e(TAG, "Unknown window type: " + type);
return APPLICATION_LAYER;
@@ -1340,18 +1351,29 @@
}
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
- // Assumes that the navigation bar appears on the side of the display in landscape.
- if (mHasNavigationBar && fullWidth > fullHeight) {
- return fullWidth - mNavigationBarWidth;
+ if (mHasNavigationBar) {
+ // For a basic navigation bar, when we are in landscape mode we place
+ // the navigation bar to the side.
+ if (fullWidth > fullHeight) {
+ return fullWidth - mNavigationBarWidth;
+ }
}
return fullWidth;
}
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
- // Assumes the navigation bar appears on the bottom of the display in portrait.
- return fullHeight
- - (mHasSystemNavBar ? mNavigationBarHeight : 0)
- - ((mHasNavigationBar && fullWidth > fullHeight) ? 0 : mNavigationBarHeight);
+ if (mHasSystemNavBar) {
+ // For the system navigation bar, we always place it at the bottom.
+ return fullHeight - mNavigationBarHeight;
+ }
+ if (mHasNavigationBar) {
+ // For a basic navigation bar, when we are in portrait mode we place
+ // the navigation bar to the bottom.
+ if (fullWidth < fullHeight) {
+ return fullHeight - mNavigationBarHeight;
+ }
+ }
+ return fullHeight;
}
public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
@@ -1359,13 +1381,15 @@
}
public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
- // This is the same as getNonDecorDisplayHeight, unless the status bar
- // can hide. If the status bar can hide, we don't count that as part
- // of the decor; however for purposes of configurations, we do want to
- // exclude it since applications can't generally use that part of the
- // screen.
- return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation)
- - (mHasSystemNavBar ? 0 : mStatusBarHeight);
+ // If we don't have a system nav bar, then there is a separate status
+ // bar at the top of the display. We don't count that as part of the
+ // fixed decor, since it can hide; however, for purposes of configurations,
+ // we do want to exclude it since applications can't generally use that part
+ // of the screen.
+ if (!mHasSystemNavBar) {
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
+ }
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation);
}
public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
@@ -3317,7 +3341,6 @@
synchronized (mLock) {
updateOrientationListenerLp();
updateLockScreenTimeout();
- updateScreenSaverTimeoutLocked();
}
}
@@ -3366,7 +3389,6 @@
mScreenOnEarly = true;
updateOrientationListenerLp();
updateLockScreenTimeout();
- updateScreenSaverTimeoutLocked();
}
}
@@ -3756,83 +3778,58 @@
mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
}
}
-
- synchronized (mLock) {
- // Only posts messages; holds no additional locks.
- updateScreenSaverTimeoutLocked();
- }
}
- Runnable mScreenSaverActivator = new Runnable() {
- public void run() {
- if (!(mScreenSaverMayRun && mScreenOnEarly)) {
- Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?");
- return;
- }
- if (!mPluggedIn) {
- if (localLOGV) Log.v(TAG, "mScreenSaverActivator: not running screen saver when not plugged in");
- return;
- }
- // Quick fix for automation tests.
- // The correct fix is to move this triggering logic to PowerManager, where more complete
- // information about wakelocks (including StayOnWhilePluggedIn) is available.
- if (Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.STAY_ON_WHILE_PLUGGED_IN,
- BatteryManager.BATTERY_PLUGGED_AC) != 0) {
- Log.v(TAG, "mScreenSaverActivator: not running screen saver when STAY_ON_WHILE_PLUGGED_IN");
- return;
- }
+ private IDreamManager getDreamManager() {
+ if (!mScreenSaverFeatureAvailable) {
+ return null;
+ }
+
+ IDreamManager sandman = IDreamManager.Stub.asInterface(
+ ServiceManager.checkService("dreams"));
+ if (sandman == null) {
+ Log.w(TAG, "Unable to find IDreamManager");
+ }
+ return sandman;
+ }
- if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
+ @Override
+ public boolean isScreenSaverEnabled() {
+ return (mScreenSaverFeatureAvailable && mScreenSaverEnabledByUser
+ && mScreenSaverMayRun && mScreenOnEarly && mPluggedIn);
+ }
- try {
- String component = Settings.Secure.getString(
- mContext.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT);
- if (component == null) {
- component = mContext.getResources().getString(R.string.config_defaultDreamComponent);
+ @Override
+ public boolean startScreenSaver() {
+ synchronized (mLock) {
+ if (isScreenSaverEnabled()) {
+ IDreamManager dm = getDreamManager();
+ if (dm == null) return false;
+
+ try {
+ if (localLOGV) Log.v(TAG, "startScreenSaver: entering dreamland...");
+
+ dm.dream();
+ return true;
+ } catch (RemoteException ex) {
+ // too bad, so sad, oh mom, oh dad
}
- if (component != null) {
- // dismiss the notification shade, recents, etc.
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT));
-
- ComponentName cn = ComponentName.unflattenFromString(component);
- Intent intent = new Intent(Intent.ACTION_MAIN)
- .setComponent(cn)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_NO_USER_ACTION
- | Intent.FLAG_FROM_BACKGROUND
- | Intent.FLAG_ACTIVITY_NO_HISTORY
- );
- mContext.startActivity(intent);
- } else {
- Log.e(TAG, "Couldn't start screen saver: none selected");
- }
- } catch (android.content.ActivityNotFoundException exc) {
- // no screensaver? give up
- Log.e(TAG, "Couldn't start screen saver: none installed");
}
}
- };
+ return false;
+ }
- // Must call while holding mLock
- private void updateScreenSaverTimeoutLocked() {
- if (mScreenSaverActivator == null) return;
-
- mHandler.removeCallbacks(mScreenSaverActivator);
- if (mScreenSaverEnabledByUser && mScreenSaverMayRun && mScreenOnEarly && mScreenSaverTimeout > 0) {
- if (localLOGV)
- Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now");
- mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout);
- } else {
- if (localLOGV) {
- if (!mScreenSaverEnabledByUser || mScreenSaverTimeout == 0)
- Log.v(TAG, "screen saver disabled by user");
- else if (!mScreenOnEarly)
- Log.v(TAG, "screen saver disabled while screen off");
- else
- Log.v(TAG, "screen saver disabled by wakelock");
+ @Override
+ public void stopScreenSaver() {
+ synchronized (mLock) {
+ IDreamManager dm = getDreamManager();
+ if (dm == null) return;
+
+ try {
+ if (localLOGV) Log.v(TAG, "startScreenSaver: awakening...");
+
+ dm.awaken();
+ } catch (RemoteException ex) {
}
}
}
@@ -4078,7 +4075,6 @@
// even if the keyguard is up, now that all the wakelocks have been released, we
// should re-enable the screen saver
mScreenSaverMayRun = true;
- updateScreenSaverTimeoutLocked();
}
}
}
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
index ef7fa168..7a4986b 100644
--- a/services/common_time/common_time_server.cpp
+++ b/services/common_time/common_time_server.cpp
@@ -80,14 +80,14 @@
// number of sync requests that can fail before a client assumes its master
// is dead
-const int CommonTimeServer::kClient_NumSyncRequestRetries = 5;
+const int CommonTimeServer::kClient_NumSyncRequestRetries = 10;
/*** Master state constants ***/
/*** Ronin state constants ***/
// number of WhoIsMaster attempts sent before declaring ourselves master
-const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 4;
+const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 20;
// timeout used when waiting for a response to a WhoIsMaster request
const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500;
@@ -96,7 +96,7 @@
// how long do we wait for an announcement from a master before
// trying another election?
-const int CommonTimeServer::kWaitForElection_TimeoutMs = 5000;
+const int CommonTimeServer::kWaitForElection_TimeoutMs = 12500;
CommonTimeServer::CommonTimeServer()
: Thread(false)
@@ -279,10 +279,14 @@
// If we were in the master state, then either we were the
// master in a no-network situation, or we were the master
// of a different network and have moved to a new interface.
- // In either case, immediately send out a master
- // announcement at low priority.
+ // In either case, immediately transition to Ronin at low
+ // priority. If there is no one in the network we just
+ // joined, we will become master soon enough. If there is,
+ // we want to be certain to defer master status to the
+ // existing timeline currently running on the network.
+ //
case CommonClockService::STATE_MASTER:
- sendMasterAnnouncement();
+ becomeRonin("leaving networkless mode");
break;
// If we were in any other state (CLIENT, RONIN, or
@@ -1072,6 +1076,12 @@
mMasterEP = masterEP;
mMasterEPValid = true;
+
+ // If we are on a real network as a client of a real master, then we should
+ // no longer force low priority. If our master disappears, we should have
+ // the high priority bit set during the election to replace the master
+ // because this group was a real group and not a singleton created in
+ // networkless mode.
setForceLowPriority(false);
mClient_MasterDeviceID = masterDeviceID;
@@ -1113,7 +1123,6 @@
memset(&mMasterEP, 0, sizeof(mMasterEP));
mMasterEPValid = false;
- setForceLowPriority(false);
mClient_MasterDevicePriority = effectivePriority();
mClient_MasterDeviceID = mDeviceID;
mClockRecovery.reset(false, true);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 52a4110..bebce7e 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1752,7 +1752,7 @@
+ " noChangeLights=" + noChangeLights
+ " reason=" + reason);
}
-
+
if (noChangeLights) {
newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
}
@@ -1794,6 +1794,19 @@
final boolean stateChanged = mPowerState != newState;
+ if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) {
+ if (mPolicy.isScreenSaverEnabled()) {
+ if (mSpew) {
+ Slog.d(TAG, "setPowerState: running screen saver instead of turning off screen");
+ }
+ if (mPolicy.startScreenSaver()) {
+ // was successful
+ return;
+ }
+ }
+ }
+
+
if (oldScreenOn != newScreenOn) {
if (newScreenOn) {
// When the user presses the power button, we need to always send out the
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7dd736d..68bbb571 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,6 +38,7 @@
import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.server.search.SearchManagerService;
+import android.service.dreams.DreamManagerService;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -269,6 +270,7 @@
CountryDetectorService countryDetector = null;
TextServicesManagerService tsms = null;
LockSettingsService lockSettings = null;
+ DreamManagerService dreamy = null;
// Bring up services needed for UI.
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
@@ -613,6 +615,18 @@
} catch (Throwable e) {
reportWtf("starting CommonTimeManagementService service", e);
}
+
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableDreams)) {
+ try {
+ Slog.i(TAG, "Dreams Service");
+ // Dreams (interactive idle-time views, a/k/a screen savers)
+ dreamy = new DreamManagerService(context);
+ ServiceManager.addService("dreams", dreamy);
+ } catch (Throwable e) {
+ reportWtf("starting DreamManagerService", e);
+ }
+ }
}
// Before things start rolling, be sure we have decided whether
@@ -699,6 +713,7 @@
final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
final TextServicesManagerService textServiceManagerServiceF = tsms;
final StatusBarManagerService statusBarF = statusBar;
+ final DreamManagerService dreamyF = dreamy;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -805,6 +820,11 @@
} catch (Throwable e) {
reportWtf("making Text Services Manager Service ready", e);
}
+ try {
+ if (dreamyF != null) dreamyF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making DreamManagerService ready", e);
+ }
}
});
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a7af8fb..00972fa 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -28,6 +28,7 @@
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -2131,6 +2132,11 @@
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
+ if (attrs.type == TYPE_DREAM) {
+ Slog.w(TAG, "Attempted to add Dream window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
} else if (attrs.type >= FIRST_APPLICATION_WINDOW
@@ -2163,6 +2169,12 @@
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
+ } else if (attrs.type == TYPE_DREAM) {
+ if (token.windowType != TYPE_DREAM) {
+ Slog.w(TAG, "Attempted to add Dream window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
}
win = new WindowState(this, session, client, token,