Merge "Glop mesh reorg, support for drawBitmapMesh"
diff --git a/api/current.txt b/api/current.txt
index c0ad9c6..676a1cd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2019,6 +2019,7 @@
field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974412; // 0x103024c
+ field public static final int ThemeOverlay_Material_Dialog = 16974564; // 0x10302e4
field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
@@ -3746,8 +3747,8 @@
public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
ctor protected AlertDialog(android.content.Context);
- ctor protected AlertDialog(android.content.Context, int);
ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+ ctor protected AlertDialog(android.content.Context, int);
method public android.widget.Button getButton(int);
method public android.widget.ListView getListView();
method public void setButton(int, java.lang.CharSequence, android.os.Message);
@@ -3766,11 +3767,11 @@
method public void setMessage(java.lang.CharSequence);
method public void setView(android.view.View);
method public void setView(android.view.View, int, int, int, int);
- field public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
- field public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
- field public static final int THEME_HOLO_DARK = 2; // 0x2
- field public static final int THEME_HOLO_LIGHT = 3; // 0x3
- field public static final int THEME_TRADITIONAL = 1; // 0x1
+ field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+ field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+ field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
+ field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
+ field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
}
public static class AlertDialog.Builder {
@@ -3785,7 +3786,7 @@
method public android.app.AlertDialog.Builder setIcon(int);
method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
method public android.app.AlertDialog.Builder setIconAttribute(int);
- method public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+ method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
method public android.app.AlertDialog.Builder setMessage(int);
@@ -5478,7 +5479,6 @@
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
- method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5527,7 +5527,6 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
- method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
@@ -7321,6 +7320,7 @@
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
+ method public final T getSystemService(java.lang.Class<T>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -7450,7 +7450,7 @@
method public int checkPermission(java.lang.String, int, int);
method public int checkUriPermission(android.net.Uri, int, int, int);
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
- method public void clearWallpaper() throws java.io.IOException;
+ method public deprecated void clearWallpaper() throws java.io.IOException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7493,20 +7493,21 @@
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
method public java.lang.Object getSystemService(java.lang.String);
+ method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
- method public android.graphics.drawable.Drawable getWallpaper();
- method public int getWallpaperDesiredMinimumHeight();
- method public int getWallpaperDesiredMinimumWidth();
+ method public deprecated android.graphics.drawable.Drawable getWallpaper();
+ method public deprecated int getWallpaperDesiredMinimumHeight();
+ method public deprecated int getWallpaperDesiredMinimumWidth();
method public void grantUriPermission(java.lang.String, android.net.Uri, int);
method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
- method public android.graphics.drawable.Drawable peekWallpaper();
+ method public deprecated android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public void removeStickyBroadcast(android.content.Intent);
- method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public deprecated void removeStickyBroadcast(android.content.Intent);
+ method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
method public void sendBroadcast(android.content.Intent);
method public void sendBroadcast(android.content.Intent, java.lang.String);
@@ -7515,13 +7516,13 @@
method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendStickyBroadcast(android.content.Intent);
- method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
- method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public deprecated void sendStickyBroadcast(android.content.Intent);
+ method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void setTheme(int);
- method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
- method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+ method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+ method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
method public void startActivities(android.content.Intent[]);
method public void startActivities(android.content.Intent[], android.os.Bundle);
method public void startActivity(android.content.Intent);
@@ -21781,7 +21782,6 @@
}
public class BatteryManager {
- ctor public BatteryManager();
method public int getIntProperty(int);
method public long getLongProperty(int);
field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
@@ -27657,7 +27657,7 @@
method public android.os.IBinder onBind(android.content.Intent);
method public void onReady();
method public void onShutdown();
- method public void startSession(android.os.Bundle, int);
+ method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
field public static final int START_WITH_ASSIST = 1; // 0x1
@@ -27669,6 +27669,7 @@
method public void finish();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
+ method public void hide();
method public void hideWindow();
method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
method public void onBackPressed();
@@ -27683,14 +27684,17 @@
method public void onDestroy();
method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
method public void onHandleAssist(android.os.Bundle);
+ method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
method public boolean onKeyUp(int, android.view.KeyEvent);
+ method public void onShow(android.os.Bundle, int);
method public void onTaskFinished(android.content.Intent, int);
method public void onTaskStarted(android.content.Intent, int);
method public void setContentView(android.view.View);
method public void setTheme(int);
+ method public void show();
method public void showWindow();
method public void startVoiceActivity(android.content.Intent);
}
@@ -29844,6 +29848,7 @@
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
method public java.lang.Object getSystemService(java.lang.String);
+ method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
method public android.graphics.drawable.Drawable getWallpaper();
method public int getWallpaperDesiredMinimumHeight();
diff --git a/api/removed.txt b/api/removed.txt
index 9322973..8668a77 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -16,6 +16,10 @@
package android.os {
+ public class BatteryManager {
+ ctor public BatteryManager();
+ }
+
public final class PowerManager {
method public void goToSleep(long);
method public deprecated void userActivity(long, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index deaa5f0..95e57c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2097,6 +2097,7 @@
field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974412; // 0x103024c
+ field public static final int ThemeOverlay_Material_Dialog = 16974564; // 0x10302e4
field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
@@ -3835,8 +3836,8 @@
public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
ctor protected AlertDialog(android.content.Context);
- ctor protected AlertDialog(android.content.Context, int);
ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+ ctor protected AlertDialog(android.content.Context, int);
method public android.widget.Button getButton(int);
method public android.widget.ListView getListView();
method public void setButton(int, java.lang.CharSequence, android.os.Message);
@@ -3855,11 +3856,11 @@
method public void setMessage(java.lang.CharSequence);
method public void setView(android.view.View);
method public void setView(android.view.View, int, int, int, int);
- field public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
- field public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
- field public static final int THEME_HOLO_DARK = 2; // 0x2
- field public static final int THEME_HOLO_LIGHT = 3; // 0x3
- field public static final int THEME_TRADITIONAL = 1; // 0x1
+ field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+ field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+ field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
+ field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
+ field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
}
public static class AlertDialog.Builder {
@@ -3874,7 +3875,7 @@
method public android.app.AlertDialog.Builder setIcon(int);
method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
method public android.app.AlertDialog.Builder setIconAttribute(int);
- method public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+ method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
method public android.app.AlertDialog.Builder setMessage(int);
@@ -5578,7 +5579,6 @@
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
- method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5628,7 +5628,6 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
- method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
@@ -7526,6 +7525,7 @@
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
+ method public final T getSystemService(java.lang.Class<T>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -7661,7 +7661,7 @@
method public int checkPermission(java.lang.String, int, int);
method public int checkUriPermission(android.net.Uri, int, int, int);
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
- method public void clearWallpaper() throws java.io.IOException;
+ method public deprecated void clearWallpaper() throws java.io.IOException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7704,20 +7704,21 @@
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
method public java.lang.Object getSystemService(java.lang.String);
+ method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
- method public android.graphics.drawable.Drawable getWallpaper();
- method public int getWallpaperDesiredMinimumHeight();
- method public int getWallpaperDesiredMinimumWidth();
+ method public deprecated android.graphics.drawable.Drawable getWallpaper();
+ method public deprecated int getWallpaperDesiredMinimumHeight();
+ method public deprecated int getWallpaperDesiredMinimumWidth();
method public void grantUriPermission(java.lang.String, android.net.Uri, int);
method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
- method public android.graphics.drawable.Drawable peekWallpaper();
+ method public deprecated android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public void removeStickyBroadcast(android.content.Intent);
- method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public deprecated void removeStickyBroadcast(android.content.Intent);
+ method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
method public void sendBroadcast(android.content.Intent);
method public void sendBroadcast(android.content.Intent, java.lang.String);
@@ -7726,13 +7727,13 @@
method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendStickyBroadcast(android.content.Intent);
- method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
- method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public deprecated void sendStickyBroadcast(android.content.Intent);
+ method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void setTheme(int);
- method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
- method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+ method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+ method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
method public void startActivities(android.content.Intent[]);
method public void startActivities(android.content.Intent[], android.os.Bundle);
method public void startActivity(android.content.Intent);
@@ -23370,7 +23371,6 @@
}
public class BatteryManager {
- ctor public BatteryManager();
method public int getIntProperty(int);
method public long getLongProperty(int);
field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
@@ -29346,7 +29346,7 @@
method public android.os.IBinder onBind(android.content.Intent);
method public void onReady();
method public void onShutdown();
- method public void startSession(android.os.Bundle, int);
+ method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
field public static final int START_WITH_ASSIST = 1; // 0x1
@@ -29358,6 +29358,7 @@
method public void finish();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
+ method public void hide();
method public void hideWindow();
method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
method public void onBackPressed();
@@ -29372,14 +29373,17 @@
method public void onDestroy();
method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
method public void onHandleAssist(android.os.Bundle);
+ method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
method public boolean onKeyUp(int, android.view.KeyEvent);
+ method public void onShow(android.os.Bundle, int);
method public void onTaskFinished(android.content.Intent, int);
method public void onTaskStarted(android.content.Intent, int);
method public void setContentView(android.view.View);
method public void setTheme(int);
+ method public void show();
method public void showWindow();
method public void startVoiceActivity(android.content.Intent);
}
@@ -32005,6 +32009,7 @@
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
method public java.lang.Object getSystemService(java.lang.String);
+ method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
method public android.graphics.drawable.Drawable getWallpaper();
method public int getWallpaperDesiredMinimumHeight();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 9322973..8668a77 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -16,6 +16,10 @@
package android.os {
+ public class BatteryManager {
+ ctor public BatteryManager();
+ }
+
public final class PowerManager {
method public void goToSleep(long);
method public deprecated void userActivity(long, boolean);
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index e3b27b5..2939322 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -206,7 +206,6 @@
private ArrayList<GhostViewListeners> mGhostViewListeners =
new ArrayList<GhostViewListeners>();
private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>();
- final private ArrayList<View> mRootSharedElements = new ArrayList<View>();
private ArrayList<Matrix> mSharedElementParentMatrices;
public ActivityTransitionCoordinator(Window window,
@@ -253,17 +252,10 @@
final String name = sharedElements.keyAt(i);
if (isFirstRun && (view == null || !view.isAttachedToWindow() || name == null)) {
sharedElements.removeAt(i);
- } else {
- if (!isNested(view, sharedElements)) {
- mSharedElementNames.add(name);
- mSharedElements.add(view);
- sharedElements.removeAt(i);
- if (isFirstRun) {
- // We need to keep track which shared elements are roots
- // and which are nested.
- mRootSharedElements.add(view);
- }
- }
+ } else if (!isNested(view, sharedElements)) {
+ mSharedElementNames.add(name);
+ mSharedElements.add(view);
+ sharedElements.removeAt(i);
}
}
isFirstRun = false;
@@ -520,24 +512,9 @@
}
private void getSharedElementParentMatrix(View view, Matrix matrix) {
- final boolean isNestedInOtherSharedElement = !mRootSharedElements.contains(view);
- final boolean useParentMatrix;
- if (isNestedInOtherSharedElement) {
- useParentMatrix = true;
- } else {
- final int index = mSharedElementParentMatrices == null ? -1
- : mSharedElements.indexOf(view);
- if (index < 0) {
- useParentMatrix = true;
- } else {
- // The indices of mSharedElementParentMatrices matches the
- // mSharedElement matrices.
- Matrix parentMatrix = mSharedElementParentMatrices.get(index);
- matrix.set(parentMatrix);
- useParentMatrix = false;
- }
- }
- if (useParentMatrix) {
+ final int index = mSharedElementParentMatrices == null ? -1
+ : mSharedElements.indexOf(view);
+ if (index < 0) {
matrix.reset();
ViewParent viewParent = view.getParent();
if (viewParent instanceof ViewGroup) {
@@ -545,6 +522,11 @@
ViewGroup parent = (ViewGroup) viewParent;
parent.transformMatrixToLocal(matrix);
}
+ } else {
+ // The indices of mSharedElementParentMatrices matches the
+ // mSharedElement matrices.
+ Matrix parentMatrix = mSharedElementParentMatrices.get(index);
+ matrix.set(parentMatrix);
}
}
@@ -701,7 +683,6 @@
mResultReceiver = null;
mPendingTransition = null;
mListener = null;
- mRootSharedElements.clear();
mSharedElementParentMatrices = null;
}
@@ -817,9 +798,12 @@
ViewGroup decor = getDecor();
if (decor != null) {
boolean moveWithParent = moveSharedElementWithParent();
+ Matrix tempMatrix = new Matrix();
for (int i = 0; i < numSharedElements; i++) {
View view = mSharedElements.get(i);
- GhostView.addGhost(view, decor);
+ tempMatrix.reset();
+ mSharedElementParentMatrices.get(i).invert(tempMatrix);
+ GhostView.addGhost(view, decor, tempMatrix);
ViewGroup parent = (ViewGroup) view.getParent();
if (moveWithParent && !isInTransitionGroup(parent, decor)) {
GhostViewListeners listener = new GhostViewListeners(view, parent, decor);
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index c8f58c6..3e545f9 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -38,6 +38,8 @@
import android.widget.ListAdapter;
import android.widget.ListView;
+import com.android.internal.R;
+
/**
* A subclass of Dialog that can display one, two or three buttons. If you only want to
* display a String in this dialog box, use the setMessage() method. If you
@@ -48,7 +50,7 @@
* FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom);
* fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
* </pre>
- *
+ *
* <p>The AlertDialog class takes care of automatically setting
* {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
* WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether
@@ -70,31 +72,46 @@
/**
* Special theme constant for {@link #AlertDialog(Context, int)}: use
* the traditional (pre-Holo) alert dialog theme.
+ *
+ * @deprecated Use {@link android.R.style#Theme_Material_Dialog_Alert}.
*/
+ @Deprecated
public static final int THEME_TRADITIONAL = 1;
-
+
/**
* Special theme constant for {@link #AlertDialog(Context, int)}: use
* the holographic alert theme with a dark background.
+ *
+ * @deprecated Use {@link android.R.style#Theme_Material_Dialog_Alert}.
*/
+ @Deprecated
public static final int THEME_HOLO_DARK = 2;
-
+
/**
* Special theme constant for {@link #AlertDialog(Context, int)}: use
* the holographic alert theme with a light background.
+ *
+ * @deprecated Use {@link android.R.style#Theme_Material_Light_Dialog_Alert}.
*/
+ @Deprecated
public static final int THEME_HOLO_LIGHT = 3;
/**
* Special theme constant for {@link #AlertDialog(Context, int)}: use
* the device's default alert theme with a dark background.
+ *
+ * @deprecated Use {@link android.R.style#Theme_DeviceDefault_Dialog_Alert}.
*/
+ @Deprecated
public static final int THEME_DEVICE_DEFAULT_DARK = 4;
/**
* Special theme constant for {@link #AlertDialog(Context, int)}: use
* the device's default alert theme with a light background.
+ *
+ * @deprecated Use {@link android.R.style#Theme_DeviceDefault_Light_Dialog_Alert}.
*/
+ @Deprecated
public static final int THEME_DEVICE_DEFAULT_LIGHT = 5;
/**
@@ -108,55 +125,92 @@
* @hide
*/
public static final int LAYOUT_HINT_SIDE = 1;
-
+
+ /**
+ * Creates an alert dialog that uses the default alert dialog theme.
+ * <p>
+ * The default alert dialog theme is defined by
+ * {@link android.R.attr#alertDialogTheme} within the parent
+ * {@code context}'s theme.
+ *
+ * @param context the parent context
+ */
protected AlertDialog(Context context) {
- this(context, resolveDialogTheme(context, 0), true);
+ this(context, 0);
}
/**
- * Construct an AlertDialog that uses an explicit theme. The actual style
- * that an AlertDialog uses is a private implementation, however you can
- * here supply either the name of an attribute in the theme from which
- * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
- * or one of the constants {@link #THEME_TRADITIONAL},
- * {@link #THEME_HOLO_DARK}, or {@link #THEME_HOLO_LIGHT}.
+ * Creates an alert dialog that uses the default alert dialog theme and a
+ * custom cancel listener.
+ * <p>
+ * This is functionally identical to:
+ * <pre>
+ * AlertDialog dialog = new AlertDialog(context);
+ * alertDialog.setCancelable(cancelable);
+ * alertDialog.setOnCancelListener(cancelListener);
+ * </pre>
+ * <p>
+ * The default alert dialog theme is defined by
+ * {@link android.R.attr#alertDialogTheme} within the parent
+ * {@code context}'s theme.
+ *
+ * @param context the parent context
*/
- protected AlertDialog(Context context, @AttrRes int theme) {
- this(context, theme, true);
+ protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
+ this(context, 0);
+
+ setCancelable(cancelable);
+ setOnCancelListener(cancelListener);
}
- AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
- super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
+ /**
+ * Creates an alert dialog that uses an explicit theme resource.
+ * <p>
+ * The specified theme resource ({@code themeResId}) is applied on top of
+ * the parent {@code context}'s theme. It may be specified as a style
+ * resource containing a fully-populated theme, such as
+ * {@link android.R.style#Theme_Material_Dialog}, to replace all attributes
+ * in the parent {@code context}'s theme including primary and accent
+ * colors.
+ * <p>
+ * To preserve attributes such as primary and accent colors, the
+ * {@code themeResId} may instead be specified as an overlay theme such as
+ * {@link android.R.style#ThemeOverlay_Material_Dialog}. This will override
+ * only the window attributes necessary to style the alert window as a
+ * dialog.
+ * <p>
+ * Alternatively, the {@code themeResId} may be specified as {@code 0} to
+ * use the parent {@code context}'s resolved value for
+ * {@link android.R.attr#alertDialogTheme}.
+ *
+ * @param context the parent context
+ * @param themeResId the resource ID of the theme against which to inflate
+ * this dialog, or {@code 0} to use the parent
+ * {@code context}'s default alert dialog theme
+ */
+ protected AlertDialog(Context context, @AttrRes int themeResId) {
+ super(context, resolveDialogTheme(context, themeResId));
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
- protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
- super(context, resolveDialogTheme(context, 0));
- mWindow.alwaysReadCloseOnTouchAttr();
- setCancelable(cancelable);
- setOnCancelListener(cancelListener);
- mAlert = new AlertController(context, this, getWindow());
- }
-
- static int resolveDialogTheme(Context context, int resid) {
- if (resid == THEME_TRADITIONAL) {
- return com.android.internal.R.style.Theme_Dialog_Alert;
- } else if (resid == THEME_HOLO_DARK) {
- return com.android.internal.R.style.Theme_Holo_Dialog_Alert;
- } else if (resid == THEME_HOLO_LIGHT) {
- return com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert;
- } else if (resid == THEME_DEVICE_DEFAULT_DARK) {
- return com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert;
- } else if (resid == THEME_DEVICE_DEFAULT_LIGHT) {
- return com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert;
- } else if (resid >= 0x01000000) { // start of real resource IDs.
- return resid;
+ static int resolveDialogTheme(Context context, int themeResId) {
+ if (themeResId == THEME_TRADITIONAL) {
+ return R.style.Theme_Dialog_Alert;
+ } else if (themeResId == THEME_HOLO_DARK) {
+ return R.style.Theme_Holo_Dialog_Alert;
+ } else if (themeResId == THEME_HOLO_LIGHT) {
+ return R.style.Theme_Holo_Light_Dialog_Alert;
+ } else if (themeResId == THEME_DEVICE_DEFAULT_DARK) {
+ return R.style.Theme_DeviceDefault_Dialog_Alert;
+ } else if (themeResId == THEME_DEVICE_DEFAULT_LIGHT) {
+ return R.style.Theme_DeviceDefault_Light_Dialog_Alert;
+ } else if (themeResId >= 0x01000000) { // start of real resource IDs.
+ return themeResId;
} else {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
- outValue, true);
+ final TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);
return outValue.resourceId;
}
}
@@ -177,13 +231,13 @@
/**
* Gets the list view used in the dialog.
- *
+ *
* @return The {@link ListView} from the dialog.
*/
public ListView getListView() {
return mAlert.getListView();
}
-
+
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
@@ -196,7 +250,7 @@
public void setCustomTitle(View customTitleView) {
mAlert.setCustomTitle(customTitleView);
}
-
+
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
@@ -207,9 +261,9 @@
public void setView(View view) {
mAlert.setView(view);
}
-
+
/**
- * Set the view to display in that dialog, specifying the spacing to appear around that
+ * Set the view to display in that dialog, specifying the spacing to appear around that
* view.
*
* @param view The view to show in the content area of the dialog
@@ -233,7 +287,7 @@
/**
* Set a message to be sent when a button is pressed.
- *
+ *
* @param whichButton Which button to set the message for, can be one of
* {@link DialogInterface#BUTTON_POSITIVE},
* {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -244,10 +298,10 @@
public void setButton(int whichButton, CharSequence text, Message msg) {
mAlert.setButton(whichButton, text, null, msg);
}
-
+
/**
* Set a listener to be invoked when the positive button of the dialog is pressed.
- *
+ *
* @param whichButton Which button to set the listener on, can be one of
* {@link DialogInterface#BUTTON_POSITIVE},
* {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -267,7 +321,7 @@
public void setButton(CharSequence text, Message msg) {
setButton(BUTTON_POSITIVE, text, msg);
}
-
+
/**
* @deprecated Use {@link #setButton(int, CharSequence, Message)} with
* {@link DialogInterface#BUTTON_NEGATIVE}.
@@ -288,7 +342,7 @@
/**
* Set a listener to be invoked when button 1 of the dialog is pressed.
- *
+ *
* @param text The text to display in button 1.
* @param listener The {@link DialogInterface.OnClickListener} to use.
* @deprecated Use
@@ -334,7 +388,7 @@
public void setIcon(@DrawableRes int resId) {
mAlert.setIcon(resId);
}
-
+
public void setIcon(Drawable icon) {
mAlert.setIcon(icon);
}
@@ -353,7 +407,7 @@
public void setInverseBackgroundForced(boolean forceInverseBackground) {
mAlert.setInverseBackgroundForced(forceInverseBackground);
}
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -371,35 +425,57 @@
if (mAlert.onKeyUp(keyCode, event)) return true;
return super.onKeyUp(keyCode, event);
}
-
+
public static class Builder {
private final AlertController.AlertParams P;
- private int mTheme;
-
+ private int mThemeResId;
+
/**
- * Constructor using a context for this builder and the {@link AlertDialog} it creates.
+ * Creates a builder for an alert dialog that uses the default alert
+ * dialog theme.
+ * <p>
+ * The default alert dialog theme is defined by
+ * {@link android.R.attr#alertDialogTheme} within the parent
+ * {@code context}'s theme.
+ *
+ * @param context the parent context
*/
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
/**
- * Constructor using a context and theme for this builder and
- * the {@link AlertDialog} it creates. The actual theme
- * that an AlertDialog uses is a private implementation, however you can
- * here supply either the name of an attribute in the theme from which
- * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
- * or one of the constants
- * {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL},
- * {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or
- * {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}.
+ * Creates a builder for an alert dialog that uses an explicit theme
+ * resource.
+ * <p>
+ * The specified theme resource ({@code themeResId}) is applied on top
+ * of the parent {@code context}'s theme. It may be specified as a
+ * style resource containing a fully-populated theme, such as
+ * {@link android.R.style#Theme_Material_Dialog}, to replace all
+ * attributes in the parent {@code context}'s theme including primary
+ * and accent colors.
+ * <p>
+ * To preserve attributes such as primary and accent colors, the
+ * {@code themeResId} may instead be specified as an overlay theme such
+ * as {@link android.R.style#ThemeOverlay_Material_Dialog}. This will
+ * override only the window attributes necessary to style the alert
+ * window as a dialog.
+ * <p>
+ * Alternatively, the {@code themeResId} may be specified as {@code 0}
+ * to use the parent {@code context}'s resolved value for
+ * {@link android.R.attr#alertDialogTheme}.
+ *
+ * @param context the parent context
+ * @param themeResId the resource ID of the theme against which to inflate
+ * this dialog, or {@code 0} to use the parent
+ * {@code context}'s default alert dialog theme
*/
- public Builder(Context context, int theme) {
+ public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
- context, resolveDialogTheme(context, theme)));
- mTheme = theme;
+ context, resolveDialogTheme(context, themeResId)));
+ mThemeResId = themeResId;
}
-
+
/**
* Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.
* Applications should use this Context for obtaining LayoutInflaters for inflating views
@@ -421,7 +497,7 @@
P.mTitle = P.mContext.getText(titleId);
return this;
}
-
+
/**
* Set the title displayed in the {@link Dialog}.
*
@@ -431,23 +507,28 @@
P.mTitle = title;
return this;
}
-
+
/**
- * Set the title using the custom view {@code customTitleView}. The
- * methods {@link #setTitle(int)} and {@link #setIcon(int)} should be
- * sufficient for most titles, but this is provided if the title needs
- * more customization. Using this will replace the title and icon set
- * via the other methods.
- *
- * @param customTitleView The custom view to use as the title.
+ * Set the title using the custom view {@code customTitleView}.
+ * <p>
+ * The methods {@link #setTitle(int)} and {@link #setIcon(int)} should
+ * be sufficient for most titles, but this is provided if the title
+ * needs more customization. Using this will replace the title and icon
+ * set via the other methods.
+ * <p>
+ * <strong>Note:</strong> To ensure consistent styling, the custom view
+ * should be inflated or constructed using the alert dialog's themed
+ * context obtained via {@link #getContext()}.
*
- * @return This Builder object to allow for chaining of calls to set methods
+ * @param customTitleView the custom view to use as the title
+ * @return this Builder object to allow for chaining of calls to set
+ * methods
*/
public Builder setCustomTitle(View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
-
+
/**
* Set the message to display using the given resource id.
*
@@ -457,7 +538,7 @@
P.mMessage = P.mContext.getText(messageId);
return this;
}
-
+
/**
* Set the message to display.
*
@@ -467,7 +548,7 @@
P.mMessage = message;
return this;
}
-
+
/**
* Set the resource id of the {@link Drawable} to be used in the title.
* <p>
@@ -479,11 +560,16 @@
P.mIconId = iconId;
return this;
}
-
+
/**
* Set the {@link Drawable} to be used in the title.
- *
- * @return This Builder object to allow for chaining of calls to set methods
+ * <p>
+ * <strong>Note:</strong> To ensure consistent styling, the drawable
+ * should be inflated or constructed using the alert dialog's themed
+ * context obtained via {@link #getContext()}.
+ *
+ * @return this Builder object to allow for chaining of calls to set
+ * methods
*/
public Builder setIcon(Drawable icon) {
P.mIcon = icon;
@@ -518,7 +604,7 @@
P.mPositiveButtonListener = listener;
return this;
}
-
+
/**
* Set a listener to be invoked when the positive button of the dialog is pressed.
* @param text The text to display in the positive button
@@ -531,7 +617,7 @@
P.mPositiveButtonListener = listener;
return this;
}
-
+
/**
* Set a listener to be invoked when the negative button of the dialog is pressed.
* @param textId The resource id of the text to display in the negative button
@@ -544,7 +630,7 @@
P.mNegativeButtonListener = listener;
return this;
}
-
+
/**
* Set a listener to be invoked when the negative button of the dialog is pressed.
* @param text The text to display in the negative button
@@ -557,7 +643,7 @@
P.mNegativeButtonListener = listener;
return this;
}
-
+
/**
* Set a listener to be invoked when the neutral button of the dialog is pressed.
* @param textId The resource id of the text to display in the neutral button
@@ -570,7 +656,7 @@
P.mNeutralButtonListener = listener;
return this;
}
-
+
/**
* Set a listener to be invoked when the neutral button of the dialog is pressed.
* @param text The text to display in the neutral button
@@ -583,7 +669,7 @@
P.mNeutralButtonListener = listener;
return this;
}
-
+
/**
* Sets whether the dialog is cancelable or not. Default is true.
*
@@ -593,7 +679,7 @@
P.mCancelable = cancelable;
return this;
}
-
+
/**
* Sets the callback that will be called if the dialog is canceled.
*
@@ -611,7 +697,7 @@
P.mOnCancelListener = onCancelListener;
return this;
}
-
+
/**
* Sets the callback that will be called when the dialog is dismissed for any reason.
*
@@ -631,7 +717,7 @@
P.mOnKeyListener = onKeyListener;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content, you will be notified of the
* selected item via the supplied listener. This should be an array type i.e. R.array.foo
@@ -643,7 +729,7 @@
P.mOnClickListener = listener;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content, you will be notified of the
* selected item via the supplied listener.
@@ -655,12 +741,12 @@
P.mOnClickListener = listener;
return this;
}
-
+
/**
* Set a list of items, which are supplied by the given {@link ListAdapter}, to be
* displayed in the dialog as the content, you will be notified of the
* selected item via the supplied listener.
- *
+ *
* @param adapter The {@link ListAdapter} to supply the list of items
* @param listener The listener that will be called when an item is clicked.
*
@@ -671,12 +757,12 @@
P.mOnClickListener = listener;
return this;
}
-
+
/**
* Set a list of items, which are supplied by the given {@link Cursor}, to be
* displayed in the dialog as the content, you will be notified of the
* selected item via the supplied listener.
- *
+ *
* @param cursor The {@link Cursor} to supply the list of items
* @param listener The listener that will be called when an item is clicked.
* @param labelColumn The column name on the cursor containing the string to display
@@ -691,7 +777,7 @@
P.mOnClickListener = listener;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content,
* you will be notified of the selected item via the supplied listener.
@@ -699,7 +785,7 @@
* a check mark displayed to the right of the text for each checked
* item. Clicking on an item in the list will not dismiss the dialog.
* Clicking on a button will dismiss the dialog.
- *
+ *
* @param itemsId the resource id of an array i.e. R.array.foo
* @param checkedItems specifies which items are checked. It should be null in which case no
* items are checked. If non null it must be exactly the same length as the array of
@@ -718,14 +804,14 @@
P.mIsMultiChoice = true;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content,
* you will be notified of the selected item via the supplied listener.
* The list will have a check mark displayed to the right of the text
* for each checked item. Clicking on an item in the list will not
* dismiss the dialog. Clicking on a button will dismiss the dialog.
- *
+ *
* @param items the text of the items to be displayed in the list.
* @param checkedItems specifies which items are checked. It should be null in which case no
* items are checked. If non null it must be exactly the same length as the array of
@@ -736,7 +822,7 @@
*
* @return This Builder object to allow for chaining of calls to set methods
*/
- public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,
+ public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,
final OnMultiChoiceClickListener listener) {
P.mItems = items;
P.mOnCheckboxClickListener = listener;
@@ -744,14 +830,14 @@
P.mIsMultiChoice = true;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content,
* you will be notified of the selected item via the supplied listener.
* The list will have a check mark displayed to the right of the text
* for each checked item. Clicking on an item in the list will not
* dismiss the dialog. Clicking on a button will dismiss the dialog.
- *
+ *
* @param cursor the cursor used to provide the items.
* @param isCheckedColumn specifies the column name on the cursor to use to determine
* whether a checkbox is checked or not. It must return an integer value where 1
@@ -764,7 +850,7 @@
*
* @return This Builder object to allow for chaining of calls to set methods
*/
- public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn,
+ public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn,
final OnMultiChoiceClickListener listener) {
P.mCursor = cursor;
P.mOnCheckboxClickListener = listener;
@@ -773,14 +859,14 @@
P.mIsMultiChoice = true;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content, you will be notified of
* the selected item via the supplied listener. This should be an array type i.e.
* R.array.foo The list will have a check mark displayed to the right of the text for the
* checked item. Clicking on an item in the list will not dismiss the dialog. Clicking on a
* button will dismiss the dialog.
- *
+ *
* @param itemsId the resource id of an array i.e. R.array.foo
* @param checkedItem specifies which item is checked. If -1 no items are checked.
* @param listener notified when an item on the list is clicked. The dialog will not be
@@ -797,13 +883,13 @@
P.mIsSingleChoice = true;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content, you will be notified of
* the selected item via the supplied listener. The list will have a check mark displayed to
* the right of the text for the checked item. Clicking on an item in the list will not
* dismiss the dialog. Clicking on a button will dismiss the dialog.
- *
+ *
* @param cursor the cursor to retrieve the items from.
* @param checkedItem specifies which item is checked. If -1 no items are checked.
* @param labelColumn The column name on the cursor containing the string to display in the
@@ -814,7 +900,7 @@
*
* @return This Builder object to allow for chaining of calls to set methods
*/
- public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn,
+ public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn,
final OnClickListener listener) {
P.mCursor = cursor;
P.mOnClickListener = listener;
@@ -823,13 +909,13 @@
P.mIsSingleChoice = true;
return this;
}
-
+
/**
* Set a list of items to be displayed in the dialog as the content, you will be notified of
* the selected item via the supplied listener. The list will have a check mark displayed to
* the right of the text for the checked item. Clicking on an item in the list will not
* dismiss the dialog. Clicking on a button will dismiss the dialog.
- *
+ *
* @param items the items to be displayed.
* @param checkedItem specifies which item is checked. If -1 no items are checked.
* @param listener notified when an item on the list is clicked. The dialog will not be
@@ -844,14 +930,14 @@
P.mCheckedItem = checkedItem;
P.mIsSingleChoice = true;
return this;
- }
-
+ }
+
/**
* Set a list of items to be displayed in the dialog as the content, you will be notified of
* the selected item via the supplied listener. The list will have a check mark displayed to
* the right of the text for the checked item. Clicking on an item in the list will not
* dismiss the dialog. Clicking on a button will dismiss the dialog.
- *
+ *
* @param adapter The {@link ListAdapter} to supply the list of items
* @param checkedItem specifies which item is checked. If -1 no items are checked.
* @param listener notified when an item on the list is clicked. The dialog will not be
@@ -867,26 +953,25 @@
P.mIsSingleChoice = true;
return this;
}
-
+
/**
* Sets a listener to be invoked when an item in the list is selected.
- *
- * @param listener The listener to be invoked.
- * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
*
- * @return This Builder object to allow for chaining of calls to set methods
+ * @param listener the listener to be invoked
+ * @return this Builder object to allow for chaining of calls to set methods
+ * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
*/
public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) {
P.mOnItemSelectedListener = listener;
return this;
}
-
+
/**
* Set a custom view resource to be the contents of the Dialog. The
* resource will be inflated, adding all top-level views to the screen.
*
* @param layoutResId Resource ID to be inflated.
- * @return This Builder object to allow for chaining of calls to set
+ * @return this Builder object to allow for chaining of calls to set
* methods
*/
public Builder setView(int layoutResId) {
@@ -897,12 +982,18 @@
}
/**
- * Set a custom view to be the contents of the Dialog. If the supplied view is an instance
- * of a {@link ListView} the light background will be used.
+ * Sets a custom view to be the contents of the alert dialog.
+ * <p>
+ * When using a pre-Holo theme, if the supplied view is an instance of
+ * a {@link ListView} then the light background will be used.
+ * <p>
+ * <strong>Note:</strong> To ensure consistent styling, the custom view
+ * should be inflated or constructed using the alert dialog's themed
+ * context obtained via {@link #getContext()}.
*
- * @param view The view to use as the contents of the Dialog.
- *
- * @return This Builder object to allow for chaining of calls to set methods
+ * @param view the view to use as the contents of the alert dialog
+ * @return this Builder object to allow for chaining of calls to set
+ * methods
*/
public Builder setView(View view) {
P.mView = view;
@@ -910,29 +1001,34 @@
P.mViewSpacingSpecified = false;
return this;
}
-
+
/**
- * Set a custom view to be the contents of the Dialog, specifying the
- * spacing to appear around that view. If the supplied view is an
- * instance of a {@link ListView} the light background will be used.
- *
- * @param view The view to use as the contents of the Dialog.
- * @param viewSpacingLeft Spacing between the left edge of the view and
- * the dialog frame
- * @param viewSpacingTop Spacing between the top edge of the view and
- * the dialog frame
- * @param viewSpacingRight Spacing between the right edge of the view
- * and the dialog frame
- * @param viewSpacingBottom Spacing between the bottom edge of the view
- * and the dialog frame
- * @return This Builder object to allow for chaining of calls to set
+ * Sets a custom view to be the contents of the alert dialog and
+ * specifies additional padding around that view.
+ * <p>
+ * When using a pre-Holo theme, if the supplied view is an instance of
+ * a {@link ListView} then the light background will be used.
+ * <p>
+ * <strong>Note:</strong> To ensure consistent styling, the custom view
+ * should be inflated or constructed using the alert dialog's themed
+ * context obtained via {@link #getContext()}.
+ *
+ * @param view the view to use as the contents of the alert dialog
+ * @param viewSpacingLeft spacing between the left edge of the view and
+ * the dialog frame
+ * @param viewSpacingTop spacing between the top edge of the view and
+ * the dialog frame
+ * @param viewSpacingRight spacing between the right edge of the view
+ * and the dialog frame
+ * @param viewSpacingBottom spacing between the bottom edge of the view
+ * and the dialog frame
+ * @return this Builder object to allow for chaining of calls to set
* methods
- *
- *
- * This is currently hidden because it seems like people should just
- * be able to put padding around the view.
- * @hide
+ *
+ * @hide Remove once the framework usages have been replaced.
+ * @deprecated Set the padding on the view itself.
*/
+ @Deprecated
public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop,
int viewSpacingRight, int viewSpacingBottom) {
P.mView = view;
@@ -944,15 +1040,18 @@
P.mViewSpacingBottom = viewSpacingBottom;
return this;
}
-
+
/**
- * Sets the Dialog to use the inverse background, regardless of what the
- * contents is.
- *
- * @param useInverseBackground Whether to use the inverse background
- *
- * @return This Builder object to allow for chaining of calls to set methods
+ * Sets the alert dialog to use the inverse background, regardless of
+ * what the contents is.
+ *
+ * @param useInverseBackground whether to use the inverse background
+ * @return this Builder object to allow for chaining of calls to set methods
+ * @deprecated This flag is only used for pre-Material themes. Instead,
+ * specify the window background using on the alert dialog
+ * theme.
*/
+ @Deprecated
public Builder setInverseBackgroundForced(boolean useInverseBackground) {
P.mForceInverseBackground = useInverseBackground;
return this;
@@ -968,13 +1067,15 @@
/**
- * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not
- * {@link Dialog#show()} the dialog. This allows the user to do any extra processing
- * before displaying the dialog. Use {@link #show()} if you don't have any other processing
- * to do and want this to be created and displayed.
+ * Creates an {@link AlertDialog} with the arguments supplied to this
+ * builder.
+ * <p>
+ * Calling this method does not display the dialog. If no additional
+ * processing is needed, {@link #show()} may be called instead to both
+ * create and display the dialog.
*/
public AlertDialog create() {
- final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
+ final AlertDialog dialog = new AlertDialog(P.mContext, mThemeResId);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
@@ -989,14 +1090,20 @@
}
/**
- * Creates a {@link AlertDialog} with the arguments supplied to this builder and
- * {@link Dialog#show()}'s the dialog.
+ * Creates an {@link AlertDialog} with the arguments supplied to this
+ * builder and immediately displays the dialog.
+ * <p>
+ * Calling this method is functionally identical to:
+ * <pre>
+ * AlertDialog dialog = builder.create();
+ * dialog.show();
+ * </pre>
*/
public AlertDialog show() {
- AlertDialog dialog = create();
+ final AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
-
+
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 503657b..eb27830 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,17 +16,9 @@
package android.app;
-import android.app.usage.IUsageStatsManager;
-import android.app.usage.UsageStatsManager;
-import android.appwidget.AppWidgetManager;
-import android.os.Build;
-import android.service.persistentdata.IPersistentDataBlockService;
-import android.service.persistentdata.PersistentDataBlockManager;
-
-import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
-import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -34,19 +26,15 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.IContentProvider;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IIntentReceiver;
import android.content.IntentSender;
-import android.content.IRestrictionsManager;
import android.content.ReceiverCallNotAllowedException;
-import android.content.RestrictionsManager;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ILauncherApps;
import android.content.pm.IPackageManager;
-import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
@@ -58,101 +46,28 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.hardware.ConsumerIrManager;
-import android.hardware.ISerialManager;
-import android.hardware.SerialManager;
-import android.hardware.SystemSensorManager;
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiControlService;
-import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManager;
-import android.hardware.usb.IUsbManager;
-import android.hardware.usb.UsbManager;
-import android.location.CountryDetector;
-import android.location.ICountryDetector;
-import android.location.ILocationManager;
-import android.location.LocationManager;
-import android.media.AudioManager;
-import android.media.MediaRouter;
-import android.media.midi.IMidiManager;
-import android.media.midi.MidiManager;
-import android.media.projection.MediaProjectionManager;
-import android.media.session.MediaSessionManager;
-import android.media.tv.ITvInputManager;
-import android.media.tv.TvInputManager;
-import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
-import android.net.EthernetManager;
-import android.net.IEthernetManager;
-import android.net.INetworkPolicyManager;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkScoreManager;
import android.net.Uri;
-import android.net.nsd.INsdManager;
-import android.net.nsd.NsdManager;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.WifiManager;
-import android.net.wifi.passpoint.IWifiPasspointManager;
-import android.net.wifi.passpoint.WifiPasspointManager;
-import android.net.wifi.p2p.IWifiP2pManager;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.IWifiScanner;
-import android.net.wifi.WifiScanner;
-import android.net.wifi.IRttManager;
-import android.net.wifi.RttManager;
-import android.nfc.NfcManager;
-import android.os.BatteryManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
-import android.os.DropBoxManager;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IPowerManager;
-import android.os.IUserManager;
import android.os.Looper;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.SystemVibrator;
-import android.os.UserManager;
import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
-import android.print.IPrintManager;
-import android.print.PrintManager;
-import android.service.fingerprint.IFingerprintService;
-import android.service.fingerprint.FingerprintManager;
-import android.telecom.TelecomManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.content.ClipboardManager;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
-import android.view.DisplayAdjustments;
-import android.view.ContextThemeWrapper;
import android.view.Display;
-import android.view.PhoneLayoutInflater;
-import android.view.WindowManagerImpl;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.CaptioningManager;
-import android.view.inputmethod.InputMethodManager;
-import android.view.textservice.TextServicesManager;
-import android.accounts.AccountManager;
-import android.accounts.IAccountManager;
-import android.app.admin.DevicePolicyManager;
-import android.app.job.IJobScheduler;
-import android.app.trust.TrustManager;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.IDropBoxManagerService;
+import android.view.DisplayAdjustments;
import java.io.File;
import java.io.FileInputStream;
@@ -160,8 +75,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
@@ -270,521 +183,8 @@
private static final String[] EMPTY_FILE_LIST = {};
- /**
- * Override this class when the system service constructor needs a
- * ContextImpl. Else, use StaticServiceFetcher below.
- */
- /*package*/ static class ServiceFetcher {
- int mContextCacheIndex = -1;
-
- /**
- * Main entrypoint; only override if you don't need caching.
- */
- public Object getService(ContextImpl ctx) {
- ArrayList<Object> cache = ctx.mServiceCache;
- Object service;
- synchronized (cache) {
- if (cache.size() == 0) {
- // Initialize the cache vector on first access.
- // At this point sNextPerContextServiceCacheIndex
- // is the number of potential services that are
- // cached per-Context.
- for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
- cache.add(null);
- }
- } else {
- service = cache.get(mContextCacheIndex);
- if (service != null) {
- return service;
- }
- }
- service = createService(ctx);
- cache.set(mContextCacheIndex, service);
- return service;
- }
- }
-
- /**
- * Override this to create a new per-Context instance of the
- * service. getService() will handle locking and caching.
- */
- public Object createService(ContextImpl ctx) {
- throw new RuntimeException("Not implemented");
- }
- }
-
- /**
- * Override this class for services to be cached process-wide.
- */
- abstract static class StaticServiceFetcher extends ServiceFetcher {
- private Object mCachedInstance;
-
- @Override
- public final Object getService(ContextImpl unused) {
- synchronized (StaticServiceFetcher.this) {
- Object service = mCachedInstance;
- if (service != null) {
- return service;
- }
- return mCachedInstance = createStaticService();
- }
- }
-
- public abstract Object createStaticService();
- }
-
- private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
- new HashMap<String, ServiceFetcher>();
-
- private static int sNextPerContextServiceCacheIndex = 0;
- private static void registerService(String serviceName, ServiceFetcher fetcher) {
- if (!(fetcher instanceof StaticServiceFetcher)) {
- fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
- }
- SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
- }
-
- // This one's defined separately and given a variable name so it
- // can be re-used by getWallpaperManager(), avoiding a HashMap
- // lookup.
- private static ServiceFetcher WALLPAPER_FETCHER = new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new WallpaperManager(ctx.getOuterContext(),
- ctx.mMainThread.getHandler());
- }};
-
- static {
- registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
- public Object getService(ContextImpl ctx) {
- return AccessibilityManager.getInstance(ctx);
- }});
-
- registerService(CAPTIONING_SERVICE, new ServiceFetcher() {
- public Object getService(ContextImpl ctx) {
- return new CaptioningManager(ctx);
- }});
-
- registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
- IAccountManager service = IAccountManager.Stub.asInterface(b);
- return new AccountManager(ctx, service);
- }});
-
- registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
- }});
-
- registerService(ALARM_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(ALARM_SERVICE);
- IAlarmManager service = IAlarmManager.Stub.asInterface(b);
- return new AlarmManager(service, ctx);
- }});
-
- registerService(AUDIO_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new AudioManager(ctx);
- }});
-
- registerService(MEDIA_ROUTER_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new MediaRouter(ctx);
- }});
-
- registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new BluetoothManager(ctx);
- }});
-
- registerService(HDMI_CONTROL_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
- IBinder b = ServiceManager.getService(HDMI_CONTROL_SERVICE);
- return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
- }});
-
- registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new ClipboardManager(ctx.getOuterContext(),
- ctx.mMainThread.getHandler());
- }});
-
- registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
- return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
- }});
-
- registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
- public Object createStaticService() {
- IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
- return new CountryDetector(ICountryDetector.Stub.asInterface(b));
- }});
-
- registerService(DEVICE_POLICY_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
- }});
-
- registerService(DOWNLOAD_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
- }});
-
- registerService(BATTERY_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new BatteryManager();
- }});
-
- registerService(NFC_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new NfcManager(ctx);
- }});
-
- registerService(DROPBOX_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
- return createDropBoxManager();
- }});
-
- registerService(INPUT_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
- return InputManager.getInstance();
- }});
-
- registerService(DISPLAY_SERVICE, new ServiceFetcher() {
- @Override
- public Object createService(ContextImpl ctx) {
- return new DisplayManager(ctx.getOuterContext());
- }});
-
- registerService(INPUT_METHOD_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
- return InputMethodManager.getInstance();
- }});
-
- registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return TextServicesManager.getInstance();
- }});
-
- registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
- public Object getService(ContextImpl ctx) {
- // TODO: why isn't this caching it? It wasn't
- // before, so I'm preserving the old behavior and
- // using getService(), instead of createService()
- // which would do the caching.
- return new KeyguardManager();
- }});
-
- registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new PhoneLayoutInflater(ctx.getOuterContext());
- }});
-
- registerService(LOCATION_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(LOCATION_SERVICE);
- return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
- }});
-
- registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
- @Override
- public Object createService(ContextImpl ctx) {
- return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
- ServiceManager.getService(NETWORK_POLICY_SERVICE)));
- }
- });
-
- registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- final Context outerContext = ctx.getOuterContext();
- return new NotificationManager(
- new ContextThemeWrapper(outerContext,
- Resources.selectSystemTheme(0,
- outerContext.getApplicationInfo().targetSdkVersion,
- com.android.internal.R.style.Theme_Dialog,
- com.android.internal.R.style.Theme_Holo_Dialog,
- com.android.internal.R.style.Theme_DeviceDefault_Dialog,
- com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
- ctx.mMainThread.getHandler());
- }});
-
- registerService(NSD_SERVICE, new ServiceFetcher() {
- @Override
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(NSD_SERVICE);
- INsdManager service = INsdManager.Stub.asInterface(b);
- return new NsdManager(ctx.getOuterContext(), service);
- }});
-
- // Note: this was previously cached in a static variable, but
- // constructed using mMainThread.getHandler(), so converting
- // it to be a regular Context-cached service...
- registerService(POWER_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(POWER_SERVICE);
- IPowerManager service = IPowerManager.Stub.asInterface(b);
- if (service == null) {
- Log.wtf(TAG, "Failed to get power manager service.");
- }
- return new PowerManager(ctx.getOuterContext(),
- service, ctx.mMainThread.getHandler());
- }});
-
- registerService(SEARCH_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new SearchManager(ctx.getOuterContext(),
- ctx.mMainThread.getHandler());
- }});
-
- registerService(SENSOR_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new SystemSensorManager(ctx.getOuterContext(),
- ctx.mMainThread.getHandler().getLooper());
- }});
-
- registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new StatusBarManager(ctx.getOuterContext());
- }});
-
- registerService(STORAGE_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- try {
- return new StorageManager(
- ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
- } catch (RemoteException rex) {
- Log.e(TAG, "Failed to create StorageManager", rex);
- return null;
- }
- }});
-
- registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new TelephonyManager(ctx.getOuterContext());
- }});
-
- registerService(TELEPHONY_SUBSCRIPTION_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new SubscriptionManager(ctx.getOuterContext());
- }});
-
- registerService(TELECOM_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new TelecomManager(ctx.getOuterContext());
- }});
-
- registerService(UI_MODE_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new UiModeManager();
- }});
-
- registerService(USB_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(USB_SERVICE);
- return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
- }});
-
- registerService(SERIAL_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(SERIAL_SERVICE);
- return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
- }});
-
- registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new SystemVibrator(ctx);
- }});
-
- registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
-
- registerService(WIFI_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(WIFI_SERVICE);
- IWifiManager service = IWifiManager.Stub.asInterface(b);
- return new WifiManager(ctx.getOuterContext(), service);
- }});
-
- registerService(WIFI_PASSPOINT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(WIFI_PASSPOINT_SERVICE);
- IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
- return new WifiPasspointManager(ctx.getOuterContext(), service);
- }});
-
- registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(WIFI_P2P_SERVICE);
- IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b);
- return new WifiP2pManager(service);
- }});
-
- registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
- IWifiScanner service = IWifiScanner.Stub.asInterface(b);
- return new WifiScanner(ctx.getOuterContext(), service);
- }});
-
- registerService(WIFI_RTT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(WIFI_RTT_SERVICE);
- IRttManager service = IRttManager.Stub.asInterface(b);
- return new RttManager(ctx.getOuterContext(), service);
- }});
-
- registerService(ETHERNET_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(ETHERNET_SERVICE);
- IEthernetManager service = IEthernetManager.Stub.asInterface(b);
- return new EthernetManager(ctx.getOuterContext(), service);
- }});
-
- registerService(WINDOW_SERVICE, new ServiceFetcher() {
- Display mDefaultDisplay;
- public Object getService(ContextImpl ctx) {
- Display display = ctx.mDisplay;
- if (display == null) {
- if (mDefaultDisplay == null) {
- DisplayManager dm = (DisplayManager)ctx.getOuterContext().
- getSystemService(Context.DISPLAY_SERVICE);
- mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
- }
- display = mDefaultDisplay;
- }
- return new WindowManagerImpl(display);
- }});
-
- registerService(USER_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(USER_SERVICE);
- IUserManager service = IUserManager.Stub.asInterface(b);
- return new UserManager(ctx, service);
- }});
-
- registerService(APP_OPS_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(APP_OPS_SERVICE);
- IAppOpsService service = IAppOpsService.Stub.asInterface(b);
- return new AppOpsManager(ctx, service);
- }});
-
- registerService(CAMERA_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new CameraManager(ctx);
- }
- });
-
- registerService(LAUNCHER_APPS_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(LAUNCHER_APPS_SERVICE);
- ILauncherApps service = ILauncherApps.Stub.asInterface(b);
- return new LauncherApps(ctx, service);
- }
- });
-
- registerService(RESTRICTIONS_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(RESTRICTIONS_SERVICE);
- IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
- return new RestrictionsManager(ctx, service);
- }
- });
- registerService(PRINT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
- IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
- return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
- UserHandle.getAppId(Process.myUid()));
- }});
-
- registerService(CONSUMER_IR_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new ConsumerIrManager(ctx);
- }});
-
- registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new MediaSessionManager(ctx);
- }
- });
-
- registerService(TRUST_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(TRUST_SERVICE);
- return new TrustManager(b);
- }
- });
-
- registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder binder = ServiceManager.getService(FINGERPRINT_SERVICE);
- IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
- return new FingerprintManager(ctx.getOuterContext(), service);
- }
- });
-
- registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
- ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
- return new TvInputManager(service, UserHandle.myUserId());
- }
- });
-
- registerService(NETWORK_SCORE_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new NetworkScoreManager(ctx);
- }
- });
-
- registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder iBinder = ServiceManager.getService(USAGE_STATS_SERVICE);
- IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
- return new UsageStatsManager(ctx.getOuterContext(), service);
- }
- });
-
- registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
- return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
- }});
-
- registerService(PERSISTENT_DATA_BLOCK_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(PERSISTENT_DATA_BLOCK_SERVICE);
- IPersistentDataBlockService persistentDataBlockService =
- IPersistentDataBlockService.Stub.asInterface(b);
- if (persistentDataBlockService != null) {
- return new PersistentDataBlockManager(persistentDataBlockService);
- } else {
- // not supported
- return null;
- }
- }
- });
-
- registerService(MEDIA_PROJECTION_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new MediaProjectionManager(ctx);
- }
- });
-
- registerService(APPWIDGET_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(APPWIDGET_SERVICE);
- return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
- }});
-
- registerService(MIDI_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(MIDI_SERVICE);
- return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
- }});
- }
+ // The system service cache for the system services that are cached per-ContextImpl.
+ final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
static ContextImpl getImpl(Context context) {
Context nextContext;
@@ -795,11 +195,6 @@
return (ContextImpl)context;
}
- // The system service cache for the system services that are
- // cached per-ContextImpl. Package-scoped to avoid accessor
- // methods.
- final ArrayList<Object> mServiceCache = new ArrayList<Object>();
-
@Override
public AssetManager getAssets() {
return getResources().getAssets();
@@ -914,6 +309,7 @@
throw new RuntimeException("Not supported in system context");
}
+ @Override
public File getSharedPrefsFile(String name) {
return makeFilename(getPreferencesDir(), name + ".xml");
}
@@ -1201,40 +597,51 @@
}
@Override
+ @Deprecated
public Drawable getWallpaper() {
return getWallpaperManager().getDrawable();
}
@Override
+ @Deprecated
public Drawable peekWallpaper() {
return getWallpaperManager().peekDrawable();
}
@Override
+ @Deprecated
public int getWallpaperDesiredMinimumWidth() {
return getWallpaperManager().getDesiredMinimumWidth();
}
@Override
+ @Deprecated
public int getWallpaperDesiredMinimumHeight() {
return getWallpaperManager().getDesiredMinimumHeight();
}
@Override
- public void setWallpaper(Bitmap bitmap) throws IOException {
+ @Deprecated
+ public void setWallpaper(Bitmap bitmap) throws IOException {
getWallpaperManager().setBitmap(bitmap);
}
@Override
+ @Deprecated
public void setWallpaper(InputStream data) throws IOException {
getWallpaperManager().setStream(data);
}
@Override
+ @Deprecated
public void clearWallpaper() throws IOException {
getWallpaperManager().clear();
}
+ private WallpaperManager getWallpaperManager() {
+ return getSystemService(WallpaperManager.class);
+ }
+
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
@@ -1506,6 +913,7 @@
}
@Override
+ @Deprecated
public void sendStickyBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1520,6 +928,7 @@
}
@Override
+ @Deprecated
public void sendStickyOrderedBroadcast(Intent intent,
BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
@@ -1554,6 +963,7 @@
}
@Override
+ @Deprecated
public void removeStickyBroadcast(Intent intent) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
if (resolvedType != null) {
@@ -1569,6 +979,7 @@
}
@Override
+ @Deprecated
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
@@ -1581,6 +992,7 @@
}
@Override
+ @Deprecated
public void sendStickyOrderedBroadcastAsUser(Intent intent,
UserHandle user, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
@@ -1614,6 +1026,7 @@
}
@Override
+ @Deprecated
public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
if (resolvedType != null) {
@@ -1850,25 +1263,12 @@
@Override
public Object getSystemService(String name) {
- ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
- return fetcher == null ? null : fetcher.getService(this);
+ return SystemServiceRegistry.getSystemService(this, name);
}
- private WallpaperManager getWallpaperManager() {
- return (WallpaperManager) WALLPAPER_FETCHER.getService(this);
- }
-
- /* package */ static DropBoxManager createDropBoxManager() {
- IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
- IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
- if (service == null) {
- // Don't return a DropBoxManager that will NPE upon use.
- // This also avoids caching a broken DropBoxManager in
- // getDropBoxManager during early boot, before the
- // DROPBOX_SERVICE is registered.
- return null;
- }
- return new DropBoxManager(service);
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
@Override
@@ -1937,6 +1337,7 @@
}
}
+ @Override
public void enforcePermission(
String permission, int pid, int uid, String message) {
enforce(permission,
@@ -1946,6 +1347,7 @@
message);
}
+ @Override
public void enforceCallingPermission(String permission, String message) {
enforce(permission,
checkCallingPermission(permission),
@@ -1954,6 +1356,7 @@
message);
}
+ @Override
public void enforceCallingOrSelfPermission(
String permission, String message) {
enforce(permission,
@@ -2091,6 +1494,7 @@
}
}
+ @Override
public void enforceUriPermission(
Uri uri, int pid, int uid, int modeFlags, String message) {
enforceForUri(
@@ -2098,6 +1502,7 @@
false, uid, uri, message);
}
+ @Override
public void enforceCallingUriPermission(
Uri uri, int modeFlags, String message) {
enforceForUri(
@@ -2106,6 +1511,7 @@
Binder.getCallingUid(), uri, message);
}
+ @Override
public void enforceCallingOrSelfUriPermission(
Uri uri, int modeFlags, String message) {
enforceForUri(
@@ -2114,6 +1520,7 @@
Binder.getCallingUid(), uri, message);
}
+ @Override
public void enforceUriPermission(
Uri uri, String readPermission, String writePermission,
int pid, int uid, int modeFlags, String message) {
@@ -2209,6 +1616,14 @@
mUser, mRestricted, display, null);
}
+ Display getDisplay() {
+ if (mDisplay != null) {
+ return mDisplay;
+ }
+ DisplayManager dm = getSystemService(DisplayManager.class);
+ return dm.getDisplay(Display.DEFAULT_DISPLAY);
+ }
+
private int getDisplayId() {
return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
}
@@ -2243,6 +1658,7 @@
}
/** {@hide} */
+ @Override
public int getUserId() {
return mUser.getIdentifier();
}
@@ -2368,6 +1784,7 @@
return mActivityToken;
}
+ @SuppressWarnings("deprecation")
static void setFilePermissionsFromMode(String name, int mode,
int extraPermissions) {
int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
new file mode 100644
index 0000000..993f416
--- /dev/null
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2015 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.app;
+
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.IDropBoxManagerService;
+
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.job.IJobScheduler;
+import android.app.job.JobScheduler;
+import android.app.trust.TrustManager;
+import android.app.usage.IUsageStatsManager;
+import android.app.usage.UsageStatsManager;
+import android.appwidget.AppWidgetManager;
+import android.bluetooth.BluetoothManager;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.IRestrictionsManager;
+import android.content.RestrictionsManager;
+import android.content.pm.ILauncherApps;
+import android.content.pm.LauncherApps;
+import android.content.res.Resources;
+import android.hardware.ConsumerIrManager;
+import android.hardware.ISerialManager;
+import android.hardware.SensorManager;
+import android.hardware.SerialManager;
+import android.hardware.SystemSensorManager;
+import android.hardware.camera2.CameraManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.IHdmiControlService;
+import android.hardware.input.InputManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbManager;
+import android.location.CountryDetector;
+import android.location.ICountryDetector;
+import android.location.ILocationManager;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.media.MediaRouter;
+import android.media.midi.IMidiManager;
+import android.media.midi.MidiManager;
+import android.media.projection.MediaProjectionManager;
+import android.media.session.MediaSessionManager;
+import android.media.tv.ITvInputManager;
+import android.media.tv.TvInputManager;
+import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.IConnectivityManager;
+import android.net.IEthernetManager;
+import android.net.INetworkPolicyManager;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkScoreManager;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
+import android.net.wifi.IRttManager;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.RttManager;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
+import android.net.wifi.p2p.IWifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.passpoint.IWifiPasspointManager;
+import android.net.wifi.passpoint.WifiPasspointManager;
+import android.nfc.NfcManager;
+import android.os.BatteryManager;
+import android.os.DropBoxManager;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.IUserManager;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemVibrator;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.Vibrator;
+import android.os.storage.StorageManager;
+import android.print.IPrintManager;
+import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.IFingerprintService;
+import android.service.persistentdata.IPersistentDataBlockService;
+import android.service.persistentdata.PersistentDataBlockManager;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.PhoneLayoutInflater;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
+import android.view.inputmethod.InputMethodManager;
+import android.view.textservice.TextServicesManager;
+
+import java.util.HashMap;
+
+/**
+ * Manages all of the system services that can be returned by {@link Context#getSystemService}.
+ * Used by {@link ContextImpl}.
+ */
+final class SystemServiceRegistry {
+ private final static String TAG = "SystemServiceRegistry";
+
+ // Service registry information.
+ // This information is never changed once static initialization has completed.
+ private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
+ new HashMap<Class<?>, String>();
+ private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
+ new HashMap<String, ServiceFetcher<?>>();
+ private static int sServiceCacheSize;
+
+ // Not instantiable.
+ private SystemServiceRegistry() { }
+
+ static {
+ registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
+ new CachedServiceFetcher<AccessibilityManager>() {
+ @Override
+ public AccessibilityManager createService(ContextImpl ctx) {
+ return AccessibilityManager.getInstance(ctx);
+ }});
+
+ registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
+ new CachedServiceFetcher<CaptioningManager>() {
+ @Override
+ public CaptioningManager createService(ContextImpl ctx) {
+ return new CaptioningManager(ctx);
+ }});
+
+ registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
+ new CachedServiceFetcher<AccountManager>() {
+ @Override
+ public AccountManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
+ IAccountManager service = IAccountManager.Stub.asInterface(b);
+ return new AccountManager(ctx, service);
+ }});
+
+ registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
+ new CachedServiceFetcher<ActivityManager>() {
+ @Override
+ public ActivityManager createService(ContextImpl ctx) {
+ return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
+ }});
+
+ registerService(Context.ALARM_SERVICE, AlarmManager.class,
+ new CachedServiceFetcher<AlarmManager>() {
+ @Override
+ public AlarmManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
+ IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+ return new AlarmManager(service, ctx);
+ }});
+
+ registerService(Context.AUDIO_SERVICE, AudioManager.class,
+ new CachedServiceFetcher<AudioManager>() {
+ @Override
+ public AudioManager createService(ContextImpl ctx) {
+ return new AudioManager(ctx);
+ }});
+
+ registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
+ new CachedServiceFetcher<MediaRouter>() {
+ @Override
+ public MediaRouter createService(ContextImpl ctx) {
+ return new MediaRouter(ctx);
+ }});
+
+ registerService(Context.BLUETOOTH_SERVICE, BluetoothManager.class,
+ new CachedServiceFetcher<BluetoothManager>() {
+ @Override
+ public BluetoothManager createService(ContextImpl ctx) {
+ return new BluetoothManager(ctx);
+ }});
+
+ registerService(Context.HDMI_CONTROL_SERVICE, HdmiControlManager.class,
+ new StaticServiceFetcher<HdmiControlManager>() {
+ @Override
+ public HdmiControlManager createService() {
+ IBinder b = ServiceManager.getService(Context.HDMI_CONTROL_SERVICE);
+ return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
+ }});
+
+ registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
+ new CachedServiceFetcher<ClipboardManager>() {
+ @Override
+ public ClipboardManager createService(ContextImpl ctx) {
+ return new ClipboardManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }});
+
+ // The clipboard service moved to a new package. If someone asks for the old
+ // interface by class then we want to redirect over to the new interface instead
+ // (which extends it).
+ SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
+
+ registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
+ new StaticServiceFetcher<ConnectivityManager>() {
+ @Override
+ public ConnectivityManager createService() {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+ }});
+
+ registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
+ new StaticServiceFetcher<CountryDetector>() {
+ @Override
+ public CountryDetector createService() {
+ IBinder b = ServiceManager.getService(Context.COUNTRY_DETECTOR);
+ return new CountryDetector(ICountryDetector.Stub.asInterface(b));
+ }});
+
+ registerService(Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class,
+ new CachedServiceFetcher<DevicePolicyManager>() {
+ @Override
+ public DevicePolicyManager createService(ContextImpl ctx) {
+ return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+ }});
+
+ registerService(Context.DOWNLOAD_SERVICE, DownloadManager.class,
+ new CachedServiceFetcher<DownloadManager>() {
+ @Override
+ public DownloadManager createService(ContextImpl ctx) {
+ return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+ }});
+
+ registerService(Context.BATTERY_SERVICE, BatteryManager.class,
+ new StaticServiceFetcher<BatteryManager>() {
+ @Override
+ public BatteryManager createService() {
+ return new BatteryManager();
+ }});
+
+ registerService(Context.NFC_SERVICE, NfcManager.class,
+ new CachedServiceFetcher<NfcManager>() {
+ @Override
+ public NfcManager createService(ContextImpl ctx) {
+ return new NfcManager(ctx);
+ }});
+
+ registerService(Context.DROPBOX_SERVICE, DropBoxManager.class,
+ new StaticServiceFetcher<DropBoxManager>() {
+ @Override
+ public DropBoxManager createService() {
+ IBinder b = ServiceManager.getService(Context.DROPBOX_SERVICE);
+ IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
+ if (service == null) {
+ // Don't return a DropBoxManager that will NPE upon use.
+ // This also avoids caching a broken DropBoxManager in
+ // getDropBoxManager during early boot, before the
+ // DROPBOX_SERVICE is registered.
+ return null;
+ }
+ return new DropBoxManager(service);
+ }});
+
+ registerService(Context.INPUT_SERVICE, InputManager.class,
+ new StaticServiceFetcher<InputManager>() {
+ @Override
+ public InputManager createService() {
+ return InputManager.getInstance();
+ }});
+
+ registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
+ new CachedServiceFetcher<DisplayManager>() {
+ @Override
+ public DisplayManager createService(ContextImpl ctx) {
+ return new DisplayManager(ctx.getOuterContext());
+ }});
+
+ registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
+ new StaticServiceFetcher<InputMethodManager>() {
+ @Override
+ public InputMethodManager createService() {
+ return InputMethodManager.getInstance();
+ }});
+
+ registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
+ new StaticServiceFetcher<TextServicesManager>() {
+ @Override
+ public TextServicesManager createService() {
+ return TextServicesManager.getInstance();
+ }});
+
+ registerService(Context.KEYGUARD_SERVICE, KeyguardManager.class,
+ new StaticServiceFetcher<KeyguardManager>() {
+ @Override
+ public KeyguardManager createService() {
+ return new KeyguardManager();
+ }});
+
+ registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
+ new CachedServiceFetcher<LayoutInflater>() {
+ @Override
+ public LayoutInflater createService(ContextImpl ctx) {
+ return new PhoneLayoutInflater(ctx.getOuterContext());
+ }});
+
+ registerService(Context.LOCATION_SERVICE, LocationManager.class,
+ new CachedServiceFetcher<LocationManager>() {
+ @Override
+ public LocationManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
+ return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
+ }});
+
+ registerService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class,
+ new StaticServiceFetcher<NetworkPolicyManager>() {
+ @Override
+ public NetworkPolicyManager createService() {
+ return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)));
+ }});
+
+ registerService(Context.NOTIFICATION_SERVICE, NotificationManager.class,
+ new CachedServiceFetcher<NotificationManager>() {
+ @Override
+ public NotificationManager createService(ContextImpl ctx) {
+ final Context outerContext = ctx.getOuterContext();
+ return new NotificationManager(
+ new ContextThemeWrapper(outerContext,
+ Resources.selectSystemTheme(0,
+ outerContext.getApplicationInfo().targetSdkVersion,
+ com.android.internal.R.style.Theme_Dialog,
+ com.android.internal.R.style.Theme_Holo_Dialog,
+ com.android.internal.R.style.Theme_DeviceDefault_Dialog,
+ com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
+ ctx.mMainThread.getHandler());
+ }});
+
+ registerService(Context.NSD_SERVICE, NsdManager.class,
+ new CachedServiceFetcher<NsdManager>() {
+ @Override
+ public NsdManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.NSD_SERVICE);
+ INsdManager service = INsdManager.Stub.asInterface(b);
+ return new NsdManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.POWER_SERVICE, PowerManager.class,
+ new CachedServiceFetcher<PowerManager>() {
+ @Override
+ public PowerManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
+ IPowerManager service = IPowerManager.Stub.asInterface(b);
+ if (service == null) {
+ Log.wtf(TAG, "Failed to get power manager service.");
+ }
+ return new PowerManager(ctx.getOuterContext(),
+ service, ctx.mMainThread.getHandler());
+ }});
+
+ registerService(Context.SEARCH_SERVICE, SearchManager.class,
+ new CachedServiceFetcher<SearchManager>() {
+ @Override
+ public SearchManager createService(ContextImpl ctx) {
+ return new SearchManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }});
+
+ registerService(Context.SENSOR_SERVICE, SensorManager.class,
+ new CachedServiceFetcher<SensorManager>() {
+ @Override
+ public SensorManager createService(ContextImpl ctx) {
+ return new SystemSensorManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler().getLooper());
+ }});
+
+ registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
+ new CachedServiceFetcher<StatusBarManager>() {
+ @Override
+ public StatusBarManager createService(ContextImpl ctx) {
+ return new StatusBarManager(ctx.getOuterContext());
+ }});
+
+ registerService(Context.STORAGE_SERVICE, StorageManager.class,
+ new CachedServiceFetcher<StorageManager>() {
+ @Override
+ public StorageManager createService(ContextImpl ctx) {
+ try {
+ return new StorageManager(
+ ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
+ } catch (RemoteException rex) {
+ Log.e(TAG, "Failed to create StorageManager", rex);
+ return null;
+ }
+ }});
+
+ registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
+ new CachedServiceFetcher<TelephonyManager>() {
+ @Override
+ public TelephonyManager createService(ContextImpl ctx) {
+ return new TelephonyManager(ctx.getOuterContext());
+ }});
+
+ registerService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+ new CachedServiceFetcher<SubscriptionManager>() {
+ @Override
+ public SubscriptionManager createService(ContextImpl ctx) {
+ return new SubscriptionManager(ctx.getOuterContext());
+ }});
+
+ registerService(Context.TELECOM_SERVICE, TelecomManager.class,
+ new CachedServiceFetcher<TelecomManager>() {
+ @Override
+ public TelecomManager createService(ContextImpl ctx) {
+ return new TelecomManager(ctx.getOuterContext());
+ }});
+
+ registerService(Context.UI_MODE_SERVICE, UiModeManager.class,
+ new CachedServiceFetcher<UiModeManager>() {
+ @Override
+ public UiModeManager createService(ContextImpl ctx) {
+ return new UiModeManager();
+ }});
+
+ registerService(Context.USB_SERVICE, UsbManager.class,
+ new CachedServiceFetcher<UsbManager>() {
+ @Override
+ public UsbManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+ return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
+ }});
+
+ registerService(Context.SERIAL_SERVICE, SerialManager.class,
+ new CachedServiceFetcher<SerialManager>() {
+ @Override
+ public SerialManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.SERIAL_SERVICE);
+ return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
+ }});
+
+ registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
+ new CachedServiceFetcher<Vibrator>() {
+ @Override
+ public Vibrator createService(ContextImpl ctx) {
+ return new SystemVibrator(ctx);
+ }});
+
+ registerService(Context.WALLPAPER_SERVICE, WallpaperManager.class,
+ new CachedServiceFetcher<WallpaperManager>() {
+ @Override
+ public WallpaperManager createService(ContextImpl ctx) {
+ return new WallpaperManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }});
+
+ registerService(Context.WIFI_SERVICE, WifiManager.class,
+ new CachedServiceFetcher<WifiManager>() {
+ @Override
+ public WifiManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.WIFI_SERVICE);
+ IWifiManager service = IWifiManager.Stub.asInterface(b);
+ return new WifiManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.WIFI_PASSPOINT_SERVICE, WifiPasspointManager.class,
+ new CachedServiceFetcher<WifiPasspointManager>() {
+ @Override
+ public WifiPasspointManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
+ IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
+ return new WifiPasspointManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
+ new StaticServiceFetcher<WifiP2pManager>() {
+ @Override
+ public WifiP2pManager createService() {
+ IBinder b = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
+ IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b);
+ return new WifiP2pManager(service);
+ }});
+
+ registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class,
+ new CachedServiceFetcher<WifiScanner>() {
+ @Override
+ public WifiScanner createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
+ IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+ return new WifiScanner(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
+ new CachedServiceFetcher<RttManager>() {
+ @Override
+ public RttManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.WIFI_RTT_SERVICE);
+ IRttManager service = IRttManager.Stub.asInterface(b);
+ return new RttManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
+ new CachedServiceFetcher<EthernetManager>() {
+ @Override
+ public EthernetManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.ETHERNET_SERVICE);
+ IEthernetManager service = IEthernetManager.Stub.asInterface(b);
+ return new EthernetManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.WINDOW_SERVICE, WindowManager.class,
+ new CachedServiceFetcher<WindowManager>() {
+ @Override
+ public WindowManager createService(ContextImpl ctx) {
+ return new WindowManagerImpl(ctx.getDisplay());
+ }});
+
+ registerService(Context.USER_SERVICE, UserManager.class,
+ new CachedServiceFetcher<UserManager>() {
+ @Override
+ public UserManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.USER_SERVICE);
+ IUserManager service = IUserManager.Stub.asInterface(b);
+ return new UserManager(ctx, service);
+ }});
+
+ registerService(Context.APP_OPS_SERVICE, AppOpsManager.class,
+ new CachedServiceFetcher<AppOpsManager>() {
+ @Override
+ public AppOpsManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ IAppOpsService service = IAppOpsService.Stub.asInterface(b);
+ return new AppOpsManager(ctx, service);
+ }});
+
+ registerService(Context.CAMERA_SERVICE, CameraManager.class,
+ new CachedServiceFetcher<CameraManager>() {
+ @Override
+ public CameraManager createService(ContextImpl ctx) {
+ return new CameraManager(ctx);
+ }});
+
+ registerService(Context.LAUNCHER_APPS_SERVICE, LauncherApps.class,
+ new CachedServiceFetcher<LauncherApps>() {
+ @Override
+ public LauncherApps createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE);
+ ILauncherApps service = ILauncherApps.Stub.asInterface(b);
+ return new LauncherApps(ctx, service);
+ }});
+
+ registerService(Context.RESTRICTIONS_SERVICE, RestrictionsManager.class,
+ new CachedServiceFetcher<RestrictionsManager>() {
+ @Override
+ public RestrictionsManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.RESTRICTIONS_SERVICE);
+ IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
+ return new RestrictionsManager(ctx, service);
+ }});
+
+ registerService(Context.PRINT_SERVICE, PrintManager.class,
+ new CachedServiceFetcher<PrintManager>() {
+ @Override
+ public PrintManager createService(ContextImpl ctx) {
+ IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
+ IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
+ return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
+ UserHandle.getAppId(Process.myUid()));
+ }});
+
+ registerService(Context.CONSUMER_IR_SERVICE, ConsumerIrManager.class,
+ new CachedServiceFetcher<ConsumerIrManager>() {
+ @Override
+ public ConsumerIrManager createService(ContextImpl ctx) {
+ return new ConsumerIrManager(ctx);
+ }});
+
+ registerService(Context.MEDIA_SESSION_SERVICE, MediaSessionManager.class,
+ new CachedServiceFetcher<MediaSessionManager>() {
+ @Override
+ public MediaSessionManager createService(ContextImpl ctx) {
+ return new MediaSessionManager(ctx);
+ }});
+
+ registerService(Context.TRUST_SERVICE, TrustManager.class,
+ new StaticServiceFetcher<TrustManager>() {
+ @Override
+ public TrustManager createService() {
+ IBinder b = ServiceManager.getService(Context.TRUST_SERVICE);
+ return new TrustManager(b);
+ }});
+
+ registerService(Context.FINGERPRINT_SERVICE, FingerprintManager.class,
+ new CachedServiceFetcher<FingerprintManager>() {
+ @Override
+ public FingerprintManager createService(ContextImpl ctx) {
+ IBinder binder = ServiceManager.getService(Context.FINGERPRINT_SERVICE);
+ IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
+ return new FingerprintManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
+ new StaticServiceFetcher<TvInputManager>() {
+ @Override
+ public TvInputManager createService() {
+ IBinder iBinder = ServiceManager.getService(Context.TV_INPUT_SERVICE);
+ ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
+ return new TvInputManager(service, UserHandle.myUserId());
+ }});
+
+ registerService(Context.NETWORK_SCORE_SERVICE, NetworkScoreManager.class,
+ new CachedServiceFetcher<NetworkScoreManager>() {
+ @Override
+ public NetworkScoreManager createService(ContextImpl ctx) {
+ return new NetworkScoreManager(ctx);
+ }});
+
+ registerService(Context.USAGE_STATS_SERVICE, UsageStatsManager.class,
+ new CachedServiceFetcher<UsageStatsManager>() {
+ @Override
+ public UsageStatsManager createService(ContextImpl ctx) {
+ IBinder iBinder = ServiceManager.getService(Context.USAGE_STATS_SERVICE);
+ IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
+ return new UsageStatsManager(ctx.getOuterContext(), service);
+ }});
+
+ registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
+ new StaticServiceFetcher<JobScheduler>() {
+ @Override
+ public JobScheduler createService() {
+ IBinder b = ServiceManager.getService(Context.JOB_SCHEDULER_SERVICE);
+ return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
+ }});
+
+ registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
+ new StaticServiceFetcher<PersistentDataBlockManager>() {
+ @Override
+ public PersistentDataBlockManager createService() {
+ IBinder b = ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+ IPersistentDataBlockService persistentDataBlockService =
+ IPersistentDataBlockService.Stub.asInterface(b);
+ if (persistentDataBlockService != null) {
+ return new PersistentDataBlockManager(persistentDataBlockService);
+ } else {
+ // not supported
+ return null;
+ }
+ }});
+
+ registerService(Context.MEDIA_PROJECTION_SERVICE, MediaProjectionManager.class,
+ new CachedServiceFetcher<MediaProjectionManager>() {
+ @Override
+ public MediaProjectionManager createService(ContextImpl ctx) {
+ return new MediaProjectionManager(ctx);
+ }});
+
+ registerService(Context.APPWIDGET_SERVICE, AppWidgetManager.class,
+ new CachedServiceFetcher<AppWidgetManager>() {
+ @Override
+ public AppWidgetManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+ return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
+ }});
+
+ registerService(Context.MIDI_SERVICE, MidiManager.class,
+ new CachedServiceFetcher<MidiManager>() {
+ @Override
+ public MidiManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.MIDI_SERVICE);
+ return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
+ }});
+ }
+
+ /**
+ * Creates an array which is used to cache per-Context service instances.
+ */
+ public static Object[] createServiceCache() {
+ return new Object[sServiceCacheSize];
+ }
+
+ /**
+ * Gets a system service from a given context.
+ */
+ public static Object getSystemService(ContextImpl ctx, String name) {
+ ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
+ return fetcher != null ? fetcher.getService(ctx) : null;
+ }
+
+ /**
+ * Gets the name of the system-level service that is represented by the specified class.
+ */
+ public static String getSystemServiceName(Class<?> serviceClass) {
+ return SYSTEM_SERVICE_NAMES.get(serviceClass);
+ }
+
+ /**
+ * Statically registers a system service with the context.
+ * This method must be called during static initialization only.
+ */
+ private static <T> void registerService(String serviceName, Class<T> serviceClass,
+ ServiceFetcher<T> serviceFetcher) {
+ SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
+ SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
+ }
+
+ /**
+ * Base interface for classes that fetch services.
+ * These objects must only be created during static initialization.
+ */
+ static abstract interface ServiceFetcher<T> {
+ T getService(ContextImpl ctx);
+ }
+
+ /**
+ * Override this class when the system service constructor needs a
+ * ContextImpl and should be cached and retained by that context.
+ */
+ static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
+ private final int mCacheIndex;
+
+ public CachedServiceFetcher() {
+ mCacheIndex = sServiceCacheSize++;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final T getService(ContextImpl ctx) {
+ final Object[] cache = ctx.mServiceCache;
+ synchronized (cache) {
+ // Fetch or create the service.
+ Object service = cache[mCacheIndex];
+ if (service == null) {
+ service = createService(ctx);
+ cache[mCacheIndex] = service;
+ }
+ return (T)service;
+ }
+ }
+
+ public abstract T createService(ContextImpl ctx);
+ }
+
+ /**
+ * Override this class when the system service does not need a ContextImpl
+ * and should be cached and retained process-wide.
+ */
+ static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
+ private T mCachedInstance;
+
+ @Override
+ public final T getService(ContextImpl unused) {
+ synchronized (StaticServiceFetcher.this) {
+ if (mCachedInstance == null) {
+ mCachedInstance = createService();
+ }
+ return mCachedInstance;
+ }
+ }
+
+ public abstract T createService();
+ }
+}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 7f9693f..7b84cb4 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -156,8 +156,8 @@
@Override
public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
- mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(
- MSG_CANCEL_RESULT, request));
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(
+ MSG_CANCEL_RESULT, request, null));
}
};
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 3074b49..d1e40ae 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -165,15 +165,24 @@
/** @hide */
public static class PolicyInfo {
public final int ident;
- final public String tag;
- final public int label;
- final public int description;
+ public final String tag;
+ public final int label;
+ public final int description;
+ public final int labelForSecondaryUsers;
+ public final int descriptionForSecondaryUsers;
- public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
- ident = identIn;
- tag = tagIn;
- label = labelIn;
- description = descriptionIn;
+ public PolicyInfo(int ident, String tag, int label, int description) {
+ this(ident, tag, label, description, label, description);
+ }
+
+ public PolicyInfo(int ident, String tag, int label, int description,
+ int labelForSecondaryUsers, int descriptionForSecondaryUsers) {
+ this.ident = ident;
+ this.tag = tag;
+ this.label = label;
+ this.description = description;
+ this.labelForSecondaryUsers = labelForSecondaryUsers;
+ this.descriptionForSecondaryUsers = descriptionForSecondaryUsers;
}
}
@@ -184,7 +193,10 @@
static {
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
com.android.internal.R.string.policylab_wipeData,
- com.android.internal.R.string.policydesc_wipeData));
+ com.android.internal.R.string.policydesc_wipeData,
+ com.android.internal.R.string.policylab_wipeData_secondaryUser,
+ com.android.internal.R.string.policydesc_wipeData_secondaryUser
+ ));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
com.android.internal.R.string.policylab_resetPassword,
com.android.internal.R.string.policydesc_resetPassword));
@@ -193,7 +205,10 @@
com.android.internal.R.string.policydesc_limitPassword));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
com.android.internal.R.string.policylab_watchLogin,
- com.android.internal.R.string.policydesc_watchLogin));
+ com.android.internal.R.string.policydesc_watchLogin,
+ com.android.internal.R.string.policylab_watchLogin,
+ com.android.internal.R.string.policydesc_watchLogin_secondaryUser
+ ));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
com.android.internal.R.string.policylab_forceLock,
com.android.internal.R.string.policydesc_forceLock));
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d0ebdbd..337bac5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -68,7 +68,7 @@
/**
* Public interface for managing policies enforced on a device. Most clients of this class must be
* registered with the system as a
- * <a href={@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
+ * <a href="{@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
* a device administrator may be registered as either a profile or device owner. A given method is
* accessible to all device administrators unless the documentation for that method specifies that
* it is restricted to either device or profile owners.
@@ -2710,6 +2710,7 @@
* <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
* then it's up to the TrustAgent itself to aggregate the values from all device admins.
* <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
+ * @hide
*/
public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
PersistableBundle configuration) {
@@ -2735,6 +2736,7 @@
* for this {@param agent} or calls it with a null configuration, null is returned.
* @param agent Which component to get enabled features for.
* @return configuration for the given trust agent.
+ * @hide
*/
public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
ComponentName agent) {
@@ -3305,7 +3307,8 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
*
* @see Activity#startLockTask()
- * @see DeviceAdminReceiver#onLockTaskModeChanged(Context, Intent, boolean, String)
+ * @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
+ * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
* @see UserManager#DISALLOW_CREATE_WINDOWS
*/
public void setLockTaskPackages(ComponentName admin, String[] packages)
@@ -3360,13 +3363,18 @@
* <li>{@link Settings.Global#ADB_ENABLED}</li>
* <li>{@link Settings.Global#AUTO_TIME}</li>
* <li>{@link Settings.Global#AUTO_TIME_ZONE}</li>
- * <li>{@link Settings.Global#BLUETOOTH_ON}</li>
+ * <li>{@link Settings.Global#BLUETOOTH_ON}
+ * Changing this setting has not effect as of {@link android.os.Build.VERSION_CODES#MNC}. Use
+ * {@link android.bluetooth.BluetoothAdapter#enable()} and
+ * {@link android.bluetooth.BluetoothAdapter#disable()} instead.</li>
* <li>{@link Settings.Global#DATA_ROAMING}</li>
* <li>{@link Settings.Global#DEVELOPMENT_SETTINGS_ENABLED}</li>
* <li>{@link Settings.Global#MODE_RINGER}</li>
* <li>{@link Settings.Global#NETWORK_PREFERENCE}</li>
* <li>{@link Settings.Global#USB_MASS_STORAGE_ENABLED}</li>
- * <li>{@link Settings.Global#WIFI_ON}</li>
+ * <li>{@link Settings.Global#WIFI_ON}
+ * Changing this setting has not effect as of {@link android.os.Build.VERSION_CODES#MNC}. Use
+ * {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
* <li>{@link Settings.Global#WIFI_SLEEP_POLICY}</li>
* </ul>
*
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 46ccc95..010c860 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -36,7 +36,6 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.media.MediaScannerConnection.OnScanCompletedListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
@@ -469,10 +468,10 @@
/**
* Retrieve styled attribute information in this Context's theme. See
- * {@link Resources.Theme#obtainStyledAttributes(int[])}
+ * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int[])}
* for more information.
*
- * @see Resources.Theme#obtainStyledAttributes(int[])
+ * @see android.content.res.Resources.Theme#obtainStyledAttributes(int[])
*/
public final TypedArray obtainStyledAttributes(
int[] attrs) {
@@ -481,10 +480,10 @@
/**
* Retrieve styled attribute information in this Context's theme. See
- * {@link Resources.Theme#obtainStyledAttributes(int, int[])}
+ * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])}
* for more information.
*
- * @see Resources.Theme#obtainStyledAttributes(int, int[])
+ * @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])
*/
public final TypedArray obtainStyledAttributes(
@StyleableRes int resid, int[] attrs) throws Resources.NotFoundException {
@@ -493,10 +492,10 @@
/**
* Retrieve styled attribute information in this Context's theme. See
- * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
+ * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
* for more information.
*
- * @see Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+ * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
*/
public final TypedArray obtainStyledAttributes(
AttributeSet set, int[] attrs) {
@@ -505,10 +504,10 @@
/**
* Retrieve styled attribute information in this Context's theme. See
- * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
+ * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
* for more information.
*
- * @see Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+ * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
*/
public final TypedArray obtainStyledAttributes(
AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
@@ -753,7 +752,8 @@
* are not automatically scanned by the media scanner, you can explicitly
* add them to the media database with
* {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[],
- * OnScanCompletedListener) MediaScannerConnection.scanFile}.
+ * android.media.MediaScannerConnection.OnScanCompletedListener)
+ * MediaScannerConnection.scanFile}.
* Note that this is not the same as
* {@link android.os.Environment#getExternalStoragePublicDirectory
* Environment.getExternalStoragePublicDirectory()}, which provides
@@ -1918,7 +1918,7 @@
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
*
- * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler
+ * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
* @see #sendBroadcast
* @see #unregisterReceiver
*/
@@ -2081,7 +2081,9 @@
* @hide
*/
@SystemApi
- public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, UserHandle user) {
+ @SuppressWarnings("unused")
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn,
+ int flags, UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -2316,6 +2318,51 @@
public abstract Object getSystemService(@ServiceName @NonNull String name);
/**
+ * Return the handle to a system-level service by class.
+ * <p>
+ * Currently available classes are:
+ * {@link android.view.WindowManager}, {@link android.view.LayoutInflater},
+ * {@link android.app.ActivityManager}, {@link android.os.PowerManager},
+ * {@link android.app.AlarmManager}, {@link android.app.NotificationManager},
+ * {@link android.app.KeyguardManager}, {@link android.location.LocationManager},
+ * {@link android.app.SearchManager}, {@link android.os.Vibrator},
+ * {@link android.net.ConnectivityManager},
+ * {@link android.net.wifi.WifiManager},
+ * {@link android.media.AudioManager}, {@link android.media.MediaRouter},
+ * {@link android.telephony.TelephonyManager}, {@link android.telephony.SubscriptionManager},
+ * {@link android.view.inputmethod.InputMethodManager},
+ * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
+ * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}.
+ * </p><p>
+ * Note: System services obtained via this API may be closely associated with
+ * the Context in which they are obtained from. In general, do not share the
+ * service objects between various different contexts (Activities, Applications,
+ * Services, Providers, etc.)
+ * </p>
+ *
+ * @param serviceClass The class of the desired service.
+ * @return The service or null if the class is not a supported system service.
+ */
+ @SuppressWarnings("unchecked")
+ public final <T> T getSystemService(Class<T> serviceClass) {
+ // Because subclasses may override getSystemService(String) we cannot
+ // perform a lookup by class alone. We must first map the class to its
+ // service name then invoke the string-based method.
+ String serviceName = getSystemServiceName(serviceClass);
+ return serviceName != null ? (T)getSystemService(serviceName) : null;
+ }
+
+ /**
+ * Gets the name of the system-level service that is represented by the specified class.
+ *
+ * @param serviceClass The class of the desired service.
+ * @return The service name or null if the class is not a supported system service.
+ *
+ * @hide
+ */
+ public abstract String getSystemServiceName(Class<?> serviceClass);
+
+ /**
* Use with {@link #getSystemService} to retrieve a
* {@link android.os.PowerManager} for controlling power management,
* including "wake locks," which let you keep the device on while
@@ -2610,7 +2657,7 @@
* of fingerprints.
*
* @see #getSystemService
- * @see android.app.FingerprintManager
+ * @see android.service.fingerprint.FingerprintManager
* @hide
*/
public static final String FINGERPRINT_SERVICE = "fingerprint";
@@ -2666,11 +2713,11 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.text.ClipboardManager} for accessing and modifying
+ * {@link android.content.ClipboardManager} for accessing and modifying
* the contents of the global clipboard.
*
* @see #getSystemService
- * @see android.text.ClipboardManager
+ * @see android.content.ClipboardManager
*/
public static final String CLIPBOARD_SERVICE = "clipboard";
@@ -2965,7 +3012,7 @@
* android.media.projection.MediaProjectionManager} instance for managing
* media projection sessions.
* @see #getSystemService
- * @see android.media.projection.ProjectionManager
+ * @see android.media.projection.MediaProjectionManager
*/
public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
@@ -3401,7 +3448,7 @@
* are not shared, however they share common state (Resources, ClassLoader,
* etc) so the Context instance itself is fairly lightweight.
*
- * <p>Throws {@link PackageManager.NameNotFoundException} if there is no
+ * <p>Throws {@link android.content.pm.PackageManager.NameNotFoundException} if there is no
* application with the given package name.
*
* <p>Throws {@link java.lang.SecurityException} if the Context requested
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index cfae1cf..6e8b7c1 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -284,36 +284,43 @@
}
@Override
+ @Deprecated
public Drawable getWallpaper() {
return mBase.getWallpaper();
}
@Override
+ @Deprecated
public Drawable peekWallpaper() {
return mBase.peekWallpaper();
}
@Override
+ @Deprecated
public int getWallpaperDesiredMinimumWidth() {
return mBase.getWallpaperDesiredMinimumWidth();
}
@Override
+ @Deprecated
public int getWallpaperDesiredMinimumHeight() {
return mBase.getWallpaperDesiredMinimumHeight();
}
@Override
+ @Deprecated
public void setWallpaper(Bitmap bitmap) throws IOException {
mBase.setWallpaper(bitmap);
}
@Override
+ @Deprecated
public void setWallpaper(InputStream data) throws IOException {
mBase.setWallpaper(data);
}
@Override
+ @Deprecated
public void clearWallpaper() throws IOException {
mBase.clearWallpaper();
}
@@ -445,11 +452,13 @@
}
@Override
+ @Deprecated
public void sendStickyBroadcast(Intent intent) {
mBase.sendStickyBroadcast(intent);
}
@Override
+ @Deprecated
public void sendStickyOrderedBroadcast(
Intent intent, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
@@ -460,16 +469,19 @@
}
@Override
+ @Deprecated
public void removeStickyBroadcast(Intent intent) {
mBase.removeStickyBroadcast(intent);
}
@Override
+ @Deprecated
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
mBase.sendStickyBroadcastAsUser(intent, user);
}
@Override
+ @Deprecated
public void sendStickyOrderedBroadcastAsUser(Intent intent,
UserHandle user, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
@@ -479,6 +491,7 @@
}
@Override
+ @Deprecated
public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
mBase.removeStickyBroadcastAsUser(intent, user);
}
@@ -563,6 +576,11 @@
}
@Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ return mBase.getSystemServiceName(serviceClass);
+ }
+
+ @Override
public int checkPermission(String permission, int pid, int uid) {
return mBase.checkPermission(permission, pid, uid);
}
@@ -679,6 +697,7 @@
}
/** @hide */
+ @Override
public Context createApplicationContext(ApplicationInfo application,
int flags) throws PackageManager.NameNotFoundException {
return mBase.createApplicationContext(application, flags);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e822708..e1a2aa9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -881,6 +881,13 @@
/**
* @hide
*/
+ public boolean isForwardLocked() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+ }
+
+ /**
+ * @hide
+ */
@Override protected ApplicationInfo getApplicationInfo() {
return this;
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b0e0300..1140756 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4405,6 +4405,13 @@
return false;
}
+ /**
+ * @hide
+ */
+ public boolean isForwardLocked() {
+ return applicationInfo.isForwardLocked();
+ }
+
public String toString() {
return "Package{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index bb162153..adab9be 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -132,6 +132,19 @@
float requestedRefreshRate, boolean inTraversal);
/**
+ * Applies an offset to the contents of a display, for example to avoid burn-in.
+ * <p>
+ * TODO: Technically this should be associated with a physical rather than logical
+ * display but this is good enough for now.
+ * </p>
+ *
+ * @param displayId The logical display id to update.
+ * @param x The X offset by which to shift the contents of the display.
+ * @param y The Y offset by which to shift the contents of the display.
+ */
+ public abstract void setDisplayOffsets(int displayId, int x, int y);
+
+ /**
* Describes the requested power state of the display.
*
* This object is intended to describe the general characteristics of the
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 537e993..bd5a3922 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -162,7 +162,15 @@
*/
public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
- private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+ private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+
+ /**
+ * @removed Was previously made visible by accident.
+ */
+ public BatteryManager() {
+ mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
+ ServiceManager.getService("batteryproperties"));
+ }
/**
* Query a battery property from the batteryproperties service.
@@ -174,12 +182,7 @@
long ret;
if (mBatteryPropertiesRegistrar == null) {
- IBinder b = ServiceManager.getService("batteryproperties");
- mBatteryPropertiesRegistrar =
- IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
- if (mBatteryPropertiesRegistrar == null)
- return Long.MIN_VALUE;
+ return Long.MIN_VALUE;
}
try {
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index a8c0c4c..797457a 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -23,6 +23,8 @@
* @hide
*/
oneway interface IVoiceInteractionSession {
+ void show(in Bundle sessionArgs, int flags);
+ void hide();
void handleAssist(in Bundle assistData);
void taskStarted(in Intent intent, int taskId);
void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 54a3a0a..0c01b25 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -71,7 +71,7 @@
public static final String SERVICE_META_DATA = "android.voice_interaction";
/**
- * Flag for use with {@link #startSession}: request that the session be started with
+ * Flag for use with {@link #showSession: request that the session be started with
* assist data from the currently focused activity.
*/
public static final int START_WITH_ASSIST = 1<<0;
@@ -139,20 +139,25 @@
}
/**
- * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}.
+ * Request that the associated {@link android.service.voice.VoiceInteractionSession} be
+ * shown to the user, starting it if necessary.
* @param args Arbitrary arguments that will be propagated to the session.
*/
- public void startSession(Bundle args, int flags) {
+ public void showSession(Bundle args, int flags) {
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
try {
- mSystemService.startSession(mInterface, args, flags);
+ mSystemService.showSession(mInterface, args, flags);
} catch (RemoteException e) {
}
}
/** @hide */
+ public void startSession(Bundle args, int flags) {
+ showSession(args, flags);
+ }
+ /** @hide */
public void startSession(Bundle args) {
startSession(args, 0);
}
@@ -174,7 +179,7 @@
/**
* Called during service initialization to tell you when the system is ready
* to receive interaction from it. You should generally do initialization here
- * rather than in {@link #onCreate}. Methods such as {@link #startSession} and
+ * rather than in {@link #onCreate}. Methods such as {@link #showSession} and
* {@link #createAlwaysOnHotwordDetector}
* will not be operational until this point.
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index a3a2ca1..4cf0e4c 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -53,10 +53,9 @@
/**
* An active voice interaction session, providing a facility for the implementation
- * to interact with the user in the voice interaction layer. This interface is no shown
- * by default, but you can request that it be shown with {@link #showWindow()}, which
- * will result in a later call to {@link #onCreateContentView()} in which the UI can be
- * built
+ * to interact with the user in the voice interaction layer. The user interface is
+ * initially shown by default, and can be created be overriding {@link #onCreateContentView()}
+ * in which the UI can be built.
*
* <p>A voice interaction session can be self-contained, ultimately calling {@link #finish}
* when done. It can also initiate voice interactions with applications by calling
@@ -151,6 +150,17 @@
final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
@Override
+ public void show(Bundle sessionArgs, int flags) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_SHOW,
+ flags, sessionArgs));
+ }
+
+ @Override
+ public void hide() {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE));
+ }
+
+ @Override
public void handleAssist(Bundle assistBundle) {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST,
assistBundle));
@@ -284,6 +294,8 @@
static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
static final int MSG_DESTROY = 103;
static final int MSG_HANDLE_ASSIST = 104;
+ static final int MSG_SHOW = 105;
+ static final int MSG_HIDE = 106;
class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
@@ -324,9 +336,8 @@
args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
break;
case MSG_CANCEL:
- args = (SomeArgs)msg.obj;
- if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
- onCancel((Request)args.arg1);
+ if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
+ onCancel((Request)msg.obj);
break;
case MSG_TASK_STARTED:
if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
@@ -350,6 +361,15 @@
if (DEBUG) Log.d(TAG, "onHandleAssist: " + (Bundle)msg.obj);
onHandleAssist((Bundle) msg.obj);
break;
+ case MSG_SHOW:
+ if (DEBUG) Log.d(TAG, "doShow: args=" + msg.obj
+ + " flags=" + msg.arg1);
+ doShow((Bundle) msg.obj, msg.arg1);
+ break;
+ case MSG_HIDE:
+ if (DEBUG) Log.d(TAG, "doHide");
+ doHide();
+ break;
}
}
@@ -457,6 +477,45 @@
onCreate(args, startFlags);
}
+ void doShow(Bundle args, int flags) {
+ if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+ + " mWindowVisible=" + mWindowVisible);
+
+ if (mInShowWindow) {
+ Log.w(TAG, "Re-entrance in to showWindow");
+ return;
+ }
+
+ try {
+ mInShowWindow = true;
+ if (!mWindowVisible) {
+ if (!mWindowAdded) {
+ mWindowAdded = true;
+ View v = onCreateContentView();
+ if (v != null) {
+ setContentView(v);
+ }
+ }
+ }
+ onShow(args, flags);
+ if (!mWindowVisible) {
+ mWindowVisible = true;
+ mWindow.show();
+ }
+ } finally {
+ mWindowWasVisible = true;
+ mInShowWindow = false;
+ }
+ }
+
+ void doHide() {
+ if (mWindowVisible) {
+ mWindow.hide();
+ mWindowVisible = false;
+ onHide();
+ }
+ }
+
void doDestroy() {
onDestroy();
if (mInitialized) {
@@ -484,41 +543,28 @@
mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
}
- public void showWindow() {
- if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
- + " mWindowVisible=" + mWindowVisible);
-
- if (mInShowWindow) {
- Log.w(TAG, "Re-entrance in to showWindow");
- return;
- }
-
+ public void show() {
try {
- mInShowWindow = true;
- if (!mWindowVisible) {
- mWindowVisible = true;
- if (!mWindowAdded) {
- mWindowAdded = true;
- View v = onCreateContentView();
- if (v != null) {
- setContentView(v);
- }
- }
- mWindow.show();
- }
- } finally {
- mWindowWasVisible = true;
- mInShowWindow = false;
+ mSystemService.showSessionFromSession(mToken, null, 0);
+ } catch (RemoteException e) {
}
}
- public void hideWindow() {
- if (mWindowVisible) {
- mWindow.hide();
- mWindowVisible = false;
+ public void hide() {
+ try {
+ mSystemService.hideSessionFromSession(mToken);
+ } catch (RemoteException e) {
}
}
+ /** TODO: remove */
+ public void showWindow() {
+ }
+
+ /** TODO: remove */
+ public void hideWindow() {
+ }
+
/**
* You can call this to customize the theme used by your IME's window.
* This must be set before {@link #onCreate}, so you
@@ -611,15 +657,33 @@
}
/**
- * Initiatize a new session.
+ * Initiatize a new session. The given args and showFlags are the initial values
+ * passed to {@link VoiceInteractionService#showSession VoiceInteractionService.showSession},
+ * if possible. Normally you should handle these in {@link #onShow}.
+ */
+ public void onCreate(Bundle args, int showFlags) {
+ onCreate(args);
+ }
+
+ /**
+ * Called when the session UI is going to be shown. This is called after
+ * {@link #onCreateContentView} (if the session's content UI needed to be created) and
+ * immediately prior to the window being shown. This may be called while the window
+ * is already shown, if a show request has come in while it is shown, to allow you to
+ * update the UI to match the new show arguments.
*
* @param args The arguments that were supplied to
- * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
- * @param startFlags The start flags originally provided to
- * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
+ * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+ * @param showFlags The show flags originally provided to
+ * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
*/
- public void onCreate(Bundle args, int startFlags) {
- onCreate(args);
+ public void onShow(Bundle args, int showFlags) {
+ }
+
+ /**
+ * Called immediately after stopping to show the session UI.
+ */
+ public void onHide() {
}
/**
@@ -663,7 +727,7 @@
}
public void onBackPressed() {
- finish();
+ hide();
}
/**
@@ -672,7 +736,7 @@
* calls {@link #finish}.
*/
public void onCloseSystemDialogs() {
- finish();
+ hide();
}
/**
@@ -717,7 +781,7 @@
* @param taskId Unique ID of the finished task.
*/
public void onTaskFinished(Intent intent, int taskId) {
- finish();
+ hide();
}
/**
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..8e9eb48 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -78,7 +78,10 @@
/**
* Bit field indicating that street addresses should be matched in methods that
- * take an options mask
+ * take an options mask. Note that this uses the
+ * {@link android.webkit.WebView#findAddress(String) findAddress()} method in
+ * {@link android.webkit.WebView} for finding addresses, which has various
+ * limitations.
*/
public static final int MAP_ADDRESSES = 0x08;
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 54a0025..0814101 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2006 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.
@@ -4171,12 +4172,6 @@
return mMediaController;
}
- private boolean isTranslucent() {
- TypedArray a = getWindowStyle();
- return a.getBoolean(a.getResourceId(
- R.styleable.Window_windowIsTranslucent, 0), false);
- }
-
@Override
public void setEnterTransition(Transition enterTransition) {
mEnterTransition = enterTransition;
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 84f0ee5..22e079c 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -34,10 +34,13 @@
import android.view.accessibility.AccessibilityNodeInfo;
/**
- * An extension to TextView that supports the {@link android.widget.Checkable} interface.
- * This is useful when used in a {@link android.widget.ListView ListView} where the it's
- * {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has been set to
- * something other than {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
+ * An extension to {@link TextView} that supports the {@link Checkable}
+ * interface and displays.
+ * <p>
+ * This is useful when used in a {@link android.widget.ListView ListView} where
+ * the {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has
+ * been set to something other than
+ * {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
*
* @attr ref android.R.styleable#CheckedTextView_checked
* @attr ref android.R.styleable#CheckedTextView_checkMark
@@ -116,9 +119,10 @@
}
/**
- * <p>Changes the checked state of this text view.</p>
+ * Sets the checked state of this view.
*
- * @param checked true to check the text, false to uncheck it
+ * @param checked {@code true} set the state to checked, {@code false} to
+ * uncheck
*/
public void setChecked(boolean checked) {
if (mChecked != checked) {
@@ -129,24 +133,24 @@
}
}
-
/**
- * Set the checkmark to a given Drawable, identified by its resourece id. This will be drawn
- * when {@link #isChecked()} is true.
+ * Sets the check mark to the drawable with the specified resource ID.
+ * <p>
+ * When this view is checked, the drawable's state set will include
+ * {@link android.R.attr#state_checked}.
*
- * @param resid The Drawable to use for the checkmark.
- *
+ * @param resId the resource identifier of drawable to use as the check
+ * mark
+ * @attr ref android.R.styleable#CheckedTextView_checkMark
* @see #setCheckMarkDrawable(Drawable)
* @see #getCheckMarkDrawable()
- *
- * @attr ref android.R.styleable#CheckedTextView_checkMark
*/
- public void setCheckMarkDrawable(@DrawableRes int resid) {
- if (resid != 0 && resid == mCheckMarkResource) {
+ public void setCheckMarkDrawable(@DrawableRes int resId) {
+ if (resId != 0 && resId == mCheckMarkResource) {
return;
}
- mCheckMarkResource = resid;
+ mCheckMarkResource = resId;
Drawable d = null;
if (mCheckMarkResource != 0) {
@@ -156,14 +160,15 @@
}
/**
- * Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true.
+ * Set the check mark to the specified drawable.
+ * <p>
+ * When this view is checked, the drawable's state set will include
+ * {@link android.R.attr#state_checked}.
*
- * @param d The Drawable to use for the checkmark.
- *
+ * @param d the drawable to use for the check mark
+ * @attr ref android.R.styleable#CheckedTextView_checkMark
* @see #setCheckMarkDrawable(int)
* @see #getCheckMarkDrawable()
- *
- * @attr ref android.R.styleable#CheckedTextView_checkMark
*/
public void setCheckMarkDrawable(Drawable d) {
if (mCheckMarkDrawable != null) {
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
old mode 100644
new mode 100755
index a053901..42bc7f2
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -112,8 +112,8 @@
mTempDate = getCalendarForLocale(mMaxDate, locale);
mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
- mMinDate.set(DEFAULT_START_YEAR, 1, 1);
- mMaxDate.set(DEFAULT_END_YEAR, 12, 31);
+ mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
+ mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
final Resources res = mDelegator.getResources();
final TypedArray a = mContext.obtainStyledAttributes(attrs,
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 6d90420..8f549a6 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,9 +26,11 @@
import android.service.voice.IVoiceInteractionSession;
interface IVoiceInteractionManagerService {
- void startSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
+ void showSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
IVoiceInteractor interactor);
+ boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags);
+ boolean hideSessionFromSession(IBinder token);
int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
void finish(IBinder token);
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d617c05..89990c2 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -19,6 +19,7 @@
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.content.Context;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -38,6 +39,7 @@
private static final String TAG = "SwipeDismissLayout";
private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
+ private boolean mUseDynamicTranslucency = true;
public interface OnDismissedListener {
void onDismissed(SwipeDismissLayout layout);
@@ -85,7 +87,7 @@
// and temporarily disables translucency when it is fully visible.
// As soon as the user starts swiping, we will re-enable
// translucency.
- if (getContext() instanceof Activity) {
+ if (mUseDynamicTranslucency && getContext() instanceof Activity) {
((Activity) getContext()).convertFromTranslucent();
}
}
@@ -117,6 +119,11 @@
android.R.integer.config_shortAnimTime);
mCancelInterpolator = new DecelerateInterpolator(1.5f);
mDismissInterpolator = new AccelerateInterpolator(1.5f);
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ com.android.internal.R.styleable.Theme);
+ mUseDynamicTranslucency = !a.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent);
+ a.recycle();
}
public void setOnDismissedListener(OnDismissedListener listener) {
@@ -230,7 +237,7 @@
mLastX = ev.getRawX();
updateSwiping(ev);
if (mSwiping) {
- if (getContext() instanceof Activity) {
+ if (mUseDynamicTranslucency && getContext() instanceof Activity) {
((Activity) getContext()).convertToTranslucent(null, null);
}
setProgress(ev.getRawX() - mDownX);
@@ -254,7 +261,7 @@
}
protected void cancel() {
- if (getContext() instanceof Activity) {
+ if (mUseDynamicTranslucency && getContext() instanceof Activity) {
((Activity) getContext()).convertFromTranslucent();
}
if (mProgressListener != null) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1dd10e1..28f1a3a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,7 +5,7 @@
LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 1afcf73..36f7963 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -160,7 +160,8 @@
android_eglGetDisplayInt
(JNIEnv *_env, jobject _this, jint display_id) {
- if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+ if (static_cast<uintptr_t>(display_id) !=
+ reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) {
jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
return 0;
}
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 713fff9..226162d 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -1935,7 +1935,11 @@
(GLsizei *)length,
(GLint *)size,
(GLenum *)type,
- (char *)name
+ // The cast below is incorrect. The driver will end up writing to the
+ // address specified by name, which will always crash the process since
+ // it is guaranteed to be in low memory. The additional static_cast
+ // suppresses the warning for now. http://b/19478262
+ (char *)static_cast<uintptr_t>(name)
);
if (_typeArray) {
releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -3643,7 +3647,7 @@
(GLenum)mode,
(GLsizei)count,
(GLenum)type,
- (GLvoid *)indicesOffset,
+ (GLvoid *)static_cast<uintptr_t>(indicesOffset),
(GLsizei)instanceCount
);
}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 2df13b7..6c95b8a 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -159,7 +159,7 @@
}
struct logger_list *logger_list = android_logger_list_open(
- LOG_ID_EVENTS, O_RDONLY | O_NONBLOCK, 0, 0);
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0);
if (!logger_list) {
jniThrowIOException(env, errno);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6094fd1..4b97138 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -300,6 +300,8 @@
<protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
<protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
+ <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6bb61a2..09103e3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -329,7 +329,9 @@
<attr name="windowOverscan" format="boolean" />
<!-- Flag indicating whether this is a floating window. -->
<attr name="windowIsFloating" format="boolean" />
- <!-- Flag indicating whether this is a translucent window. -->
+ <!-- Flag indicating whether this is a translucent window. If this attribute is unset (but
+ not if set to false), the window might still be considered translucent, if
+ windowSwipeToDismiss is set to true. -->
<attr name="windowIsTranslucent" format="boolean" />
<!-- Flag indicating that this window's background should be the
user's current wallpaper. Corresponds
@@ -455,7 +457,9 @@
<attr name="windowTranslucentNavigation" format="boolean" />
<!-- Flag to indicate that a window can be swiped away to be dismissed.
- Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS} -->
+ Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS}. It will also
+ dynamically change translucency of the window, if the windowIsTranslucent is not set.
+ If windowIsTranslucent is set (to either true or false) it will obey that setting. -->
<attr name="windowSwipeToDismiss" format="boolean" />
<!-- Flag indicating whether this window requests that content changes be performed
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4c0520e..fd8b803 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2074,4 +2074,23 @@
<!-- Scale factor threshold used by the screen magnifier to determine when to switch from
panning to scaling the magnification viewport. -->
<item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
+
+ <!-- If true, the display will be shifted around in ambient mode. -->
+ <bool name="config_enableBurnInProtection">false</bool>
+
+ <!-- Specifies the maximum burn-in offset displacement from the center. If -1, no maximum value
+ will be used. -->
+ <integer name="config_burnInProtectionMaxRadius">-1</integer>
+
+ <!-- Specifies the minimum burn-in offset horizontally. -->
+ <integer name="config_burnInProtectionMinHorizontalOffset">0</integer>
+
+ <!-- Specifies the maximum burn-in offset horizontally. -->
+ <integer name="config_burnInProtectionMaxHorizontalOffset">0</integer>
+
+ <!-- Specifies the minimum burn-in offset vertically. -->
+ <integer name="config_burnInProtectionMinVerticalOffset">0</integer>
+
+ <!-- Specifies the maximum burn-in offset vertically. -->
+ <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index af4922f..46e3d75 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2634,6 +2634,7 @@
<public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
<public type="style" name="Theme.Material.DayNight.Panel" />
<public type="style" name="Theme.Material.Light.LightStatusBar" />
+ <public type="style" name="ThemeOverlay.Material.Dialog" />
<!-- Context menu ID for the "Undo" menu item to undo the last text edit operation. -->
<public type="id" name="undo" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d95b17e..199b783 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2396,7 +2396,7 @@
<!-- Title of policy access to limiting the user's password choices -->
<string name="policylab_limitPassword">Set password rules</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords.</string>
+ <string name="policydesc_limitPassword">Control the length and the characters allowed in screen lock passwords and PINs.</string>
<!-- Title of policy access to watch user login attempts -->
<string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
<!-- Description of policy access to watch user login attempts -->
@@ -2411,15 +2411,24 @@
<string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
typed. when unlocking the screen, and lock the phone or erase all the phone\'s
data if too many incorrect passwords are typed.</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
+ typed when unlocking the screen, and lock the tablet or erase all this user\'s data
+ if too many incorrect passwords are typed.</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
+ typed when unlocking the screen, and lock the TV or erase all this user\'s data
+ if too many incorrect passwords are typed.</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
+ typed when unlocking the screen, and lock the phone or erase all this user\'s data
+ if too many incorrect passwords are typed.</string>
<!-- Title of policy access to reset user's password -->
- <string name="policylab_resetPassword">Change the screen-unlock password</string>
+ <string name="policylab_resetPassword">Change the screen lock</string>
<!-- Description of policy access to reset user's password -->
- <string name="policydesc_resetPassword">Change the screen-unlock password.</string>
+ <string name="policydesc_resetPassword">Change the screen lock.</string>
<!-- Title of policy access to force lock the device -->
<string name="policylab_forceLock">Lock the screen</string>
<!-- Description of policy access to limiting the user's password choices -->
<string name="policydesc_forceLock">Control how and when the screen locks.</string>
- <!-- Title of policy access to wipe the user's data -->
+ <!-- Title of policy access to wipe primary user's data -->
<string name="policylab_wipeData">Erase all data</string>
<!-- Description of policy access to wipe the user's data -->
<string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
@@ -2427,15 +2436,23 @@
<string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
<!-- Description of policy access to wipe the user's data -->
<string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
- <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+ <!-- Title of policy access to wipe secondary user's data -->
+ <string name="policylab_wipeData_secondaryUser">Erase user data</string>
<!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
+ <!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+ <!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
+ <!-- Title of policy access to set global proxy -->
+ <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+ <!-- Description of policy access to set global proxy -->
<string name="policydesc_setGlobalProxy">Set the device global proxy
- to be used while policy is enabled. Only the first device admin
- sets the effective global proxy.</string>
+ to be used while policy is enabled. Only the device owner can set the global proxy.</string>
<!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
- <string name="policylab_expirePassword">Set lock-screen password expiration</string>
+ <string name="policylab_expirePassword">Set screen lock password expiration</string>
<!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
- <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be changed.</string>
+ <string name="policydesc_expirePassword">Change how frequently the screen lock password, PIN, or pattern must be changed.</string>
<!-- Title of policy access to require encrypted storage [CHAR LIMIT=30]-->
<string name="policylab_encryptedStorage">Set storage encryption</string>
<!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]-->
@@ -2445,9 +2462,9 @@
<!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
<string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
<!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
- <string name="policylab_disableKeyguardFeatures">Disable features in keyguard</string>
+ <string name="policylab_disableKeyguardFeatures">Disable features of screen lock</string>
<!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
- <string name="policydesc_disableKeyguardFeatures">Prevent use of some features in keyguard.</string>
+ <string name="policydesc_disableKeyguardFeatures">Prevent use of some features of screen lock.</string>
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -5073,7 +5090,7 @@
<string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
<!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_forever">Indefinitely</string>
+ <string name="zen_mode_forever">Until you turn this off</string>
<!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
<string name="toolbar_collapse_description">Collapse</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index d75e496..9a64dec9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -513,9 +513,7 @@
<item name="background">@null</item>
</style>
- <style name="Widget.Material.ButtonBar.AlertDialog">
- <item name="background">@null</item>
- </style>
+ <style name="Widget.Material.ButtonBar.AlertDialog" />
<style name="Widget.Material.SearchView">
<item name="layout">@layout/search_view</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 615f445..39c0e8f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -254,6 +254,7 @@
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
<java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
<java-symbol type="bool" name="config_enable_puk_unlock_screen" />
+ <java-symbol type="bool" name="config_enableBurnInProtection" />
<java-symbol type="bool" name="config_hotswapCapable" />
<java-symbol type="bool" name="config_mms_content_disposition_support" />
<java-symbol type="bool" name="config_networkSamplingWakesDevice" />
@@ -344,6 +345,11 @@
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+ <java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_drawLockTimeoutMillis" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -754,7 +760,9 @@
<java-symbol type="string" name="policydesc_resetPassword" />
<java-symbol type="string" name="policydesc_setGlobalProxy" />
<java-symbol type="string" name="policydesc_watchLogin" />
+ <java-symbol type="string" name="policydesc_watchLogin_secondaryUser" />
<java-symbol type="string" name="policydesc_wipeData" />
+ <java-symbol type="string" name="policydesc_wipeData_secondaryUser" />
<java-symbol type="string" name="policydesc_disableKeyguardFeatures" />
<java-symbol type="string" name="policylab_disableCamera" />
<java-symbol type="string" name="policylab_encryptedStorage" />
@@ -765,6 +773,7 @@
<java-symbol type="string" name="policylab_setGlobalProxy" />
<java-symbol type="string" name="policylab_watchLogin" />
<java-symbol type="string" name="policylab_wipeData" />
+ <java-symbol type="string" name="policylab_wipeData_secondaryUser" />
<java-symbol type="string" name="policylab_disableKeyguardFeatures" />
<java-symbol type="string" name="postalTypeCustom" />
<java-symbol type="string" name="postalTypeHome" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 0107356..d496e18 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -174,14 +174,14 @@
<item name="windowSharedElementExitTransition">@transition/move</item>
<!-- Dialog attributes -->
- <item name="dialogTheme">@style/Theme.Material.Dialog</item>
+ <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
<!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>
+ <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog</item>
<item name="alertDialogStyle">@style/AlertDialog.Material</item>
<item name="alertDialogCenterButtons">false</item>
<item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
@@ -529,14 +529,14 @@
<item name="windowActivityTransitions">true</item>
<!-- Dialog attributes -->
- <item name="dialogTheme">@style/Theme.Material.Light.Dialog</item>
+ <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
<!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>
+ <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog</item>
<item name="alertDialogStyle">@style/AlertDialog.Material.Light</item>
<item name="alertDialogCenterButtons">false</item>
<item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
@@ -695,7 +695,7 @@
<item name="dividerVertical">?attr/listDivider</item>
<item name="dividerHorizontal">?attr/listDivider</item>
- <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar</item>
+ <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
<item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
<item name="segmentedButtonStyle">@style/Widget.Material.Light.SegmentedButton</item>
@@ -839,7 +839,7 @@
secondary text color, with the primary text color. -->
<style name="ThemeOverlay.Material.ActionBar">
<item name="colorControlNormal">?attr/textColorPrimary</item>
- <item name="searchViewStyle">@style/Widget.Material.Light.SearchView.ActionBar</item>
+ <item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
</style>
<!-- Theme overlay that replaces colors with their dark versions and replaces the normal
@@ -850,6 +850,34 @@
<item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
</style>
+ <!-- Theme overlay that overrides window properties to display as a dialog. -->
+ <style name="ThemeOverlay.Material.Dialog">
+ <item name="colorBackground">@color/background_floating_material_light</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+
+ <item name="windowFrame">@null</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
+ <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
+ <item name="windowBackground">@drawable/dialog_background_material</item>
+ <item name="windowElevation">@dimen/floating_window_z</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+
+ <item name="listPreferredItemPaddingLeft">?attr/dialogPreferredPadding</item>
+ <item name="listPreferredItemPaddingRight">?attr/dialogPreferredPadding</item>
+ <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
+ <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+
+ <item name="listDivider">@null</item>
+
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+
<!-- Variant of the material (dark) theme with no action bar. -->
<style name="Theme.Material.NoActionBar">
<item name="windowActionBar">false</item>
@@ -1033,12 +1061,6 @@
<item name="colorBackgroundCacheHint">@null</item>
- <item name="buttonBarStyle">@style/Widget.Material.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@style/Widget.Material.Button.Borderless</item>
-
- <item name="textAppearance">@style/TextAppearance.Material</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
-
<item name="listPreferredItemPaddingLeft">24dip</item>
<item name="listPreferredItemPaddingRight">24dip</item>
<item name="listPreferredItemPaddingStart">24dip</item>
@@ -1150,12 +1172,6 @@
<item name="colorBackgroundCacheHint">@null</item>
- <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@style/Widget.Material.Light.Button.Borderless</item>
-
- <item name="textAppearance">@style/TextAppearance.Material</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
-
<item name="listPreferredItemPaddingLeft">24dip</item>
<item name="listPreferredItemPaddingRight">24dip</item>
<item name="listPreferredItemPaddingStart">24dip</item>
@@ -1254,8 +1270,6 @@
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
- <item name="dialogTheme">@style/Theme.Material.Settings.Dialog</item>
- <item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
<item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
<item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
<item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 1ebc708..e730dff 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,9 +24,6 @@
<item name="windowBackground">@color/black</item>
<item name="windowContentOverlay">@null</item>
<item name="windowIsFloating">false</item>
- <!-- We need the windows to be translucent for SwipeToDismiss layout
- to work properly. -->
- <item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
<!-- Required to force windowInsets dispatch through application UI. -->
<item name="windowOverscan">true</item>
@@ -42,9 +39,6 @@
<item name="windowBackground">@color/white</item>
<item name="windowContentOverlay">@null</item>
<item name="windowIsFloating">false</item>
- <!-- We need the windows to be translucent for SwipeToDismiss layout
- to work properly. -->
- <item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
<!-- Required to force windowInsets dispatch through application UI. -->
<item name="windowOverscan">true</item>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index bed4b4d..45bd76a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -48,6 +48,11 @@
provided by the Device Administration API to provide stronger security for
employee devices that are powered by Android.</p>
+<p class="note"><strong>Note</strong> For information on building a Work Policy
+Controller for Android for Work deployments, see <a
+href="{@docRoot}training/enterprise/work-policy-ctrl.html">Building a Work
+Policy Controller</a>.</p>
+
<h2 id="overview">Device Administration API Overview</h2>
@@ -712,4 +717,4 @@
</pre>
<p>
See the Device Administration API sample for a complete example of how to enable storage encryption.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/images/enterprise/work-launcher.png b/docs/html/images/enterprise/work-launcher.png
new file mode 100644
index 0000000..3bbd835
--- /dev/null
+++ b/docs/html/images/enterprise/work-launcher.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 6fb906e..9caf938 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1186,5 +1186,21 @@
"training/multiscreen/index.html",
"training/monitoring-device-state/index.html"
]
+ },
+ "training/work/apps": {
+ "title": "",
+ "resources": [
+ "training/enterprise/app-compatibility.html",
+ "training/enterprise/app-restrictions.html",
+ "samples/AppRestrictionSchema/index.html",
+ "samples/AppRestrictionEnforcer/index.html"
+ ]
+ },
+ "training/work/admin": {
+ "title": "",
+ "resources": [
+ "training/enterprise/work-policy-ctrl.html",
+ "samples/BasicManagedProfile/index.html"
+ ]
}
}
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index d899ef3..45d1890 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -124,7 +124,7 @@
<li>If the SDK is not already installed, follow the setup wizard to install the SDK and any
necessary SDK tools.
<p class="note"><strong>Note:</strong> You may also need to install the ia32-libs,
- lib32ncurses5-dev, and lib32stc++6 packages. These packages are required to support 32-bit apps
+ lib32ncurses5-dev, and lib32stdc++6 packages. These packages are required to support 32-bit apps
on a 64-bit machine. </p>
</li>
</ol>
diff --git a/docs/html/tools/help/android.jd b/docs/html/tools/help/android.jd
index 19891e8..0d7d2aa 100644
--- a/docs/html/tools/help/android.jd
+++ b/docs/html/tools/help/android.jd
@@ -6,25 +6,26 @@
<p>{@code android} is an important development tool that lets you:</p>
<ul>
- <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href=
- "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command
-Line</a>.</li>
+ <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href=
+ "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command Line</a>.</li>
- <li>Create and update Android projects. See <a href=
+ <li>Create and update Android projects. See <a href=
"{@docRoot}tools/projects/projects-cmdline.html">Managing Projects from
the Command Line</a>.</li>
- <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href=
- "{@docRoot}sdk/exploring.html">Exploring the SDK</a>.</li>
- </ul>If you are using Eclipse, the <code>android</code> tool's features are integrated
- into ADT, so you should not need to use this tool directly.
-
+ <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href=
+ "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</li>
+ </ul>
+
+<p>If you are using Android Studio or Eclipse, the <code>android</code> tool's features are
+integrated into the IDE, so you should not need to use this tool directly. </p>
+
<p class="note"><strong>Note:</strong> The documentation of options below is not exhaustive
and may be out of date. For the most current list of options, execute <code>android
--help</code>.</p>
-
-
-
+
+
+
<h2>Syntax</h2>
<pre>android [global options] action [action options]</pre>
diff --git a/docs/html/tools/help/draw9patch.jd b/docs/html/tools/help/draw9patch.jd
index 859b1cf..7c26441 100644
--- a/docs/html/tools/help/draw9patch.jd
+++ b/docs/html/tools/help/draw9patch.jd
@@ -2,42 +2,50 @@
page.tags=NinePatch
@jd:body
-<p>The Draw 9-patch tool allows you to easily create a
- {@link android.graphics.NinePatch} graphic using a WYSIWYG editor.</p>
-<p>For an introduction to Nine-patch graphics and how they work, please read
-the section about Nine-patch in the
-<a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D Graphics</a>
+<p>The Draw 9-patch tool is a WYSIWYG editor that allows you to create bitmap images that
+automatically resize to accommodate the contents of the view and the size of the screen. Selected
+parts of the image are scaled horizontally or vertically based indicators drawn within the image. </p>
+<p>For an introduction to NinePatch graphics and how they work, please read
+the section about NinePatch Drawables in the
+<a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">Canvas and Drawables</a>
document.</p>
<img src="{@docRoot}images/draw9patch-norm.png" style="float:right" alt="" height="300" width="341"
/>
-<p>Here's a quick guide to create a Nine-patch graphic using the Draw 9-patch tool.
-You'll need the PNG image with which you'd like to create a NinePatch.</p>
+<p>Here's a quick guide to create a NinePatch graphic using the Draw 9-patch tool.
+You'll need the PNG image with which you'd like to create a NinePatch image.</p>
<ol>
- <li>From a terminal, launch the <code>draw9patch</code> application from your SDK
- <code>/tools</code> directory.
+ <li>From a terminal, run the <code>draw9patch</code> command from your SDK
+ <code>sdk/tools</code> directory to launch the Draw 9-patch tool.
</li>
- <li>Drag your PNG image into the Draw 9-patch window
+ <li>Drag your PNG image into the Draw 9-patch window
(or <strong>File</strong> > <strong>Open 9-patch...</strong> to locate the file).
Your workspace will now open.
<p>The left pane is your drawing area, in which you can edit the lines for the
- stretchable patches and content area. The right
+ stretchable patches and content area. The right
pane is the preview area, where you can preview your graphic when stretched.</p>
</li>
- <li>Click within the 1-pixel perimeter to draw the lines that define the stretchable
- patches and (optional) content area. Right-click (or hold Shift and click, on Mac) to erase
+ <li>Click within the 1-pixel perimeter to draw the lines that define the stretchable
+ patches and (optional) content area. Right-click (or hold Shift and click, on Mac) to erase
previously drawn lines.
</li>
<li>When done, select <strong>File</strong> > <strong>Save 9-patch...</strong>
<p>Your image will be saved with the <code>.9.png</code> file name.</p>
</li>
</ol>
- <p class="note"><strong>Note:</strong> A normal PNG file (<code>*.png</code>) will be
- loaded with an empty one-pixel border added around the image, in which you can draw
+
+ <p>To make sure that your NinePatch graphics scale down properly, verify that any
+ stretchable regions are at least 2x2 pixels in size.
+ Otherwise, they may disappear when scaled down. Also, provide one pixel of extra safe space in
+ the graphics before and after stretchable regions to avoid interpolation during scaling that may
+ cause the color at the boundaries to change. </p>
+
+ <p class="note"><strong>Note:</strong> A normal PNG file (<code>*.png</code>) will be
+ loaded with an empty one-pixel border added around the image, in which you can draw
the stretchable patches and content area.
- A previously saved 9-patch file (<code>*.9.png</code>) will be loaded as-is,
+ A previously saved NinePatch file (<code>*.9.png</code>) will be loaded as-is,
with no drawing area added, because it already exists.</p>
<img src="{@docRoot}images/draw9patch-bad.png" style="float:right;clear:both" alt="" height="300" width="341"
diff --git a/docs/html/training/enterprise/app-compatibility.jd b/docs/html/training/enterprise/app-compatibility.jd
index 1ae1ee3..216a799 100644
--- a/docs/html/training/enterprise/app-compatibility.jd
+++ b/docs/html/training/enterprise/app-compatibility.jd
@@ -1,4 +1,6 @@
page.title=Ensuring Compatibility with Managed Profiles
+page.metaDescription=Learn how to make sure your apps operate smoothly in a corporate environment by following some best practices.
+
@jd:body
<div id="tb-wrapper">
diff --git a/docs/html/training/enterprise/app-restrictions.jd b/docs/html/training/enterprise/app-restrictions.jd
new file mode 100644
index 0000000..fc5dfcc
--- /dev/null
+++ b/docs/html/training/enterprise/app-restrictions.jd
@@ -0,0 +1,351 @@
+page.title=Implementing App Restrictions
+page.metaDescription=Learn how to implement app restrictions and configuration settings that can be changed by other apps on the same device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#define_restrictions">Define App Restrictions</a></li>
+ <li><a href="#check_restrictions">Check App Restrictions</a></li>
+ <li><a href="#listen">Listen for App Restriction Changes</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+<h2>Resources</h2>
+<ul>
+ <li><a href="{@docRoot}samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a>
+ sample app</li>
+ <li><a href="{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+ sample app</li>
+</ul>
+
+</div>
+</div>
+
+<p>If you are developing apps for the enterprise market, you may need to satisfy
+particular requirements set by a company's policies. Application restrictions
+allow the enterprise administrator to remotely specify settings for apps.
+This capability is particularly useful for enterprise-approved apps deployed to
+a managed profile.</p>
+
+<p>For example, an enterprise might require that approved apps allow the
+enterprise administrator to:</p>
+
+<ul>
+ <li>Whitelist or blacklist URLs for a web browser</li>
+ <li>Configure whether an app is allowed to sync content via cellular, or just
+ by Wi-Fi</li>
+ <li>Configure the app's email settings</li>
+</ul>
+
+<p>
+ This guide shows how to implement these configuration settings in your app.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> For historical reasons, these configuration settings are known as
+ <em>restrictions,</em> and are implemented with files and classes that use this
+ term (such as {@link android.content.RestrictionsManager}). However, these
+ restrictions can actually implement a wide range of configuration options,
+ not just restrictions on app functionality.
+</p>
+
+<h2 id="overview">
+ Remote Configuration Overview
+</h2>
+
+<p>
+ Apps define the restrictions and configuration options that can be remotely
+ set by an administrator. These restrictions are
+ arbitrary configuration settings that can be changed by a restrictions
+ provider. If your app is running on an enterprise device's managed
+ profile, the enterprise administrator can change your app's restrictions.
+</p>
+
+<p>
+ The restrictions provider is another app running on the same device.
+ This app is typically controlled by the enterprise administrator. The
+ enterprise administrator communicates restriction changes to the restrictions
+ provider app. That app, in turn, changes the restrictions on your app.
+</p>
+
+<p>
+ To provide externally configurable restrictions:
+</p>
+
+<ul>
+ <li>Declare the restrictions in your app manifest. Doing so allows the
+ enterprise administrator to read the app's restrictions through Google
+ Play APIs.
+ </li>
+
+ <li>Whenever the app resumes, use the {@link
+ android.content.RestrictionsManager} object to check the current
+ restrictions, and change your app's UI and behavior to conform with those
+ restrictions.
+ </li>
+
+ <li>Listen for the
+ {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. When you receive this
+ broadcast, check the {@link android.content.RestrictionsManager} to see what
+ the current restrictions are, and make any necessary changes to your app's
+ behavior.
+ </li>
+</ul>
+
+<h2 id="define_restrictions">
+ Define App Restrictions
+</h2>
+
+<p>
+ Your app can support any restrictions you want to define. You declare the
+ app's restrictions in a <em>restrictions file</em>, and declare the
+ restrictions file in the manifest. Creating a restrictions file allows other
+ apps to examine the restrictions your app provides. Enterprise Mobility
+ Management (EMM) partners can read your app's restrictions by using Google
+ Play APIs.
+</p>
+
+<p>
+ To define your app's remote configuration options, put the following element
+ in your manifest's
+ <a href="{@docRoot}guide/topics/manifest/application-element.html">
+ <code><application></code></a> element:
+</p>
+
+<pre><meta-data android:name="android.content.APP_RESTRICTIONS"
+ android:resource="@xml/app_restrictions" />
+</pre>
+
+<p>
+ Create a file named <code>app_restrictions.xml</code> in your app's
+ <code>res/xml</code> directory. The structure of that file is described in
+ the reference for {@link android.content.RestrictionsManager}. The file has a
+ single top-level <code><restrictions></code> element, which contains
+ one <code><restriction></code> child element for every configuration
+ option the app has.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> Do not create localized versions of the restrictions
+ file. Your app is only allowed to have a single restrictions file,
+ so restrictions will be consistent for your app in all locales.
+</p>
+
+<p>
+ In an enterprise environment, an EMM will typically use the restrictions
+ schema to generate a remote console for IT administrators, so the
+ administrators can remotely configure your application.
+</p>
+
+<p>
+ For example, suppose your app can be remotely configured to allow or forbid
+ it to download data over a cellular connection. Your app could have a
+ <code><restriction></code> element like this:
+</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <restriction
+ android:key="downloadOnCellular"
+ android:title="App is allowed to download data via cellular"
+ android:restrictionType="bool"
+ android:description="If 'false', app can only download data via Wi-Fi"
+ android:defaultValue="true" />
+
+</restrictions>
+</pre>
+
+<p>
+ The supported types for the <code>android:restrictionType</code> element are
+ documented in the reference for {@link android.content.RestrictionsManager}.
+</p>
+
+<p>
+ You use each restriction's <code>android:key</code> attribute to read its
+ value from a restrictions bundle. For this reason, each restriction must have
+ a unique key string, and the string <em>cannot</em> be localized. It must be
+ specified with a string literal.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> In a production app, <code>android:title</code> and
+ <code>android:description</code> should be drawn from a localized resource
+ file, as described in <a href=
+ "{@docRoot}guide/topics/resources/localization.html">Localizing with
+ Resources</a>.
+</p>
+
+<p>
+ The restrictions provider can query the app to find details on the app's
+ available restrictions, including their description text. Restrictions
+ providers and enterprise administrators can change your app's restrictions at
+ any time, even when the app is not running.
+</p>
+
+<h2 id="check_restrictions">
+ Check App Restrictions
+</h2>
+
+<p>
+ Your app is not automatically notified when other apps change its restriction
+ settings. Instead, you need to check what the restrictions are when your app
+ starts or resumes, and listen for a system intent to find out if the
+ restrictions change while your app is running.
+</p>
+
+<p>
+ To find out the current restriction settings, your app uses a {@link
+ android.content.RestrictionsManager} object. Your app should check for the
+ current restrictions at the following times:
+</p>
+
+<ul>
+ <li>When the app starts or resumes, in its
+ {@link android.app.Activity#onResume onResume()} method
+ </li>
+
+ <li>When the app is notified of a restriction change, as described in
+ <a href="#listen">Listen for Device Configuration
+ Changes</a>
+ </li>
+</ul>
+
+<p>
+ To get a {@link android.content.RestrictionsManager} object, get the current
+ activity with {@link android.app.Fragment#getActivity getActivity()}, then
+ call that activity's {@link android.app.Activity#getSystemService
+ Activity.getSystemService()} method:
+</p>
+
+<pre>RestrictionsManager myRestrictionsMgr =
+ (RestrictionsManager) getActivity()
+ .getSystemService(Context.RESTRICTIONS_SERVICE);</pre>
+
+<p>
+ Once you have a {@link android.content.RestrictionsManager}, you can get the current restrictions
+ settings by calling its
+ {@link android.content.RestrictionsManager#getApplicationRestrictions
+ getApplicationRestrictions()} method:
+</p>
+
+<pre>Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();</pre>
+
+<p class="note">
+ <strong>Note:</strong> For convenience, you can also fetch the current
+ restrictions with a {@link android.os.UserManager}, by calling {@link
+ android.os.UserManager#getApplicationRestrictions
+ UserManager.getApplicationRestrictions()}. This method behaves exactly the
+ same as {@link android.content.RestrictionsManager#getApplicationRestrictions
+ RestrictionsManager.getApplicationRestrictions()}.
+</p>
+
+<p>
+ The {@link android.content.RestrictionsManager#getApplicationRestrictions
+ getApplicationRestrictions()} method requires reading from data storage, so
+ it should be done sparingly. Do not call this method every time you need to
+ know the current restrictions. Instead, you should call it once when your app
+ starts or resumes, and cache the fetched restrictions bundle. Then listen for
+ the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if restrictions
+ change while your app is active, as described in <a href="#listen">Listen for
+ Device Configuration Changes</a>.
+</p>
+
+<h3 id="read_restrictions">
+ Reading and applying restrictions
+</h3>
+
+<p>
+ The {@link android.content.RestrictionsManager#getApplicationRestrictions
+ getApplicationRestrictions()} method returns a {@link android.os.Bundle}
+ containing a key-value pair for each restriction that has been set. The
+ values are all of type <code>Boolean</code>, <code>int</code>,
+ <code>String</code>, and <code>String[]</code>. Once you have the
+ restrictions {@link android.os.Bundle}, you can check the current
+ restrictions settings with the standard {@link android.os.Bundle} methods for
+ those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
+ or
+ {@link android.os.Bundle#getString getString()}.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> The restrictions {@link android.os.Bundle} contains
+ one item for every restriction that has been explicitly set by a restrictions
+ provider. However, you <em>cannot</em> assume that a restriction will be
+ present in the bundle just because you defined a default value in the
+ restrictions XML file.
+</p>
+
+<p>
+ It is up to your app to take appropriate action based on the current
+ restrictions settings. For example, if your app has a restriction specifying
+ whether it can download data over a cellular connection, and you find that
+ the restriction is set to <code>false</code>, you would have to disable data
+ download except when the device has a Wi-Fi connection, as shown in the
+ following example code:
+</p>
+
+<pre>
+boolean appCanUseCellular;
+
+if appRestrictions.containsKey("downloadOnCellular") {
+ appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
+} else {
+ // here, cellularDefault is a boolean set with the restriction's
+ // default value
+ appCanUseCellular = cellularDefault;
+}
+
+if (!appCanUseCellular) {
+ // ...turn off app's cellular-download functionality
+ // ...show appropriate notices to user
+}</pre>
+
+<h2 id="listen">
+ Listen for App Restriction Changes
+</h2>
+
+<p>
+ Whenever an app's restrictions are changed, the system fires the
+ {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. Your app has to listen for
+ this intent so you can change the app's behavior when the restriction settings
+ change. The following code shows how to dynamically register a broadcast
+ receiver for this intent:
+</p>
+
+<pre>IntentFilter restrictionsFilter =
+ new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+
+BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+
+ // Get the current restrictions bundle
+ Bundle <code>appRestrictions</code> =
+
+ myRestrictionsMgr.getApplicationRestrictions();
+
+ // Check current restrictions settings, change your app's UI and
+ // functionality as necessary.
+
+ }
+
+};
+
+registerReceiver(restrictionsReceiver, restrictionsFilter);
+</pre>
+<p class="note">
+ <strong>Note:</strong> Ordinarily, your app does not need to be notified
+ about restriction changes when it is paused. Instead, you should unregister
+ your broadcast receiver when the app is paused. When the app resumes, you
+ first check for the current restrictions (as discussed in <a href=
+ "#check_restrictions">Check Device Restrictions</a>), then register your
+ broadcast receiver to make sure you're notified about restriction changes
+ that happen while the app is active.
+</p>
diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd
index 0ac68cc..10be14e 100644
--- a/docs/html/training/enterprise/index.jd
+++ b/docs/html/training/enterprise/index.jd
@@ -1,58 +1,67 @@
-page.title=Developing for Enterprise
-page.tags=policy,privacy
-
-trainingnavtop=true
-startpage=true
-next.title=Enhancing Security with Device Management Policies
-next.link=device-management-policy.html
+page.title=Building Apps for Work
+meta.tags="work, enterprise, corporate"
+page.tags="work", "enterprise", "corporate"
+page.metaDescription=Learn how to build Android apps for the enterprise and take advantage of Google's Android for Work program.
+page.tags="education"
+page.article=true
@jd:body
-<div id="tb-wrapper">
-<div id="tb">
+<img src="{@docRoot}images/enterprise/work-launcher.png"
+ width="300"
+ style="float:right;margin:0 0 20px 20px"
+ alt="Android for Work apps in a managed profile">
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.2 (API Level 8) or higher</li>
-</ul>
+<p>
+ The Android framework provides features to support the security, data separation, and
+ administration needs of a enterprise environment. As an app developer, you can make your app more
+ appealing to corporate customers by gracefully handling enterprise security and feature
+ restrictions. You can also modify your app so that technology administrators can remotely
+ configure it for use with enterprise resources.
+</p>
-<!-- related docs (NOT javadocs) -->
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a></li>
-</ul>
+<p>
+ To help businesses incorporate Android devices and apps into the workplace, Google provides the
+ <a href="http://www.google.com/work/android">Android for Work</a> program, which offers a suite
+ of APIs and services for device distribution and administration. Through this program companies
+ can connect with Enterprise Mobility Management (EMM) providers to help integrate Android with
+ their businesses.
+</p>
-<h2>Try it out</h2>
+<p>
+ For more information, follow the links below to learn how to update your Android app to support
+ the enterprise environment or build enterprise-specific solutions.
+</p>
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/DeviceManagement.zip"
-class="button">Download the sample</a>
- <p class="filename">DeviceManagement.zip</p>
-</div>
-</div>
+<h2 id="apps">App Development for Enterprises</h2>
+
+<p>
+ Learn how to make your app function smoothly in corporate environments that restrict device
+ features and data access. Go further to support enterprise use of your app by enabling
+ restrictions that corporate technology administrators can use to remotely configure your app:
+</p>
+
+<div class="dynamic-grid">
+ <div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/work/apps"
+ data-cardSizes="9x3"
+ data-maxResults="6">
+ </div>
</div>
-<p>In this class, you'll learn APIs and techniques you can use when developing applications
-for the enterprise.</p>
+<h2 id="admin">Device and App Administration</h2>
+<p>
+ Learn how to build policy controller apps that enable enterprise technology administrators
+ to manage devices, manage corporate apps, and provide access to company resources:
+</p>
-<h2>Lessons</h2>
-
-
-<dl>
- <dt><b><a href="device-management-policy.html">Enhancing Security with Device Management
-Policies</a></b></dt>
- <dd>In this lesson, you will learn how to create a security-aware application that manages
-access to its content by enforcing device management policies</dd>
-
- <dt><b><a href="app-compatibility.html">Ensuring Compatibility with Managed Profiles</a></b></dt>
-
- <dd>In this lesson, you will learn the best practices to follow to ensure
- that your app functions properly on devices that use <a
- href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed
- profiles</a></dd>
-
-</dl>
+<div class="dynamic-grid">
+ <div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/work/admin"
+ data-cardSizes="9x3"
+ data-maxResults="4">
+ </div>
+</div>
diff --git a/docs/html/training/enterprise/work-policy-ctrl.jd b/docs/html/training/enterprise/work-policy-ctrl.jd
new file mode 100644
index 0000000..5854e65
--- /dev/null
+++ b/docs/html/training/enterprise/work-policy-ctrl.jd
@@ -0,0 +1,339 @@
+page.title=Building a Work Policy Controller
+page.metaDescription=Learn how to develop a Work Policy Controller to create and administer a managed profile on an employee's device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#after_creating_profile">Create a Managed Profile</a></li>
+ <li><a href="#set_up_policies">Set Up Device Policies</a></li>
+ <li><a href="#apply_restrictions">Apply App Restrictions</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+
+<h2>
+ You should also read
+</h2>
+
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/admin/device-admin.html">Device
+ Administration</a>
+ </li>
+</ul>
+
+<h2>Resources</h2>
+<ul>
+
+ <li>
+ <a href=
+ "{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>
+ </li>
+
+ <li>
+ <a href=
+ "{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+ </li>
+</ul>
+
+</div>
+</div>
+
+
+<p>
+ In an Android for Work deployment, an enterprise needs to maintain control
+ over certain aspects of the employees' devices. The enterprise needs to
+ ensure that work-related information is encrypted and is kept separate from
+ employees' personal data. The enterprise may also need to limit device
+ capabilities, such as whether the device is allowed to use its camera. And
+ the enterprise may require that approved apps provide app restrictions, so
+ the enterprise can turn app capability on or off as needed.
+</p>
+
+<p>
+ To handle these tasks, an enterprise develops and deploys a Work Policy
+ Controller app. This app is installed on each employee's device. The
+ controller app installed on each employee's device and creates a work user
+ profile, which accesses enterprise apps and data separately from the user's
+ personal account. The controller app also acts as the
+ bridge between the enterprise's management software and the device; the
+ enterprise tells the controller app when it needs to make configuration
+ changes, and the controller app makes the appropriate settings changes for the
+ device and for other apps.
+</p>
+
+<p>
+ This lesson describes how to develop a Work Policy Controller app for devices
+ in an Android for Work deployment. The lesson describes how to create a work
+ user profile, how to set device policies, and how to apply
+ restrictions to other apps running on the managed profile.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> This lesson does not cover the situation where the
+ only profile on the device is the managed profile, under the enterprise's
+ control.
+</p>
+
+<h2 id="overview">Device Administration Overview</h2>
+
+<p>
+ In an Android for Work deployment, the enterprise administrator can set
+ policies to control the behavior of employees' devices and apps. The
+ enterprise administrator sets these policies with software provided by their
+ Enterprise Mobility Management (EMM) provider. The EMM software communicates
+ with a Work Policy Controller on each device. The Work Policy Controller, in
+ turn, manages the settings and behavior of the work user profile on each
+ individual’s device.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> A Work Policy Controller is built on the existing
+ model used for device administration applications, as described in <a href=
+ "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>.
+ In particular, your app needs to create a subclass of {@link
+ android.app.admin.DeviceAdminReceiver}, as described in that document.
+</p>
+
+<h3 id="managed_profiles">Managed profiles</h3>
+
+<p>
+ Users often want to use their personal devices in an enterprise setting. This
+ situation can present enterprises with a dilemma. If the user can use their
+ own device, the enterprise has to worry that confidential information (like
+ employee emails and contacts) are on a device the enterprise does not
+ control.
+</p>
+
+<p>
+ To address this situation, Android 5.0 (API level 21) allows enterprises to
+ set up a special work user profile using the Managed Profile API. This
+ user profile is called a <em>managed profile</em>, or a <em>work profile</em>
+ in the Android for Work program. If a device has a
+ managed profile for work, the profile's settings are under the control of the
+ enterprise administrator. The administrator can choose which apps are allowed
+ for that profile, and can control just what device features are available to
+ the profile.
+</p>
+
+<h2 id="create_profile">Create a Managed Profile</h2>
+
+<p>To create a managed profile on a device that already has a personal profile,
+first check that the device can support a managed profile, by seeing if the
+device supports the {@link
+android.content.pm.PackageManager#FEATURE_MANAGED_USERS FEATURE_MANAGED_USERS}
+system feature:</p>
+
+<pre>PackageManager pm = getPackageManager();
+if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
+
+ // This device does not support native managed profiles!
+
+}</pre>
+
+<p>If the device supports managed profiles, create one by sending an intent with
+an {@link android.app.admin.DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE
+ACTION_PROVISION_MANAGED_PROFILE} action. Include the device admin package
+name as an extra.</p>
+
+<pre>Activity provisioningActivity = getActivity();
+
+// You'll need the package name for the WPC app.
+String myWPCPackageName = "com.example.myWPCApp";
+
+// Set up the provisioning intent
+Intent provisioningIntent =
+ new Intent("android.app.action.PROVISION_MANAGED_PROFILE");
+intent.putExtra(myWPCPackageName,
+ provisioningActivity.getApplicationContext().getPackageName());
+
+if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager())
+ == null) {
+
+ // No handler for intent! Can't provision this device.
+ // Show an error message and cancel.
+} else {
+
+ // REQUEST_PROVISION_MANAGED_PROFILE is defined
+ // to be a suitable request code
+ startActivityForResult(provisioningIntent,
+ REQUEST_PROVISION_MANAGED_PROFILE);
+ provisioningActivity.finish();
+}</pre>
+
+<p>The system responds to this intent by doing the following:</p>
+
+<ul>
+ <li>Verifies that the device is encrypted. If it is not, the system prompts
+ the user to encrypt the device before proceeding.
+ </li>
+
+ <li>Creates a managed profile.
+ </li>
+
+ <li>Removes non-required applications from the managed profile.
+ </li>
+
+ <li>Copies the Work Policy Controller application into the managed profile and
+ sets it as the profile owner.
+ </li>
+</ul>
+
+<p>Override {@link android.app.Activity#onActivityResult onActivityResult()} to
+see whether the provisioning was successful, as shown in the following
+example code:</p>
+
+<pre>@Override
+public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+ // Check if this is the result of the provisioning activity
+ if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
+
+ // If provisioning was successful, the result code is
+ // Activity.RESULT_OK
+ if (resultCode == Activity.RESULT_OK) {
+ // Hurray! Managed profile created and provisioned!
+ } else {
+ // Boo! Provisioning failed!
+ }
+ return;
+
+ } else {
+ // This is the result of some other activity, call the superclass
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+}</pre>
+
+<h3 id="after_creating_profile">After Creating the Managed Profile</h3>
+
+<p>When the profile has been provisioned, the system calls the Work Policy
+Controller app's {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} method. Override this
+callback method to finish enabling the managed profile.</p>
+
+<p>Typically, your {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} callback implementation
+would perform these tasks:</p>
+
+<ul>
+ <li>Verify that the device is complying with the EMM's device policies, as
+ described in <a href="#set_up_policies">Set Up Device Policies</a>
+ </li>
+
+ <li>Enable any system applications that the administrator chooses to make
+ available within the managed profile, using {@link
+ android.app.admin.DevicePolicyManager#enableSystemApp
+ DevicePolicyManager.enableSystemApp()} </li>
+
+ <li>If the device uses Google Play for Work, add the Google account
+ to the managed profile with {@link android.accounts.AccountManager#addAccount
+ AccountManager.addAccount()}, so administrators can install
+ applications to the device
+ </li>
+</ul>
+
+<p>Once you have completed these tasks, call the device policy manager's
+{@link android.app.admin.DevicePolicyManager#setProfileEnabled
+setProfileEnabled()} method to activate the managed profile:</p>
+
+
+<pre>// Get the device policy manager
+DevicePolicyManager myDevicePolicyMgr =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ComponentName componentName = myDeviceAdminReceiver.getComponentName(this);
+
+// Set the name for the newly created managed profile.
+myDevicePolicyMgr.setProfileName(componentName, "My New Managed Profile");
+
+// ...and enable the profile
+manager.setProfileEnabled(componentName);</pre>
+
+<h2 id="set_up_policies">Set Up Device Policies</h2>
+
+<p>
+ The Work Policy Controller app is responsible for applying the enterprise's
+ device policies. For example, a particular enterprise might require that all
+ devices become locked after a certain number of failed attempts to enter the
+ device password. The controller app queries the EMM to find out what
+ the current policies are, then uses the <a href=
+ "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
+ API to apply those policies.
+</p>
+
+<p>For information on how to apply device policies, see the
+<a href="{@docRoot}guide/topics/admin/device-admin.html#policies">Device
+Administration</a> guide.</p>
+
+
+<h2 id="apply_restrictions">Apply App Restrictions</h2>
+
+<p>Enterprise environments may require that approved apps implement apps
+implement security or feature restrictions. App developers must implement these
+restrictions and declare them for use by enterprise administrators, as described
+in <a href="{@docRoot}training/enterprise/app-restrictions.html">Implementing
+App Restrictions</a>. The Work Policy Controller receives restriction changes
+from the enterprise administrator, and forwards those restriction changes to the
+apps.</p>
+
+<p>For example, a particular news app might have a restriction setting that
+controls whether the app is allowed to download videos over a cellular
+network. When the EMM wants to disable cellular downloads, it sends a
+notification to the controller app. The controller app, in turn,
+notifies the news app that the restriction setting has changed.</p>
+
+<p class="note"><strong>Note:</strong> This document covers how the Work Policy
+Controller app changes the restriction settings for the other apps on the
+managed profile. Details on how the Work Policy Controller app communicates with
+the EMM are out of scope for this document.</p>
+
+<p>To change an app's restrictions, call the {@link
+android.app.admin.DevicePolicyManager#setApplicationRestrictions
+DevicePolicyManager.setApplicationRestrictions()} method. This method is passed
+three parameters: the controller app's {@link
+android.app.admin.DeviceAdminReceiver}, the package name of the app whose
+restrictions are being changed, and a {@link android.os.Bundle Bundle} that
+contains the restrictions you want to set.</p>
+
+<p>For example, suppose there's an app on the managed profile with the package
+name <code>"com.example.newsfetcher"</code>. This app has a single boolean
+restriction that can be configured, with the key
+<code>"downloadByCellular"</code>. If this restriction is set to
+<code>false</code>, the newsfetcher app is not allowed to download data through
+a cellular network; it must use a Wi-Fi network instead.</p>
+
+<p>
+ If your Work Policy Controller app needs to turn off cellular downloads, it
+ would first fetch the device policy service object, as described above. It
+ then assembles a restrictions bundle and passes this bundle to {@link
+ android.app.admin.DevicePolicyManager#setApplicationRestrictions
+ setApplicationRestrictions()}:
+</p>
+
+<pre>// Fetch the DevicePolicyManager
+DevicePolicyManager myDevicePolicyMgr =
+ (DevicePolicyManager) thisActivity
+ .getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+// Set up the restrictions bundle
+bundle restrictionsBundle = new Bundle();
+restrictionsBundle.putBoolean("downloadByCellular", false);
+
+// Pass the restrictions to the policy manager. Assume the WPC app
+// already has a DeviceAdminReceiver defined (myDeviceAdminReceiver).
+myDevicePolicyMgr.setApplicationRestrictions(
+ myDeviceAdminReceiver, "com.example.newsfetcher", restrictionsBundle);</pre>
+
+
+<p class="note"><strong>Note:</strong> The device policy service conveys the restrictions
+change to the app you name. However, it is up to that app to actually implement
+the restriction. For example, in this case, the app would be responsible for
+disabling its ability to use cellular networks for video downloads. Setting the
+restriction does not cause the system to enforce this restriction on the app.
+For more information, see <a href="{@docRoot}training/enterprise/app-
+restrictions.html">Implementing App Restrictions</a>.</p>
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index efc0ee3..86e91a7 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -46,9 +46,10 @@
background as:</p>
<ul>
-<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple</li>
+<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple.</li>
<li><code>?android:attr/selectableItemBackgroundBorderless</code> for a ripple that extends beyond
-the view</li>
+the view. It will be drawn upon, and bounded by, the nearest parent of the view with a non-null
+background.</li>
</ul>
<p class="note"><strong>Note:</strong> <code>selectableItemBackgroundBorderless</code> is a new
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index c59d8ff..89e72f1 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1040,6 +1040,32 @@
<!-- End: Building for Auto -->
+ <!-- Start: Building for Work -->
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/enterprise/index.html">
+ <span class="small">Building Apps for</span><br/>
+ Work
+ </a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
+ Ensuring Compatibility with Managed Profiles
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/enterprise/app-restrictions.html">
+ Implementing App Restrictions
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/enterprise/work-policy-ctrl.html">
+ Building a Work Policy Controller
+ </a>
+ </li>
+ </ul>
+ </li>
+ <!-- End: Building for Work -->
+
+
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/best-ux.html">
@@ -1752,10 +1778,6 @@
Enhancing Security with Device Management Policies
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
- Ensuring Compatibility with Managed Profiles
- </a>
- </li>
</ul>
</li>
</ul>
@@ -1887,4 +1909,4 @@
buildToggleLists();
changeNavLang(getLangPref());
//-->
-</script>
\ No newline at end of file
+</script>
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index db94d89..24e0d6a 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -37,38 +37,47 @@
/**
* @hide
*/
-public class AnimatedRotateDrawable extends DrawableWrapper implements Runnable, Animatable {
+public class AnimatedRotateDrawable extends DrawableWrapper implements Animatable {
private AnimatedRotateState mState;
private float mCurrentDegrees;
private float mIncrement;
+
+ /** Whether this drawable is currently animating. */
private boolean mRunning;
+ /**
+ * Creates a new animated rotating drawable with no wrapped drawable.
+ */
public AnimatedRotateDrawable() {
this(new AnimatedRotateState(null), null);
}
@Override
public void draw(Canvas canvas) {
- int saveCount = canvas.save();
+ final Drawable drawable = getDrawable();
+ final Rect bounds = drawable.getBounds();
+ final int w = bounds.right - bounds.left;
+ final int h = bounds.bottom - bounds.top;
final AnimatedRotateState st = mState;
- final Drawable drawable = st.mDrawable;
- final Rect bounds = drawable.getBounds();
+ final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+ final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
- int w = bounds.right - bounds.left;
- int h = bounds.bottom - bounds.top;
-
- float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
- float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
-
+ final int saveCount = canvas.save();
canvas.rotate(mCurrentDegrees, px + bounds.left, py + bounds.top);
-
drawable.draw(canvas);
-
canvas.restoreToCount(saveCount);
}
+ /**
+ * Starts the rotation animation.
+ * <p>
+ * The animation will run until {@link #stop()} is called. Calling this
+ * method while the animation is already running has no effect.
+ *
+ * @see #stop()
+ */
@Override
public void start() {
if (!mRunning) {
@@ -77,10 +86,15 @@
}
}
+ /**
+ * Stops the rotation animation.
+ *
+ * @see #start()
+ */
@Override
public void stop() {
mRunning = false;
- unscheduleSelf(this);
+ unscheduleSelf(mNextFrame);
}
@Override
@@ -89,20 +103,8 @@
}
private void nextFrame() {
- unscheduleSelf(this);
- scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
- }
-
- @Override
- public void run() {
- // TODO: This should be computed in draw(Canvas), based on the amount
- // of time since the last frame drawn
- mCurrentDegrees += mIncrement;
- if (mCurrentDegrees > (360.0f - mIncrement)) {
- mCurrentDegrees = 0.0f;
- }
- invalidateSelf();
- nextFrame();
+ unscheduleSelf(mNextFrame);
+ scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + mState.mFrameDuration);
}
@Override
@@ -114,7 +116,7 @@
nextFrame();
}
} else {
- unscheduleSelf(this);
+ unscheduleSelf(mNextFrame);
}
return changed;
}
@@ -208,11 +210,6 @@
}
static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState {
- Drawable mDrawable;
- int[] mThemeAttrs;
-
- int mChangingConfigurations;
-
boolean mPivotXRel = false;
float mPivotX = 0;
boolean mPivotYRel = false;
@@ -220,9 +217,6 @@
int mFrameDuration = 150;
int mFramesCount = 12;
- private boolean mCanConstantState;
- private boolean mCheckedConstantState;
-
public AnimatedRotateState(AnimatedRotateState orig) {
super(orig);
@@ -240,26 +234,6 @@
public Drawable newDrawable(Resources res) {
return new AnimatedRotateDrawable(this, res);
}
-
- @Override
- public boolean canApplyTheme() {
- return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
- || super.canApplyTheme();
- }
-
- @Override
- public int getChangingConfigurations() {
- return mChangingConfigurations;
- }
-
- public boolean canConstantState() {
- if (!mCheckedConstantState) {
- mCanConstantState = mDrawable.getConstantState() != null;
- mCheckedConstantState = true;
- }
-
- return mCanConstantState;
- }
}
private AnimatedRotateDrawable(AnimatedRotateState state, Resources res) {
@@ -276,7 +250,7 @@
// Force the wrapped drawable to use filtering and AA, if applicable,
// so that it looks smooth when rotated.
- final Drawable drawable = state.mDrawable;
+ final Drawable drawable = getDrawable();
if (drawable != null) {
drawable.setFilterBitmap(true);
if (drawable instanceof BitmapDrawable) {
@@ -284,4 +258,18 @@
}
}
}
+
+ private final Runnable mNextFrame = new Runnable() {
+ @Override
+ public void run() {
+ // TODO: This should be computed in draw(Canvas), based on the amount
+ // of time since the last frame drawn
+ mCurrentDegrees += mIncrement;
+ if (mCurrentDegrees > (360.0f - mIncrement)) {
+ mCurrentDegrees = 0.0f;
+ }
+ invalidateSelf();
+ nextFrame();
+ }
+ };
}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 74ff1b0..5ccb165 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -31,20 +31,23 @@
import android.util.AttributeSet;
/**
- * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
- * which can be used as a View object's background.
+ * An object used to create frame-by-frame animations, defined by a series of
+ * Drawable objects, which can be used as a View object's background.
* <p>
- * The simplest way to create a frame-by-frame animation is to define the animation in an XML
- * file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
- * {@link #start()} to run the animation.
+ * The simplest way to create a frame-by-frame animation is to define the
+ * animation in an XML file, placed in the res/drawable/ folder, and set it as
+ * the background to a View object. Then, call {@link #start()} to run the
+ * animation.
* <p>
- * An AnimationDrawable defined in XML consists of a single <code><animation-list></code> element,
- * and a series of nested <code><item></code> tags. Each item defines a frame of the animation.
- * See the example below.
- * </p>
- * <p>spin_animation.xml file in res/drawable/ folder:</p>
- * <pre><!-- Animation frames are wheel0.png -- wheel5.png files inside the
- * res/drawable/ folder -->
+ * An AnimationDrawable defined in XML consists of a single
+ * {@code <animation-list>} element and a series of nested
+ * {@code <item>} tags. Each item defines a frame of the animation. See
+ * the example below.
+ * <p>
+ * spin_animation.xml file in res/drawable/ folder:
+ * <pre>
+ * <!-- Animation frames are wheel0.png through wheel5.png
+ * files inside the res/drawable/ folder -->
* <animation-list android:id="@+id/selected" android:oneshot="false">
* <item android:drawable="@drawable/wheel0" android:duration="50" />
* <item android:drawable="@drawable/wheel1" android:duration="50" />
@@ -53,8 +56,8 @@
* <item android:drawable="@drawable/wheel4" android:duration="50" />
* <item android:drawable="@drawable/wheel5" android:duration="50" />
* </animation-list></pre>
- *
- * <p>Here is the code to load and play this animation.</p>
+ * <p>
+ * Here is the code to load and play this animation.
* <pre>
* // Load the ImageView that will host the animation and
* // set its background to our AnimationDrawable XML resource.
@@ -128,13 +131,17 @@
}
/**
- * <p>Starts the animation, looping if necessary. This method has no effect
- * if the animation is running. Do not call this in the {@link android.app.Activity#onCreate}
- * method of your activity, because the {@link android.graphics.drawable.AnimationDrawable} is
- * not yet fully attached to the window. If you want to play
- * the animation immediately, without requiring interaction, then you might want to call it
- * from the {@link android.app.Activity#onWindowFocusChanged} method in your activity,
- * which will get called when Android brings your window into focus.</p>
+ * Starts the animation, looping if necessary. This method has no effect
+ * if the animation is running.
+ * <p>
+ * <strong>Note:</strong> Do not call this in the
+ * {@link android.app.Activity#onCreate} method of your activity, because
+ * the {@link AnimationDrawable} is not yet fully attached to the window.
+ * If you want to play the animation immediately without requiring
+ * interaction, then you might want to call it from the
+ * {@link android.app.Activity#onWindowFocusChanged} method in your
+ * activity, which will get called when Android brings your window into
+ * focus.
*
* @see #isRunning()
* @see #stop()
@@ -149,8 +156,8 @@
}
/**
- * <p>Stops the animation. This method has no effect if the animation is
- * not running.</p>
+ * Stops the animation. This method has no effect if the animation is not
+ * running.
*
* @see #isRunning()
* @see #start()
@@ -165,7 +172,7 @@
}
/**
- * <p>Indicates whether the animation is currently running or not.</p>
+ * Indicates whether the animation is currently running or not.
*
* @return true if the animation is running, false otherwise
*/
@@ -175,8 +182,8 @@
}
/**
- * <p>This method exists for implementation purpose only and should not be
- * called directly. Invoke {@link #start()} instead.</p>
+ * This method exists for implementation purpose only and should not be
+ * called directly. Invoke {@link #start()} instead.
*
* @see #start()
*/
@@ -208,7 +215,7 @@
/**
* @return The duration in milliseconds of the frame at the
- * specified index
+ * specified index
*/
public int getDuration(int i) {
return mAnimationState.mDurations[i];
@@ -231,12 +238,12 @@
}
/**
- * Add a frame to the animation
+ * Adds a frame to the animation
*
* @param frame The frame to add
* @param duration How long in milliseconds the frame should appear
*/
- public void addFrame(Drawable frame, int duration) {
+ public void addFrame(@NonNull Drawable frame, int duration) {
mAnimationState.addFrame(frame, duration);
if (mCurFrame < 0) {
setFrame(0, true, false);
@@ -244,13 +251,16 @@
}
private void nextFrame(boolean unschedule) {
- int next = mCurFrame+1;
- final int N = mAnimationState.getChildCount();
- if (next >= N) {
- next = 0;
+ int nextFrame = mCurFrame + 1;
+ final int numFrames = mAnimationState.getChildCount();
+ final boolean isLastFrame = mAnimationState.mOneShot && nextFrame >= (numFrames - 1);
+
+ // Loop if necessary. One-shot animations should never hit this case.
+ if (!mAnimationState.mOneShot && nextFrame >= numFrames) {
+ nextFrame = 0;
}
- setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N - 1));
+ setFrame(nextFrame, unschedule, !isLastFrame);
}
private void setFrame(int frame, boolean unschedule, boolean animate) {
@@ -262,6 +272,7 @@
selectDrawable(frame);
if (unschedule || animate) {
unscheduleSelf(this);
+ mRunning = false;
}
if (animate) {
// Unscheduling may have clobbered these values; restore them
@@ -341,6 +352,7 @@
}
@Override
+ @NonNull
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mAnimationState.mutate();
@@ -366,8 +378,7 @@
private int[] mDurations;
private boolean mOneShot = false;
- AnimationState(AnimationState orig, AnimationDrawable owner,
- Resources res) {
+ AnimationState(AnimationState orig, AnimationDrawable owner, Resources res) {
super(orig, owner, res);
if (orig != null) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index b0cd386..97f7105 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -58,7 +58,7 @@
* No-arg constructor used by drawable inflation.
*/
InsetDrawable() {
- this(new InsetState(), null);
+ this(new InsetState(null), null);
}
/**
@@ -82,7 +82,7 @@
*/
public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
int insetBottom) {
- this(new InsetState(), null);
+ this(new InsetState(null), null);
mState.mInsetLeft = insetLeft;
mState.mInsetTop = insetTop;
@@ -267,10 +267,6 @@
int mInsetRight = 0;
int mInsetBottom = 0;
- InsetState() {
- this(null);
- }
-
InsetState(InsetState orig) {
super(orig);
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 595061c..ca161ee 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -58,10 +58,10 @@
private RotateState mState;
/**
- * Create a new rotating drawable with an empty state.
+ * Creates a new rotating drawable with no wrapped drawable.
*/
public RotateDrawable() {
- this(null, null);
+ this(new RotateState(null), null);
}
@Override
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5dacbb5..ecb625b 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -104,6 +104,14 @@
LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
endif
+ifeq (true, $(HWUI_NULL_GPU))
+ LOCAL_SRC_FILES += \
+ tests/nullegl.cpp \
+ tests/nullgles.cpp
+
+ LOCAL_CFLAGS += -DHWUI_NULL_GPU
+endif
+
# Defaults for ATRACE_TAG and LOG_TAG for libhwui
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index bd933b8..e5489a8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -107,14 +107,6 @@
startMark = startMarkNull;
endMark = endMarkNull;
}
-
- if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
- setLabel = glLabelObjectEXT;
- getLabel = glGetObjectLabelEXT;
- } else {
- setLabel = setLabelNull;
- getLabel = getLabelNull;
- }
}
void Caches::initConstraints() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 92a87e2..8aea8ff 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -207,9 +207,6 @@
PFNGLPUSHGROUPMARKEREXTPROC startMark;
PFNGLPOPGROUPMARKEREXTPROC endMark;
- PFNGLLABELOBJECTEXTPROC setLabel;
- PFNGLGETOBJECTLABELEXTPROC getLabel;
-
// TEMPORARY properties
void initTempProperties();
void setTempProperty(const char* name, const char* value);
@@ -244,14 +241,6 @@
static void startMarkNull(GLsizei length, const GLchar* marker) { }
static void endMarkNull() { }
- static void setLabelNull(GLenum type, uint object, GLsizei length,
- const char* label) { }
- static void getLabelNull(GLenum type, uint object, GLsizei bufferSize,
- GLsizei* length, char* label) {
- if (length) *length = 0;
- if (label) *label = '\0';
- }
-
RenderState* mRenderState;
// Used to render layers
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index c68822b..2a82216 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -55,7 +55,6 @@
mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
- mHasDebugLabel = hasGlExtension("GL_EXT_debug_label");
mHasTiledRendering = hasGlExtension("GL_QCOM_tiled_rendering");
mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 731001a..e7d317d 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -40,7 +40,6 @@
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
inline bool hasDebugMarker() const { return mHasDebugMarker; }
- inline bool hasDebugLabel() const { return mHasDebugLabel; }
inline bool hasTiledRendering() const { return mHasTiledRendering; }
inline bool has1BitStencil() const { return mHas1BitStencil; }
inline bool has4BitStencil() const { return mHas4BitStencil; }
@@ -68,7 +67,6 @@
bool mHasFramebufferFetch;
bool mHasDiscardFramebuffer;
bool mHasDebugMarker;
- bool mHasDebugLabel;
bool mHasTiledRendering;
bool mHas1BitStencil;
bool mHas4BitStencil;
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index a69f3fb..51898d2 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -25,6 +25,8 @@
LOCAL_MODULE_STEM_32 := hwuitest
LOCAL_MODULE_STEM_64 := hwuitest64
+HWUI_NULL_GPU := false
+
include $(LOCAL_PATH)/Android.common.mk
LOCAL_SRC_FILES += \
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index b61d72f..0d1e63e 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -93,16 +93,16 @@
animation.createContent(width, height, renderer);
endRecording(renderer, rootNode);
- for (int i = 0; i < 150; i++) {
+ for (int i = 0; i < animation.getFrameCount(); i++) {
+#if !HWUI_NULL_GPU
testContext.waitForVsync();
+#endif
ATRACE_NAME("UI-Draw Frame");
animation.doFrame(i);
proxy->syncAndDrawFrame();
}
- sleep(5);
-
rootNode->decStrong(nullptr);
}
};
diff --git a/libs/hwui/tests/nullegl.cpp b/libs/hwui/tests/nullegl.cpp
new file mode 100644
index 0000000..b6cc2f2
--- /dev/null
+++ b/libs/hwui/tests/nullegl.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+static EGLDisplay gDisplay = (EGLDisplay) 1;
+
+typedef struct {
+ EGLSurface surface;
+ EGLContext context;
+} ThreadState;
+
+static pthread_key_t ThreadStateKey;
+static pthread_once_t ThreadStateSetupOnce = PTHREAD_ONCE_INIT;
+
+static void destroyThreadState(void* state) {
+ free(state);
+}
+
+static void makeThreadState() {
+ pthread_key_create(&ThreadStateKey, destroyThreadState);
+}
+
+ThreadState* getThreadState() {
+ ThreadState* ptr;
+ pthread_once(&ThreadStateSetupOnce, makeThreadState);
+ if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
+ ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+ ptr->context = EGL_NO_CONTEXT;
+ ptr->surface = EGL_NO_SURFACE;
+ pthread_setspecific(ThreadStateKey, ptr);
+ }
+ return ptr;
+}
+
+EGLint eglGetError(void) {
+ return EGL_SUCCESS;
+}
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
+ return gDisplay;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+ return EGL_TRUE;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy) {
+ return EGL_TRUE;
+}
+
+const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+ return "";
+}
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config) {
+ memset(configs, 9, sizeof(EGLConfig) * config_size);
+ *num_config = config_size;
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint *attrib_list) {
+ return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list) {
+ return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+ free(surface);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value) {
+ *value = 1000;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void) {
+ return EGL_TRUE;
+}
+
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint value) {
+ return EGL_TRUE;
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+ return EGL_TRUE;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_context,
+ const EGLint *attrib_list) {
+ return (EGLContext) malloc(sizeof(void*));
+}
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+ free(ctx);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx) {
+ ThreadState* state = getThreadState();
+ state->surface = draw;
+ state->context = ctx;
+ return EGL_TRUE;
+}
+
+EGLContext eglGetCurrentContext(void) {
+ return getThreadState()->context;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw) {
+ return getThreadState()->surface;
+}
+
+EGLDisplay eglGetCurrentDisplay(void) {
+ return gDisplay;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+ return EGL_TRUE;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
+ return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
+ free(image);
+ return EGL_TRUE;
+}
+
+void eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {}
diff --git a/libs/hwui/tests/nullgles.cpp b/libs/hwui/tests/nullgles.cpp
new file mode 100644
index 0000000..8ca7598
--- /dev/null
+++ b/libs/hwui/tests/nullgles.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright(C) 2015 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.
+ */
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct {
+ GLboolean scissorEnabled;
+} gState;
+
+void glGenCommon(GLsizei n, GLuint *buffers) {
+ static GLuint nextId = 0;
+ int i;
+ for(i = 0; i < n; i++) {
+ buffers[i] = ++nextId;
+ }
+}
+
+void glGenBuffers(GLsizei n, GLuint *buffers) {
+ glGenCommon(n, buffers);
+}
+
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
+ glGenCommon(n, framebuffers);
+}
+
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+ glGenCommon(n, renderbuffers);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+ glGenCommon(n, textures);
+}
+
+GLuint glCreateProgram(void) {
+ static GLuint nextProgram = 0;
+ return ++nextProgram;
+}
+
+GLuint glCreateShader(GLenum type) {
+ static GLuint nextShader = 0;
+ return ++nextShader;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
+ switch (pname) {
+ case GL_DELETE_STATUS:
+ case GL_LINK_STATUS:
+ case GL_VALIDATE_STATUS:
+ *params = GL_TRUE;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = 16;
+ break;
+ }
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+ *length = snprintf(infoLog, bufSize, "success");
+ if (*length >= bufSize) {
+ *length = bufSize - 1;
+ }
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
+ switch (pname) {
+ case GL_COMPILE_STATUS:
+ case GL_DELETE_STATUS:
+ *params = GL_TRUE;
+ }
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+ *length = snprintf(infoLog, bufSize, "success");
+ if (*length >= bufSize) {
+ *length = bufSize - 1;
+ }
+}
+
+void setBooleanState(GLenum cap, GLboolean value) {
+ switch (cap) {
+ case GL_SCISSOR_TEST:
+ gState.scissorEnabled = value;
+ break;
+ }
+}
+
+void glEnable(GLenum cap) {
+ setBooleanState(cap, GL_TRUE);
+}
+
+void glDisable(GLenum cap) {
+ setBooleanState(cap, GL_FALSE);
+}
+
+GLboolean glIsEnabled(GLenum cap) {
+ switch (cap) {
+ case GL_SCISSOR_TEST:
+ return gState.scissorEnabled;
+ default:
+ return GL_FALSE;
+ }
+}
+
+void glGetIntegerv(GLenum pname, GLint *data) {
+ switch (pname) {
+ case GL_MAX_TEXTURE_SIZE:
+ *data = 2048;
+ break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ *data = 4;
+ break;
+ default:
+ *data = 0;
+ }
+}
+
+const char* getString(GLenum name) {
+ switch (name) {
+ case GL_VENDOR:
+ return "android";
+ case GL_RENDERER:
+ return "null";
+ case GL_VERSION:
+ return "OpenGL ES 2.0 rev1";
+ case GL_SHADING_LANGUAGE_VERSION:
+ return "OpenGL ES GLSL ES 2.0 rev1";
+ case GL_EXTENSIONS:
+ default:
+ return "";
+ }
+}
+
+const GLubyte* glGetString(GLenum name) {
+ return (GLubyte*) getString(name);
+}
+
+void glActiveTexture(GLenum texture) {}
+void glAttachShader(GLuint program, GLuint shader) {}
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
+void glBindBuffer(GLenum target, GLuint buffer) {}
+void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
+void glBindTexture(GLenum target, GLuint texture) {}
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glBlendEquation(GLenum mode) {}
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
+void glClear(GLbitfield mask) {}
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glClearDepthf(GLfloat d) {}
+void glClearStencil(GLint s) {}
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
+void glCompileShader(GLuint shader) {}
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glCullFace(GLenum mode) {}
+void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
+void glDeleteProgram(GLuint program) {}
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
+void glDeleteShader(GLuint shader) {}
+void glDeleteTextures(GLsizei n, const GLuint *textures) {}
+void glDepthFunc(GLenum func) {}
+void glDepthMask(GLboolean flag) {}
+void glDepthRangef(GLfloat n, GLfloat f) {}
+void glDetachShader(GLuint program, GLuint shader) {}
+void glDisableVertexAttribArray(GLuint index) {}
+void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
+void glEnableVertexAttribArray(GLuint index) {}
+void glFinish(void) {}
+void glFlush(void) {}
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
+void glFrontFace(GLenum mode) {}
+void glGenerateMipmap(GLenum target) {}
+GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
+GLenum glGetError(void) { return GL_NO_ERROR; }
+GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
+void glHint(GLenum target, GLenum mode) {}
+void glLineWidth(GLfloat width) {}
+void glLinkProgram(GLuint program) {}
+void glPixelStorei(GLenum pname, GLint param) {}
+void glPolygonOffset(GLfloat factor, GLfloat units) {}
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
+void glReleaseShaderCompiler(void) {}
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
+void glSampleCoverage(GLfloat value, GLboolean invert) {}
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
+void glStencilMask(GLuint mask) {}
+void glStencilMaskSeparate(GLenum face, GLuint mask) {}
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
+void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
+void glUniform1f(GLint location, GLfloat v0) {}
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform1i(GLint location, GLint v0) {}
+void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform2i(GLint location, GLint v0, GLint v1) {}
+void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
+void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUseProgram(GLuint program) {}
+void glValidateProgram(GLuint program) {}
+void glVertexAttrib1f(GLuint index, GLfloat x) {}
+void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
+void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
+void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
+
+
+// gles2 ext
+void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPopGroupMarkerEXT(void) {}
+void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
+void glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) {}
+void glEndTilingQCOM(GLbitfield preserveMask) {}
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
+
+// GLES3
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+ return 0;
+}
+
+GLboolean glUnmapBuffer(GLenum target) {
+ return GL_FALSE;
+}
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
new file mode 100644
index 0000000..28d2e26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
@@ -0,0 +1,41 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:alpha=".3"
+ android:width="64dp" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.8,11.1L17.0,11.1l0.0,2.0l-1.2,0.0l4.5,4.5c1.1,-1.6 1.7,-3.5 1.7,-5.5c0.0,-5.5 -4.5,-10.0 -10.0,-10.0c-2.0,0.0 -3.9,0.6 -5.5,1.7L13.8,11.1z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.0,13.1L7.0,13.1l0.0,-2.0l4.0,0.0L4.9,5.0C3.1,6.8 2.0,9.3 2.0,12.1c0.0,5.5 4.5,10.0 10.0,10.0c2.8,0.0 5.3,-1.1 7.1,-2.9L13.0,13.1z" />
+
+ <group
+ android:pivotX="12.0"
+ android:pivotY="12.0"
+ android:rotation="45.0"
+ android:translateX="0.5"
+ android:translateY="0.5" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M-2.8,11.8l28.3,0.0l0.0,2.0l-28.3,0.0z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
new file mode 100644
index 0000000..7617ec4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
new file mode 100644
index 0000000..9361bc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 27353ff..33c1899 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -40,6 +40,16 @@
android:clipChildren="false" />
</FrameLayout>
+ <View
+ android:id="@+id/zen_embedded_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:visibility="gone"
+ android:layout_marginStart="@dimen/qs_panel_padding"
+ android:layout_marginEnd="@dimen/qs_panel_padding"
+ android:layout_marginBottom="@dimen/qs_panel_padding"
+ android:background="#4dffffff" />
+
<RelativeLayout
android:id="@+id/zen_subhead"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8a73fca..2e9e9f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -118,7 +118,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast,hotspot
+ wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d8b6a82..1b1b525 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -430,6 +430,16 @@
<string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
<!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_airplane_changed_on">Airplane mode turned on.</string>
+ <!-- Content description of the do not disturb tile in quick settings when on in priority (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
+ <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+ <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
+ <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
+ <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
<!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
<!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -554,6 +564,12 @@
<!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
<string name="quick_settings_airplane_mode_label">Airplane mode</string>
+ <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_dnd_label">Do not disturb</string>
+ <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_dnd_priority_label">Priority only</string>
+ <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_dnd_none_label">No interruptions</string>
<!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
<string name="quick_settings_bluetooth_label">Bluetooth</string>
<!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 4dacacf..7f944f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -253,12 +253,6 @@
@Override
public void onStateChanged(QSTile.State state) {
int visibility = state.visible ? VISIBLE : GONE;
- if (state.visible && !mGridContentVisible) {
-
- // We don't want to show it if the content is hidden,
- // then we just set it to invisible, to ensure that it gets visible again
- visibility = INVISIBLE;
- }
setTileVisibility(r.tileView, visibility);
r.tileView.onStateChanged(state);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
new file mode 100644
index 0000000..79600f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 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.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Do not disturb **/
+public class DndTile extends QSTile<QSTile.BooleanState> {
+ private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+ private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
+ private static final String EXTRA_VISIBLE = "visible";
+ private static final String PREF_KEY_VISIBLE = "DndTileVisible";
+
+ private final ZenModeController mController;
+ private final DndDetailAdapter mDetailAdapter;
+
+ private boolean mListening;
+ private boolean mVisible;
+ private boolean mShowingDetail;
+
+ public DndTile(Host host) {
+ super(host);
+ mController = host.getZenModeController();
+ mDetailAdapter = new DndDetailAdapter();
+ mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
+ mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+ }
+
+ public static void setVisible(Context context, boolean visible) {
+ context.sendBroadcast(new Intent(DndTile.ACTION_SET_VISIBLE)
+ .putExtra(DndTile.EXTRA_VISIBLE, visible));
+ }
+
+ public static boolean isVisible(Context context) {
+ return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
+ }
+
+ @Override
+ public DetailAdapter getDetailAdapter() {
+ return mDetailAdapter;
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void handleClick() {
+ if (mState.value) {
+ mController.setZen(Global.ZEN_MODE_OFF);
+ } else {
+ mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ showDetail(true);
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
+ state.value = zen != Global.ZEN_MODE_OFF;
+ state.visible = mVisible;
+ switch (zen) {
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+ state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_dnd_priority_on);
+ break;
+ case Global.ZEN_MODE_NO_INTERRUPTIONS:
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+ state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_dnd_none_on);
+ break;
+ default:
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
+ state.label = mContext.getString(R.string.quick_settings_dnd_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_dnd_off);
+ break;
+ }
+ if (mShowingDetail && !state.value) {
+ showDetail(false);
+ }
+ }
+
+ @Override
+ protected String composeChangeAnnouncement() {
+ if (mState.value) {
+ return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
+ } else {
+ return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
+ }
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (mListening == listening) return;
+ mListening = listening;
+ if (mListening) {
+ mController.addCallback(mZenCallback);
+ } else {
+ mController.removeCallback(mZenCallback);
+ }
+ }
+
+ private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+ public void onZenChanged(int zen) {
+ refreshState(zen);
+ }
+ };
+
+ private static SharedPreferences getSharedPrefs(Context context) {
+ return context.getSharedPreferences(context.getPackageName(), 0);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mVisible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
+ getSharedPrefs(mContext).edit().putBoolean(PREF_KEY_VISIBLE, mVisible).commit();
+ refreshState();
+ }
+ };
+
+ private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
+
+ @Override
+ public int getTitle() {
+ return R.string.quick_settings_dnd_label;
+ }
+
+ @Override
+ public Boolean getToggleState() {
+ return mState.value;
+ }
+
+ @Override
+ public Intent getSettingsIntent() {
+ return ZEN_SETTINGS;
+ }
+
+ @Override
+ public void setToggleState(boolean state) {
+ if (!state) {
+ mController.setZen(Global.ZEN_MODE_OFF);
+ showDetail(false);
+ }
+ }
+
+ @Override
+ public View createDetailView(Context context, View convertView, ViewGroup parent) {
+ final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
+ : (ZenModePanel) LayoutInflater.from(context).inflate(
+ R.layout.zen_mode_panel, parent, false);
+ if (convertView == null) {
+ zmp.init(mController);
+ zmp.setEmbedded(true);
+ zmp.addOnAttachStateChangeListener(this);
+ }
+ return zmp;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mShowingDetail = true;
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ mShowingDetail = false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index e8a000c..5da8457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.R;
+import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -198,7 +199,11 @@
int volumeIconId = 0;
String volumeDescription = null;
- if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+ if (DndTile.isVisible(mContext)) {
+ zenVisible = mZen != Global.ZEN_MODE_OFF;
+ zenIconId = R.drawable.stat_sys_dnd;
+ zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
+ } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
zenVisible = true;
zenIconId = R.drawable.stat_sys_zen_none;
zenDescription = mContext.getString(R.string.zen_no_interruptions);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 45a1386..954eb10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -41,6 +41,7 @@
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
@@ -256,6 +257,7 @@
else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
else if (tileSpec.equals("cell")) return new CellularTile(this);
else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
+ else if (tileSpec.equals("dnd")) return new DndTile(this);
else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
else if (tileSpec.equals("location")) return new LocationTile(this);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 8048a48..97ebbf1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -44,6 +44,7 @@
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.statusbar.ServiceMonitor;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -114,6 +115,7 @@
if (LOGD) Log.d(TAG, "Registering volume controller");
mAudioManager.setVolumeController(mVolumeController);
mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
+ DndTile.setVisible(mContext, false);
} else {
if (LOGD) Log.d(TAG, "Unregistering volume controller");
mAudioManager.setVolumeController(null);
@@ -322,7 +324,8 @@
.setContentTitle(mContext.getString(
R.string.volumeui_notification_title, getAppLabel(component)))
.setContentText(mContext.getString(R.string.volumeui_notification_text))
- .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0))
+ .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT))
.setPriority(Notification.PRIORITY_MIN)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(mContext.getResources().getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 5726fa7..6cecc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -90,9 +90,11 @@
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
private SegmentedButtons mZenButtons;
+ private ViewGroup mZenButtonsContainer;
private View mZenSubhead;
private TextView mZenSubheadCollapsed;
private TextView mZenSubheadExpanded;
+ private View mZenEmbeddedDivider;
private View mMoreSettings;
private LinearLayout mZenConditions;
@@ -114,6 +116,7 @@
private Condition mSessionExitCondition;
private Condition[] mConditions;
private Condition mTimeCondition;
+ private boolean mEmbedded;
public ZenModePanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -140,9 +143,25 @@
pw.print(" mExpanded="); pw.println(mExpanded);
pw.print(" mSessionZen="); pw.println(mSessionZen);
pw.print(" mAttachedZen="); pw.println(mAttachedZen);
+ pw.print(" mEmbedded="); pw.println(mEmbedded);
mTransitionHelper.dump(fd, pw, args);
}
+ public void setEmbedded(boolean embedded) {
+ if (mEmbedded == embedded) return;
+ mEmbedded = embedded;
+ mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
+ if (mEmbedded) {
+ mZenButtonsContainer.setBackground(null);
+ } else {
+ mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
+ }
+ mZenButtons.getChildAt(2).setVisibility(mEmbedded ? GONE : VISIBLE);
+ mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
+ setExpanded(mEmbedded);
+ updateWidgets();
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -156,10 +175,11 @@
Global.ZEN_MODE_OFF);
mZenButtons.setCallback(mZenButtonsCallback);
- final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
- zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
+ mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
+ mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
mZenSubhead = findViewById(R.id.zen_subhead);
+ mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider);
mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
@@ -222,7 +242,9 @@
mAttachedZen = -1;
mSessionZen = -1;
setSessionExitCondition(null);
- setExpanded(false);
+ if (!mEmbedded) {
+ setExpanded(false);
+ }
setRequestingConditions(false);
mTransitionHelper.clear();
}
@@ -361,7 +383,7 @@
private void handleUpdateZen(int zen) {
if (mSessionZen != -1 && mSessionZen != zen) {
- setExpanded(zen != Global.ZEN_MODE_OFF);
+ setExpanded(mEmbedded || zen != Global.ZEN_MODE_OFF);
mSessionZen = zen;
}
mZenButtons.setSelectedValue(zen);
@@ -403,7 +425,7 @@
final boolean expanded = !mHidden && mExpanded;
mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
- mZenSubhead.setVisibility(!mHidden && !zenOff ? VISIBLE : GONE);
+ mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE);
mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8d7a182..376ef2a 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -736,50 +736,47 @@
}
public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) {
+ log("notifySignalStrengthForSubscriber: subId=" + subId
+ + " signalStrength=" + signalStrength);
if (!checkNotifyPermission("notifySignalStrength()")) {
+ log("notifySignalStrengthForSubscriber: permission check failure");
return;
}
- if (VDBG) {
- log("notifySignalStrengthForSubscriber: subId=" + subId
- + " signalStrength=" + signalStrength);
- toStringLogSSC("notifySignalStrengthForSubscriber");
- }
+ toStringLogSSC("notifySignalStrengthForSubscriber");
synchronized (mRecords) {
int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
- if (VDBG) log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
+ log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
mSignalStrength[phoneId] = signalStrength;
for (Record r : mRecords) {
- if (VDBG) {
- log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
- + " phoneId=" + phoneId + " ss=" + signalStrength);
- }
+ log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
+ + " phoneId=" + phoneId + " ss=" + signalStrength);
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
idMatch(r.subId, subId, phoneId)) {
try {
- if (DBG) {
- log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
- + " subId=" + subId + " phoneId=" + phoneId
- + " ss=" + signalStrength);
- }
+ log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " ss=" + signalStrength);
r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
} catch (RemoteException ex) {
+ log("notifySignalStrengthForSubscriber: Exception while calling callback!!");
mRemoveList.add(r.binder);
}
+ } else {
+ log("notifySignalStrengthForSubscriber: no match for LISTEN_SIGNAL_STRENGTHS");
}
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
idMatch(r.subId, subId, phoneId)){
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
- if (DBG) {
- log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
- + " subId=" + subId + " phoneId=" + phoneId
- + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
- }
+ log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
r.callback.onSignalStrengthChanged(ss);
} catch (RemoteException ex) {
+ log("notifySignalStrengthForSubscriber: Exception in deprecated LISTEN_SIGNAL_STRENGTH");
mRemoveList.add(r.binder);
}
}
@@ -787,6 +784,7 @@
} else {
log("notifySignalStrengthForSubscriber: invalid phoneId=" + phoneId);
}
+ log("notifySignalStrengthForSubscriber: done with all records");
handleRemoveListLocked();
}
broadcastSignalStrengthChanged(signalStrength, subId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 966dc88..008d718 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2398,8 +2398,7 @@
} else {
finishRunningVoiceLocked();
}
- mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity");
- if (r != null) {
+ if (r != null && mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
}
applyUpdateLockStateLocked(r);
@@ -2423,6 +2422,7 @@
ActivityRecord r = stack.topRunningActivityLocked(null);
if (r != null) {
setFocusedActivityLocked(r, "setFocusedStack");
+ mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index c0d2502..0cbc9d7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -479,10 +479,16 @@
AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
realTheme, com.android.internal.R.styleable.Window, userId);
+ final boolean translucent = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+ || (!ent.array.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent)
+ && ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+ false));
fullscreen = ent != null && !ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false)
- && !ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ && !translucent;
noDisplay = ent != null && ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c3343f5..40a8b86 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -496,11 +496,20 @@
final void moveToFront(String reason) {
if (isAttached()) {
- if (isOnHomeDisplay()) {
- mStackSupervisor.moveHomeStack(isHomeStack(), reason);
+ final boolean homeStack = isHomeStack()
+ || (mActivityContainer.mParentActivity != null
+ && mActivityContainer.mParentActivity.isHomeActivity());
+ ActivityStack lastFocusStack = null;
+ if (!homeStack) {
+ // Need to move this stack to the front before calling
+ // {@link ActivityStackSupervisor#moveHomeStack} below.
+ lastFocusStack = mStacks.get(mStacks.size() - 1);
+ mStacks.remove(this);
+ mStacks.add(this);
}
- mStacks.remove(this);
- mStacks.add(this);
+ if (isOnHomeDisplay()) {
+ mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
+ }
final TaskRecord task = topTask();
if (task != null) {
mWindowManager.moveTaskToTop(task.taskId);
@@ -2580,7 +2589,6 @@
if (top == null) {
return false;
}
- stack.moveToFront(myReason);
mService.setFocusedActivityLocked(top, myReason);
return true;
}
@@ -3656,8 +3664,7 @@
}
}
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare to back transition: task=" + taskId);
+ if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
boolean prevIsHome = false;
if (tr.isOverHomeStack()) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 907381e..c4234eb 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -386,21 +386,22 @@
return mLastFocusedStack;
}
- /** Top of all visible stacks. Use {@link ActivityStack#isStackVisibleLocked} to determine if a
- * specific stack is visible or not. */
+ /** Top of all visible stacks is/should always be equal to the focused stack.
+ * Use {@link ActivityStack#isStackVisibleLocked} to determine if a specific
+ * stack is visible or not. */
boolean isFrontStack(ActivityStack stack) {
final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
if (parent != null) {
stack = parent.task.stack;
}
- ArrayList<ActivityStack> stacks = stack.mStacks;
- if (stacks != null && !stacks.isEmpty()) {
- return stack == stacks.get(stacks.size() - 1);
- }
- return false;
+ return stack == mFocusedStack;
}
void moveHomeStack(boolean toFront, String reason) {
+ moveHomeStack(toFront, reason, null);
+ }
+
+ void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) {
ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
final int topNdx = stacks.size() - 1;
if (topNdx <= 0) {
@@ -409,13 +410,17 @@
ActivityStack topStack = stacks.get(topNdx);
final boolean homeInFront = topStack == mHomeStack;
if (homeInFront != toFront) {
- mLastFocusedStack = topStack;
stacks.remove(mHomeStack);
stacks.add(toFront ? topNdx : 0, mHomeStack);
- mFocusedStack = stacks.get(topNdx);
if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new="
+ mFocusedStack);
}
+
+ if (lastFocusedStack != null) {
+ mLastFocusedStack = lastFocusedStack;
+ }
+ mFocusedStack = stacks.get(topNdx);
+
EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED,
mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(),
mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason);
@@ -1541,25 +1546,27 @@
return err;
}
- ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
+ ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
final TaskRecord task = r.task;
// On leanback only devices we should keep all activities in the same stack.
if (!mLeanbackOnlyDevice &&
(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+
+ ActivityStack stack;
+
if (task != null) {
- final ActivityStack taskStack = task.stack;
- if (taskStack.isOnHomeDisplay()) {
- if (mFocusedStack != taskStack) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
+ stack = task.stack;
+ if (stack.isOnHomeDisplay()) {
+ if (mFocusedStack != stack) {
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: Setting " +
"focused stack to r=" + r + " task=" + task);
- mFocusedStack = taskStack;
} else {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
- "adjustStackFocus: Focused stack already=" + mFocusedStack);
+ "computeStackFocus: Focused stack already=" + mFocusedStack);
}
}
- return taskStack;
+ return stack;
}
final ActivityContainer container = r.mInitialActivityContainer;
@@ -1572,43 +1579,41 @@
if (mFocusedStack != mHomeStack && (!newTask ||
mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
- "adjustStackFocus: Have a focused stack=" + mFocusedStack);
+ "computeStackFocus: Have a focused stack=" + mFocusedStack);
return mFocusedStack;
}
final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = homeDisplayStacks.get(stackNdx);
+ stack = homeDisplayStacks.get(stackNdx);
if (!stack.isHomeStack()) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
- "adjustStackFocus: Setting focused stack=" + stack);
- mFocusedStack = stack;
- return mFocusedStack;
+ "computeStackFocus: Setting focused stack=" + stack);
+ return stack;
}
}
// Need to create an app stack for this user.
- mFocusedStack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
- " stackId=" + mFocusedStack.mStackId);
- return mFocusedStack;
+ stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: New stack r=" + r +
+ " stackId=" + stack.mStackId);
+ return stack;
}
return mHomeStack;
}
- void setFocusedStack(ActivityRecord r, String reason) {
- if (r != null) {
- final TaskRecord task = r.task;
- boolean isHomeActivity = !r.isApplicationActivity();
- if (!isHomeActivity && task != null) {
- isHomeActivity = !task.isApplicationTask();
- }
- if (!isHomeActivity && task != null) {
- final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
- isHomeActivity = parent != null && parent.isHomeActivity();
- }
- moveHomeStack(isHomeActivity, reason);
+ boolean setFocusedStack(ActivityRecord r, String reason) {
+ if (r == null) {
+ // Not sure what you are trying to do, but it is not going to work...
+ return false;
}
+ final TaskRecord task = r.task;
+ if (task == null || task.stack == null) {
+ Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+ return false;
+ }
+ task.stack.moveToFront(reason);
+ return true;
}
final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
@@ -2082,10 +2087,9 @@
return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
newTask = true;
- targetStack = adjustStackFocus(r, newTask);
- if (!launchTaskBehind) {
- targetStack.moveToFront("startingNewTask");
- }
+ targetStack = computeStackFocus(r, newTask);
+ targetStack.moveToFront("startingNewTask");
+
if (reuseTask == null) {
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo != null ? newTaskInfo : r.info,
@@ -2206,7 +2210,7 @@
// This not being started from an existing activity, and not part
// of a new task... just put it in the top task, though these days
// this case should never happen.
- targetStack = adjustStackFocus(r, newTask);
+ targetStack = computeStackFocus(r, newTask);
targetStack.moveToFront("addingToTopTask");
ActivityRecord prev = targetStack.topActivity();
r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index afe7d7a..473f5db 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1425,6 +1425,7 @@
private void sendBroadcastToAll(Intent intent) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
@@ -1434,6 +1435,7 @@
}
private void sendStickyBroadcastToAll(Intent intent) {
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 09dc477..5f0ad9f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -46,7 +46,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -832,6 +831,24 @@
}
}
+ private void setDisplayOffsetsInternal(int displayId, int x, int y) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display == null) {
+ return;
+ }
+ if (display.getDisplayOffsetXLocked() != x
+ || display.getDisplayOffsetYLocked() != y) {
+ if (DEBUG) {
+ Slog.d(TAG, "Display " + displayId + " burn-in offset set to ("
+ + x + ", " + y + ")");
+ }
+ display.setDisplayOffsetsLocked(x, y);
+ scheduleTraversalLocked(false);
+ }
+ }
+ }
+
private void clearViewportsLocked() {
mDefaultViewport.valid = false;
mExternalTouchViewport.valid = false;
@@ -1513,5 +1530,10 @@
float requestedRefreshRate, boolean inTraversal) {
setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal);
}
+
+ @Override
+ public void setDisplayOffsets(int displayId, int x, int y) {
+ setDisplayOffsetsInternal(displayId, x, y);
+ }
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6c57eec..3bb7818 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -76,6 +76,10 @@
// The pending requested refresh rate. 0 if no request is pending.
private float mRequestedRefreshRate;
+ // The display offsets to apply to the display projection.
+ private int mDisplayOffsetX;
+ private int mDisplayOffsetY;
+
// Temporary rectangle used when needed.
private final Rect mTempLayerStackRect = new Rect();
private final Rect mTempDisplayRect = new Rect();
@@ -313,6 +317,10 @@
mTempDisplayRect.set(displayRectLeft, displayRectTop,
displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
+ mTempDisplayRect.left += mDisplayOffsetX;
+ mTempDisplayRect.right += mDisplayOffsetX;
+ mTempDisplayRect.top += mDisplayOffsetY;
+ mTempDisplayRect.bottom += mDisplayOffsetY;
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
}
@@ -356,10 +364,34 @@
return mRequestedRefreshRate;
}
+ /**
+ * Gets the burn-in offset in X.
+ */
+ public int getDisplayOffsetXLocked() {
+ return mDisplayOffsetX;
+ }
+
+ /**
+ * Gets the burn-in offset in Y.
+ */
+ public int getDisplayOffsetYLocked() {
+ return mDisplayOffsetY;
+ }
+
+ /**
+ * Sets the burn-in offsets.
+ */
+ public void setDisplayOffsetsLocked(int x, int y) {
+ mDisplayOffsetX = x;
+ mDisplayOffsetY = y;
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println("mDisplayId=" + mDisplayId);
pw.println("mLayerStack=" + mLayerStack);
pw.println("mHasContent=" + mHasContent);
+ pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
+ pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
mPrimaryDisplayDevice.getNameLocked() : "null"));
pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
new file mode 100644
index 0000000..79e7a20
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * Provides various methods for obtaining and converting of instruction sets.
+ *
+ * @hide
+ */
+public class InstructionSets {
+ private static final String PREFERRED_INSTRUCTION_SET =
+ VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);;
+ public static String[] getAppDexInstructionSets(ApplicationInfo info) {
+ if (info.primaryCpuAbi != null) {
+ if (info.secondaryCpuAbi != null) {
+ return new String[] {
+ VMRuntime.getInstructionSet(info.primaryCpuAbi),
+ VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+ } else {
+ return new String[] {
+ VMRuntime.getInstructionSet(info.primaryCpuAbi) };
+ }
+ }
+
+ return new String[] { getPreferredInstructionSet() };
+ }
+
+ public static String[] getAppDexInstructionSets(PackageSetting ps) {
+ if (ps.primaryCpuAbiString != null) {
+ if (ps.secondaryCpuAbiString != null) {
+ return new String[] {
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
+ VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
+ } else {
+ return new String[] {
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+ }
+ }
+
+ return new String[] { getPreferredInstructionSet() };
+ }
+
+ public static String getPreferredInstructionSet() {
+ return PREFERRED_INSTRUCTION_SET;
+ }
+
+ /**
+ * Returns the instruction set that should be used to compile dex code. In the presence of
+ * a native bridge this might be different than the one shared libraries use.
+ */
+ public static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+ String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+ return TextUtils.isEmpty(dexCodeIsa) ? sharedLibraryIsa : dexCodeIsa;
+ }
+
+ public static String[] getDexCodeInstructionSets(String[] instructionSets) {
+ ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
+ for (String instructionSet : instructionSets) {
+ dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+ }
+ return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+ }
+
+ /**
+ * Returns deduplicated list of supported instructions for dex code.
+ */
+ public static String[] getAllDexCodeInstructionSets() {
+ String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
+ for (int i = 0; i < supportedInstructionSets.length; i++) {
+ String abi = Build.SUPPORTED_ABIS[i];
+ supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
+ }
+ return getDexCodeInstructionSets(supportedInstructionSets);
+ }
+
+ public static List<String> getAllInstructionSets() {
+ final String[] allAbis = Build.SUPPORTED_ABIS;
+ final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
+
+ for (String abi : allAbis) {
+ final String instructionSet = VMRuntime.getInstructionSet(abi);
+ if (!allInstructionSets.contains(instructionSet)) {
+ allInstructionSets.add(instructionSet);
+ }
+ }
+
+ return allInstructionSets;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
new file mode 100644
index 0000000..0a7c5cf
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+
+/**
+ * Helper class for running dexopt command on packages.
+ */
+final class PackageDexOptimizer {
+ static final String TAG = "PackageManager.DexOptimizer";
+ static final int DEX_OPT_SKIPPED = 0;
+ static final int DEX_OPT_PERFORMED = 1;
+ static final int DEX_OPT_DEFERRED = 2;
+ static final int DEX_OPT_FAILED = -1;
+
+ private final PackageManagerService mPackageManagerService;
+ private ArraySet<PackageParser.Package> mDeferredDexOpt;
+
+ PackageDexOptimizer(PackageManagerService packageManagerService) {
+ this.mPackageManagerService = packageManagerService;
+ }
+
+ /**
+ * Performs dexopt on all code paths and libraries of the specified package for specified
+ * instruction sets.
+ *
+ * <p>Calls to {@link com.android.server.pm.Installer#dexopt} are synchronized on
+ * {@link PackageManagerService#mInstallLock}.
+ */
+ int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
+ boolean forceDex, boolean defer, boolean inclDependencies) {
+ ArraySet<String> done;
+ if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
+ done = new ArraySet<String>();
+ done.add(pkg.packageName);
+ } else {
+ done = null;
+ }
+ synchronized (mPackageManagerService.mInstallLock) {
+ return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+ }
+ }
+
+ private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
+ boolean forceDex, boolean defer, ArraySet<String> done) {
+ final String[] instructionSets = targetInstructionSets != null ?
+ targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+
+ if (done != null) {
+ done.add(pkg.packageName);
+ if (pkg.usesLibraries != null) {
+ performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
+ }
+ if (pkg.usesOptionalLibraries != null) {
+ performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
+ done);
+ }
+ }
+
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+ return DEX_OPT_SKIPPED;
+ }
+
+ final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
+
+ final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+ boolean performedDexOpt = false;
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are deferring a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+ continue;
+ }
+
+ for (String path : paths) {
+ try {
+ // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+ // package or the one we find does not match the image checksum (i.e. it was
+ // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+ // odex file and it matches the checksum of the image but not its base address,
+ // meaning we need to move it.
+ final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName, dexCodeInstructionSet, defer);
+ if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
+ Log.i(TAG, "Running dexopt on: " + path + " pkg="
+ + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ + " vmSafeMode=" + vmSafeMode);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+ !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
+ vmSafeMode);
+
+ if (ret < 0) {
+ // Don't bother running dexopt again if we failed, it will probably
+ // just result in an error again. Also, don't bother dexopting for other
+ // paths & ISAs.
+ return DEX_OPT_FAILED;
+ }
+
+ performedDexOpt = true;
+ } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
+ Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int ret = mPackageManagerService.mInstaller.patchoat(path, sharedGid,
+ !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet);
+
+ if (ret < 0) {
+ // Don't bother running patchoat again if we failed, it will probably
+ // just result in an error again. Also, don't bother dexopting for other
+ // paths & ISAs.
+ return DEX_OPT_FAILED;
+ }
+
+ performedDexOpt = true;
+ }
+
+ // We're deciding to defer a needed dexopt. Don't bother dexopting for other
+ // paths and instruction sets. We'll deal with them all together when we process
+ // our list of deferred dexopts.
+ if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
+ addPackageForDeferredDexopt(pkg);
+ return DEX_OPT_DEFERRED;
+ }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Apk not found for dexopt: " + path);
+ return DEX_OPT_FAILED;
+ } catch (IOException e) {
+ Slog.w(TAG, "IOException reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
+ Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when doing dexopt : ", e);
+ return DEX_OPT_FAILED;
+ }
+ }
+
+ // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
+ // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+ // it isn't required. We therefore mark that this package doesn't need dexopt unless
+ // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
+ // it.
+ pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+ }
+
+ // If we've gotten here, we're sure that no error occurred and that we haven't
+ // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
+ // we've skipped all of them because they are up to date. In both cases this
+ // package doesn't need dexopt any longer.
+ return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+ }
+
+ private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
+ boolean forceDex, boolean defer, ArraySet<String> done) {
+ for (String libName : libs) {
+ PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
+ libName);
+ if (libPkg != null && !done.contains(libName)) {
+ performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
+ }
+ }
+ }
+
+ /**
+ * Clears set of deferred dexopt packages.
+ * @return content of dexopt set if it was not empty
+ */
+ public ArraySet<PackageParser.Package> clearDeferredDexOptPackages() {
+ ArraySet<PackageParser.Package> result = mDeferredDexOpt;
+ mDeferredDexOpt = null;
+ return result;
+ }
+
+ public void addPackageForDeferredDexopt(PackageParser.Package pkg) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new ArraySet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c3f1418..2e2f350 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -55,6 +55,10 @@
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import android.util.ArrayMap;
@@ -184,7 +188,6 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
@@ -213,7 +216,6 @@
import java.util.concurrent.atomic.AtomicLong;
import dalvik.system.DexFile;
-import dalvik.system.StaleDexCacheError;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -323,13 +325,8 @@
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
- private static String sPreferredInstructionSet;
-
final ServiceThread mHandlerThread;
- private static final String IDMAP_PREFIX = "/data/resource-cache/";
- private static final String IDMAP_SUFFIX = "@idmap";
-
final PackageHandler mHandler;
/**
@@ -466,8 +463,7 @@
final PackageInstallerService mInstallerService;
- ArraySet<PackageParser.Package> mDeferredDexOpt = null;
-
+ private final PackageDexOptimizer mPackageDexOptimizer;
// Cache of users who need badging.
SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
@@ -1050,7 +1046,7 @@
res.pkg.applicationInfo.packageName, null, updateUsers);
// treat asec-hosted packages like removable media on upgrade
- if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {
+ if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg
+ " is ASEC-hosted -> AVAILABLE");
@@ -1338,6 +1334,7 @@
}
mInstaller = installer;
+ mPackageDexOptimizer = new PackageDexOptimizer(this);
getDefaultDisplayMetrics(context, mMetrics);
@@ -1438,9 +1435,10 @@
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
- final List<String> allInstructionSets = getAllInstructionSets();
+ final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
final String[] dexCodeInstructionSets =
- getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
+ getDexCodeInstructionSets(
+ allInstructionSets.toArray(new String[allInstructionSets.size()]));
/**
* Ensure all external libraries have had dexopt run on them.
@@ -2335,6 +2333,19 @@
return null;
}
+ /**
+ * @hide
+ */
+ PackageParser.Package findSharedNonSystemLibrary(String libName) {
+ synchronized (mPackages) {
+ PackageManagerService.SharedLibraryEntry lib = mSharedLibraries.get(libName);
+ if (lib != null && lib.apk != null) {
+ return mPackages.get(lib.apk);
+ }
+ }
+ return null;
+ }
+
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
Collection<FeatureInfo> featSet;
@@ -4616,8 +4627,7 @@
final ArraySet<PackageParser.Package> pkgs;
synchronized (mPackages) {
- pkgs = mDeferredDexOpt;
- mDeferredDexOpt = null;
+ pkgs = mPackageDexOptimizer.clearDeferredDexOptPackages();
}
if (pkgs != null) {
@@ -4773,8 +4783,8 @@
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
- performDexOptLI(p, null /* instruction sets */, false /* force dex */,
- false /* defer */, true /* include dependencies */);
+ mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
+ false /* force dex */, false /* defer */, true /* include dependencies */);
}
}
@@ -4823,8 +4833,9 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
- return performDexOptLI(p, instructionSets, false /* force dex */, false /* defer */,
- true /* include dependencies */) == DEX_OPT_PERFORMED;
+ int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
+ false /* forceDex */, false /* defer */, true /* inclDependencies */);
+ return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
}
@@ -4851,226 +4862,6 @@
mPackageUsage.write(true);
}
- private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
- boolean forceDex, boolean defer, ArraySet<String> done) {
- for (int i=0; i<libs.size(); i++) {
- PackageParser.Package libPkg;
- String libName;
- synchronized (mPackages) {
- libName = libs.get(i);
- SharedLibraryEntry lib = mSharedLibraries.get(libName);
- if (lib != null && lib.apk != null) {
- libPkg = mPackages.get(lib.apk);
- } else {
- libPkg = null;
- }
- }
- if (libPkg != null && !done.contains(libName)) {
- performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
- }
- }
- }
-
- static final int DEX_OPT_SKIPPED = 0;
- static final int DEX_OPT_PERFORMED = 1;
- static final int DEX_OPT_DEFERRED = 2;
- static final int DEX_OPT_FAILED = -1;
-
- private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- boolean forceDex, boolean defer, ArraySet<String> done) {
- final String[] instructionSets = targetInstructionSets != null ?
- targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
-
- if (done != null) {
- done.add(pkg.packageName);
- if (pkg.usesLibraries != null) {
- performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
- }
- if (pkg.usesOptionalLibraries != null) {
- performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, done);
- }
- }
-
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
- return DEX_OPT_SKIPPED;
- }
-
- final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
-
- final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
- boolean performedDexOpt = false;
- // There are three basic cases here:
- // 1.) we need to dexopt, either because we are forced or it is needed
- // 2.) we are defering a needed dexopt
- // 3.) we are skipping an unneeded dexopt
- final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
- continue;
- }
-
- for (String path : paths) {
- try {
- // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
- // patckage or the one we find does not match the image checksum (i.e. it was
- // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
- // odex file and it matches the checksum of the image but not its base address,
- // meaning we need to move it.
- final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
- pkg.packageName, dexCodeInstructionSet, defer);
- if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
- Log.i(TAG, "Running dexopt on: " + path + " pkg="
- + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
- + " vmSafeMode=" + vmSafeMode);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, dexCodeInstructionSet, vmSafeMode);
-
- if (ret < 0) {
- // Don't bother running dexopt again if we failed, it will probably
- // just result in an error again. Also, don't bother dexopting for other
- // paths & ISAs.
- return DEX_OPT_FAILED;
- }
-
- performedDexOpt = true;
- } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
- Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, dexCodeInstructionSet);
-
- if (ret < 0) {
- // Don't bother running patchoat again if we failed, it will probably
- // just result in an error again. Also, don't bother dexopting for other
- // paths & ISAs.
- return DEX_OPT_FAILED;
- }
-
- performedDexOpt = true;
- }
-
- // We're deciding to defer a needed dexopt. Don't bother dexopting for other
- // paths and instruction sets. We'll deal with them all together when we process
- // our list of deferred dexopts.
- if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new ArraySet<PackageParser.Package>();
- }
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Apk not found for dexopt: " + path);
- return DEX_OPT_FAILED;
- } catch (IOException e) {
- Slog.w(TAG, "IOException reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (StaleDexCacheError e) {
- Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (Exception e) {
- Slog.w(TAG, "Exception when doing dexopt : ", e);
- return DEX_OPT_FAILED;
- }
- }
-
- // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
- // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
- // it isn't required. We therefore mark that this package doesn't need dexopt unless
- // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
- // it.
- pkg.mDexOptPerformed.add(dexCodeInstructionSet);
- }
-
- // If we've gotten here, we're sure that no error occurred and that we haven't
- // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
- // we've skipped all of them because they are up to date. In both cases this
- // package doesn't need dexopt any longer.
- return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
- }
-
- private static String[] getAppDexInstructionSets(ApplicationInfo info) {
- if (info.primaryCpuAbi != null) {
- if (info.secondaryCpuAbi != null) {
- return new String[] {
- VMRuntime.getInstructionSet(info.primaryCpuAbi),
- VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
- } else {
- return new String[] {
- VMRuntime.getInstructionSet(info.primaryCpuAbi) };
- }
- }
-
- return new String[] { getPreferredInstructionSet() };
- }
-
- private static String[] getAppDexInstructionSets(PackageSetting ps) {
- if (ps.primaryCpuAbiString != null) {
- if (ps.secondaryCpuAbiString != null) {
- return new String[] {
- VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
- VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
- } else {
- return new String[] {
- VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
- }
- }
-
- return new String[] { getPreferredInstructionSet() };
- }
-
- private static String getPreferredInstructionSet() {
- if (sPreferredInstructionSet == null) {
- sPreferredInstructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
- }
-
- return sPreferredInstructionSet;
- }
-
- private static List<String> getAllInstructionSets() {
- final String[] allAbis = Build.SUPPORTED_ABIS;
- final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
-
- for (String abi : allAbis) {
- final String instructionSet = VMRuntime.getInstructionSet(abi);
- if (!allInstructionSets.contains(instructionSet)) {
- allInstructionSets.add(instructionSet);
- }
- }
-
- return allInstructionSets;
- }
-
- /**
- * Returns the instruction set that should be used to compile dex code. In the presence of
- * a native bridge this might be different than the one shared libraries use.
- */
- private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
- String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
- return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
- }
-
- private static String[] getDexCodeInstructionSets(String[] instructionSets) {
- ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
- for (String instructionSet : instructionSets) {
- dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
- }
- return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
- }
-
- /**
- * Returns deduplicated list of supported instructions for dex code.
- */
- public static String[] getAllDexCodeInstructionSets() {
- String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
- for (int i = 0; i < supportedInstructionSets.length; i++) {
- String abi = Build.SUPPORTED_ABIS[i];
- supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
- }
- return getDexCodeInstructionSets(supportedInstructionSets);
- }
-
@Override
public void forceDexOpt(String packageName) {
enforceSystemOrRoot("forceDexOpt");
@@ -5086,25 +4877,14 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] {
getPrimaryInstructionSet(pkg.applicationInfo) };
- final int res = performDexOptLI(pkg, instructionSets, true, false, true);
- if (res != DEX_OPT_PERFORMED) {
+ final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
+ true /*forceDex*/, false /* defer */, true /* inclDependencies */);
+ if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
throw new IllegalStateException("Failed to dexopt: " + res);
}
}
}
- private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
- boolean forceDex, boolean defer, boolean inclDependencies) {
- ArraySet<String> done;
- if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
- done = new ArraySet<String>();
- done.add(pkg.packageName);
- } else {
- done = null;
- }
- return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
- }
-
private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -5120,10 +4900,6 @@
return true;
}
- File getDataPathForUser(int userId) {
- return new File(mUserAppDataDir.getAbsolutePath() + File.separator + userId);
- }
-
private File getDataPathForPackage(String packageName, int userId) {
/*
* Until we fully support multiple users, return the directory we
@@ -5791,7 +5567,7 @@
// pass once we've determined ABI below.
setNativeLibraryPaths(pkg);
- final boolean isAsec = isForwardLocked(pkg) || isExternal(pkg);
+ final boolean isAsec = pkg.isForwardLocked() || isExternal(pkg);
final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
@@ -5967,8 +5743,9 @@
}
if ((scanFlags & SCAN_NO_DEX) == 0) {
- if (performDexOptLI(pkg, null /* instruction sets */, forceDex,
- (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+ int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
+ forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
}
}
@@ -6042,8 +5819,10 @@
if ((scanFlags & SCAN_NO_DEX) == 0) {
for (int i = 0; i < clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
- if (performDexOptLI(clientPkg, null /* instruction sets */, forceDex,
- (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+ int result = mPackageDexOptimizer.performDexOpt(clientPkg,
+ null /* instruction sets */, forceDex,
+ (scanFlags & SCAN_DEFER_DEX) != 0, false);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
"scanPackageLI failed to dexopt clientLibPkgs");
}
@@ -6512,14 +6291,15 @@
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
- if (performDexOptLI(ps.pkg, null /* instruction sets */, forceDexOpt,
- deferDexOpt, true) == DEX_OPT_FAILED) {
+ int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
+ null /* instruction sets */, forceDexOpt, deferDexOpt, true);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
ps.primaryCpuAbiString = null;
ps.pkg.applicationInfo.primaryCpuAbi = null;
return;
} else {
mInstaller.rmdex(ps.codePathString,
- getDexCodeInstructionSet(getPreferredInstructionSet()));
+ getDexCodeInstructionSet(getPreferredInstructionSet()));
}
}
}
@@ -6592,7 +6372,7 @@
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info);
- final boolean asecApp = isForwardLocked(info) || isExternal(info);
+ final boolean asecApp = info.isForwardLocked() || isExternal(info);
info.nativeLibraryRootDir = null;
info.nativeLibraryRootRequiresIsa = false;
@@ -9427,6 +9207,25 @@
}
}
+ private void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
+ if (!allCodePaths.isEmpty()) {
+ if (instructionSets == null) {
+ throw new IllegalStateException("instructionSet == null");
+ }
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String codePath : allCodePaths) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location " + codePath + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
+ }
+ }
+ }
+ }
+
/**
* Logic to handle installation of non-ASEC applications, including copying
* and renaming logic.
@@ -9639,23 +9438,7 @@
}
cleanUp();
-
- if (!allCodePaths.isEmpty()) {
- if (instructionSets == null) {
- throw new IllegalStateException("instructionSet == null");
- }
- String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String codePath : allCodePaths) {
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
- }
- }
- }
+ removeDexFiles(allCodePaths, instructionSets);
}
boolean doPostDeleteLI(boolean delete) {
@@ -9960,31 +9743,10 @@
private void cleanUpResourcesLI(List<String> allCodePaths) {
cleanUp();
-
- if (!allCodePaths.isEmpty()) {
- if (instructionSets == null) {
- throw new IllegalStateException("instructionSet == null");
- }
- String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String codePath : allCodePaths) {
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
- }
- }
- }
+ removeDexFiles(allCodePaths, instructionSets);
}
- boolean matchContainer(String app) {
- if (cid.startsWith(app)) {
- return true;
- }
- return false;
- }
+
String getPackageName() {
return getAsecPackageName(cid);
@@ -10302,7 +10064,7 @@
// If deleted package lived in a container, give users a chance to
// relinquish resources before killing.
- if (isForwardLocked(deletedPackage) || isExternal(deletedPackage)) {
+ if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
}
@@ -10343,7 +10105,7 @@
// Parse old package
boolean oldOnSd = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
- (isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+ (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
(oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
try {
@@ -10733,18 +10495,6 @@
}
}
- private static boolean isForwardLocked(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
- }
-
- private static boolean isForwardLocked(ApplicationInfo info) {
- return (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
- }
-
- private boolean isForwardLocked(PackageSetting ps) {
- return (ps.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
- }
-
private static boolean isMultiArch(PackageSetting ps) {
return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
}
@@ -10798,7 +10548,7 @@
if (isExternal(ps)) {
installFlags |= PackageManager.INSTALL_EXTERNAL;
}
- if (isForwardLocked(ps)) {
+ if (ps.isForwardLocked()) {
installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
}
return installFlags;
@@ -11652,7 +11402,7 @@
if (ps != null) {
libDirRoot = ps.legacyNativeLibraryPathString;
}
- if (p != null && (isExternal(p) || isForwardLocked(p))) {
+ if (p != null && (isExternal(p) || p.isForwardLocked())) {
String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
if (secureContainerId != null) {
asecPath = PackageHelper.getSdFilesystem(secureContainerId);
@@ -11666,7 +11416,7 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- if (isForwardLocked(p)) {
+ if (p.isForwardLocked()) {
publicSrcDir = applicationInfo.getBaseResourcePath();
}
}
@@ -13006,7 +12756,7 @@
}
final AsecInstallArgs args = new AsecInstallArgs(cid,
- getAppDexInstructionSets(ps), isForwardLocked(ps));
+ getAppDexInstructionSets(ps), ps.isForwardLocked());
// The package status is changed only if the code path
// matches between settings and the container id.
if (ps.codePathString != null
@@ -13288,7 +13038,7 @@
Slog.w(TAG, "No move required. Trying to move to same location");
returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
} else {
- if (isForwardLocked(pkg)) {
+ if (pkg.isForwardLocked()) {
currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 8ea0bee..06d842a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -64,4 +64,8 @@
public boolean isPrivileged() {
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
+
+ public boolean isForwardLocked() {
+ return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+ }
}
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
new file mode 100644
index 0000000..b8a3155
--- /dev/null
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.policy;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemClock;
+import android.view.Display;
+
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+public class BurnInProtectionHelper implements DisplayManager.DisplayListener {
+ private static final String TAG = "BurnInProtection";
+
+ // Default value when max burnin radius is not set.
+ public static final int BURN_IN_RADIUS_MAX_DEFAULT = -1;
+
+ private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
+ private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
+
+ private static final String ACTION_BURN_IN_PROTECTION =
+ "android.internal.policy.action.BURN_IN_PROTECTION";
+
+ private static final int BURN_IN_SHIFT_STEP = 2;
+
+ private boolean mBurnInProtectionActive;
+
+ private final int mMinHorizontalBurnInOffset;
+ private final int mMaxHorizontalBurnInOffset;
+ private final int mMinVerticalBurnInOffset;
+ private final int mMaxVerticalBurnInOffset;
+
+ private final int mBurnInRadiusMaxSquared;
+
+ private int mLastBurnInXOffset = 0;
+ /* 1 means increasing, -1 means decreasing */
+ private int mXOffsetDirection = 1;
+ private int mLastBurnInYOffset = 0;
+ /* 1 means increasing, -1 means decreasing */
+ private int mYOffsetDirection = 1;
+
+ private final AlarmManager mAlarmManager;
+ private final PendingIntent mBurnInProtectionIntent;
+ private final DisplayManagerInternal mDisplayManagerInternal;
+ private final Display mDisplay;
+
+ private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateBurnInProtection();
+ }
+ };
+
+ public BurnInProtectionHelper(Context context) {
+ final Resources resources = context.getResources();
+ mMinHorizontalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
+ mMaxHorizontalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
+ mMinVerticalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
+ mMaxVerticalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
+ int burnInRadiusMax = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMaxRadius);
+ if (burnInRadiusMax != BURN_IN_RADIUS_MAX_DEFAULT) {
+ mBurnInRadiusMaxSquared = burnInRadiusMax * burnInRadiusMax;
+ } else {
+ mBurnInRadiusMaxSquared = BURN_IN_RADIUS_MAX_DEFAULT;
+ }
+
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+ mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ context.registerReceiver(mBurnInProtectionReceiver,
+ new IntentFilter(ACTION_BURN_IN_PROTECTION));
+ Intent intent = new Intent(ACTION_BURN_IN_PROTECTION);
+ intent.setPackage(context.getPackageName());
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ DisplayManager displayManager =
+ (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ displayManager.registerDisplayListener(this, null /* handler */);
+ }
+
+ public void startBurnInProtection() {
+ if (!mBurnInProtectionActive) {
+ mBurnInProtectionActive = true;
+ updateBurnInProtection();
+ }
+ }
+
+ private void updateBurnInProtection() {
+ if (mBurnInProtectionActive) {
+ adjustOffsets();
+ mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
+ mLastBurnInXOffset, mLastBurnInYOffset);
+ // Next adjustment at least ten seconds in the future.
+ long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
+ // And aligned to the minute.
+ next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
+ + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
+ } else {
+ mAlarmManager.cancel(mBurnInProtectionIntent);
+ mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
+ }
+ }
+
+ public void cancelBurnInProtection() {
+ if (mBurnInProtectionActive) {
+ mBurnInProtectionActive = false;
+ updateBurnInProtection();
+ }
+ }
+
+ /**
+ * Gently shifts current burn-in offsets, minimizing the change for the user.
+ *
+ * Shifts are applied in following fashion:
+ * 1) shift horizontally from minimum to the maximum;
+ * 2) shift vertically by one from minimum to the maximum;
+ * 3) shift horizontally from maximum to the minimum;
+ * 4) shift vertically by one from minimum to the maximum.
+ * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum.
+ *
+ * On top of that, stay within specified radius. If the shift distance from the center is
+ * higher than the radius, skip these values and go the next position that is within the radius.
+ */
+ private void adjustOffsets() {
+ do {
+ // By default, let's just shift the X offset.
+ final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP;
+ mLastBurnInXOffset += xChange;
+ if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset
+ || mLastBurnInXOffset < mMinHorizontalBurnInOffset) {
+ // Whoops, we went too far horizontally. Let's retract..
+ mLastBurnInXOffset -= xChange;
+ // change horizontal direction..
+ mXOffsetDirection *= -1;
+ // and let's shift the Y offset.
+ final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP;
+ mLastBurnInYOffset += yChange;
+ if (mLastBurnInYOffset > mMaxVerticalBurnInOffset
+ || mLastBurnInYOffset < mMinVerticalBurnInOffset) {
+ // Whoops, we went to far vertically. Let's retract..
+ mLastBurnInYOffset -= yChange;
+ // and change vertical direction.
+ mYOffsetDirection *= -1;
+ }
+ }
+ // If we are outside of the radius, let's try again.
+ } while (mBurnInRadiusMaxSquared != BURN_IN_RADIUS_MAX_DEFAULT
+ && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
+ > mBurnInRadiusMaxSquared);
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TAG);
+ prefix += " ";
+ pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive);
+ pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", "
+ + mMaxHorizontalBurnInOffset + ")");
+ pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", "
+ + mMaxVerticalBurnInOffset + ")");
+ pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared);
+ pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", "
+ + mLastBurnInYOffset + ")");
+ pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", "
+ + mYOffsetDirection + ")");
+ }
+
+ @Override
+ public void onDisplayAdded(int i) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int i) {
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == mDisplay.getDisplayId()) {
+ if (mDisplay.getState() == Display.STATE_DOZE
+ || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+ startBurnInProtection();
+ } else {
+ cancelBurnInProtection();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f691b4e..c414072 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2006 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.
@@ -256,6 +257,7 @@
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
SearchManager mSearchManager;
AccessibilityManager mAccessibilityManager;
+ BurnInProtectionHelper mBurnInProtectionHelper;
// Vibrator pattern for haptic feedback of a long press.
long[] mLongPressVibePattern;
@@ -1185,6 +1187,10 @@
mWindowManagerFuncs = windowManagerFuncs;
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableBurnInProtection)){
+ mBurnInProtectionHelper = new BurnInProtectionHelper(context);
+ }
mHandler = new PolicyHandler();
mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
@@ -6457,5 +6463,8 @@
if (mOrientationListener != null) {
mOrientationListener.dump(pw, prefix);
}
+ if (mBurnInProtectionHelper != null) {
+ mBurnInProtectionHelper.dump(prefix, pw);
+ }
}
}
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 111c09b..de9360e 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -18,6 +18,7 @@
import com.android.server.EventLogTags;
import com.android.server.SystemService;
+import com.android.server.pm.InstructionSets;
import com.android.server.pm.PackageManagerService;
import android.app.Notification;
@@ -341,7 +342,7 @@
}
private static boolean isBootImageOnDisk() {
- for (String instructionSet : PackageManagerService.getAllDexCodeInstructionSets()) {
+ for (String instructionSet : InstructionSets.getAllDexCodeInstructionSets()) {
if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 62f2b48..5e4bd8b 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -93,7 +93,9 @@
}
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
mSurfaceControl.setPosition(0, 0);
- mOverlay.setBounds(0, 0, mScreenSize.x, mScreenSize.y);
+ // Always draw the overlay with square dimensions
+ int size = Math.max(mScreenSize.x, mScreenSize.y);
+ mOverlay.setBounds(0, 0, size, size);
mOverlay.draw(c);
mSurface.unlockCanvasAndPost(c);
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 3e1c5ff..6d09f55 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -93,10 +93,6 @@
// stack bounds once the stack is no longer forced to fullscreen.
final private Rect mPreForceFullscreenBounds;
- // When true this stack is at the top of the screen and should be layed out to extend under
- // the status bar.
- boolean mUnderStatusBar;
-
// Device rotation as of the last time {@link #mBounds} was set.
int mRotation;
@@ -106,7 +102,6 @@
mOverrideConfig = Configuration.EMPTY;
mForceFullscreen = false;
mPreForceFullscreenBounds = new Rect();
- mUnderStatusBar = true;
// TODO: remove bounds from log, they are always 0.
EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
mBounds.right, mBounds.bottom);
@@ -165,7 +160,6 @@
mDimLayer.setBounds(bounds);
mAnimationBackgroundSurface.setBounds(bounds);
mBounds.set(bounds);
- mUnderStatusBar = (mBounds.top == 0);
mRotation = rotation;
updateOverrideConfiguration();
return true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fde0bd5..7e69e87 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4316,8 +4316,13 @@
+ " ShowWallpaper="
+ ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false));
- if (ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+ final boolean windowIsTranslucentDefined = ent.array.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent);
+ final boolean windowIsTranslucent = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ final boolean windowSwipeToDismiss = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
+ if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
return;
}
if (ent.array.getBoolean(
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 04aea84..f94ed77 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,21 +16,21 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+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;
import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-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_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.app.AppOpsManager;
import android.os.Debug;
@@ -519,9 +519,15 @@
TaskStack stack = mAppToken != null ? getStack() : null;
if (stack != null && !stack.isFullscreen()) {
stack.getBounds(mContainingFrame);
- if (stack.mUnderStatusBar) {
- mContainingFrame.top = pf.top;
+ final WindowState imeWin = mService.mInputMethodWindow;
+ if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
+ && mContainingFrame.bottom > cf.bottom) {
+ // IME is up and obscuring this window. Adjust the window position so it is visible.
+ mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
}
+ // Make sure the containing frame is within the content frame so we don't layout
+ // resized window under screen decorations.
+ mContainingFrame.intersect(cf);
mDisplayFrame.set(mContainingFrame);
} else {
mContainingFrame.set(pf);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 770da5b..a19cd9f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -196,13 +196,11 @@
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE);
- GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.BLUETOOTH_ON);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.MODE_RINGER);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.NETWORK_PREFERENCE);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
- GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_ON);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY);
}
@@ -4053,16 +4051,18 @@
}
/**
- * Device owner can only be set on an unprovisioned device, unless it was initiated by "adb", in
- * which case we allow it if no account is associated with the device.
+ * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
+ * we also allow it if no accounts or additional users are present on the device.
*/
private boolean allowedToSetDeviceOwnerOnDevice() {
- int callingId = Binder.getCallingUid();
- if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
- return AccountManager.get(mContext).getAccounts().length == 0;
- } else {
- return !hasUserSetupCompleted(UserHandle.USER_OWNER);
+ if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ return true;
}
+
+ int callingId = Binder.getCallingUid();
+ return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
+ && mUserManager.getUserCount() == 1
+ && AccountManager.get(mContext).getAccounts().length == 0;
}
private void enforceCrossUserPermission(int userHandle) {
@@ -5267,8 +5267,13 @@
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
- throw new SecurityException(String.format(
- "Permission denial: device owners cannot update %1$s", setting));
+ // BLUETOOTH_ON and WIFI_ON used to be supported but not any more. We do not want to
+ // throw a SecurityException not to break apps.
+ if (!Settings.Global.BLUETOOTH_ON.equals(setting)
+ && !Settings.Global.WIFI_ON.equals(setting)) {
+ throw new SecurityException(String.format(
+ "Permission denial: device owners cannot update %1$s", setting));
+ }
}
long id = Binder.clearCallingIdentity();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index fd990d7..6b8c49c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -385,7 +385,7 @@
}
@Override
- public void startSession(IVoiceInteractionService service, Bundle args, int flags) {
+ public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
synchronized (this) {
if (mImpl == null || mImpl.mService == null
|| service.asBinder() != mImpl.mService.asBinder()) {
@@ -396,7 +396,7 @@
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
- mImpl.startSessionLocked(callingPid, callingUid, args, flags);
+ mImpl.showSessionLocked(callingPid, callingUid, args, flags);
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -424,6 +424,42 @@
}
@Override
+ public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "showSessionFromSession without running voice interaction service");
+ return false;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public boolean hideSessionFromSession(IBinder token) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
+ return false;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.hideSessionLocked(callingPid, callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
synchronized (this) {
if (mImpl == null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e80f702..9e92867 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -26,7 +26,6 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -35,20 +34,17 @@
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.IVoiceInteractionSessionService;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import android.util.Slog;
import android.view.IWindowManager;
-import android.view.WindowManager;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.IResultReceiver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-class VoiceInteractionManagerServiceImpl {
+class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
final static String TAG = "VoiceInteractionServiceManager";
final boolean mValid;
@@ -65,7 +61,7 @@
boolean mBound = false;
IVoiceInteractionService mService;
- SessionConnection mActiveSession;
+ VoiceInteractionSessionConnection mActiveSession;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -101,124 +97,6 @@
}
};
- final class SessionConnection implements ServiceConnection {
- final IBinder mToken = new Binder();
- final Bundle mArgs;
- final int mFlags;
- boolean mBound;
- IVoiceInteractionSessionService mService;
- IVoiceInteractionSession mSession;
- IVoiceInteractor mInteractor;
- boolean mHaveAssistData;
- Bundle mAssistData;
-
- final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
- @Override
- public void send(int resultCode, Bundle resultData) throws RemoteException {
- synchronized (mLock) {
- mHaveAssistData = true;
- mAssistData = resultData;
- if (mSession != null) {
- try {
- mSession.handleAssist(resultData);
- } catch (RemoteException e) {
- }
- }
- }
- }
- };
-
- SessionConnection(Bundle args, int flags) {
- mArgs = args;
- mFlags = flags;
- Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
- serviceIntent.setComponent(mSessionComponentName);
- mBound = mContext.bindServiceAsUser(serviceIntent, this,
- Context.BIND_AUTO_CREATE, new UserHandle(mUser));
- if (mBound) {
- try {
- mIWindowManager.addWindowToken(mToken,
- WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed adding window token", e);
- }
- if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
- try {
- mAm.requestAssistContextExtras(0, mAssistReceiver);
- } catch (RemoteException e) {
- }
- } else {
- mHaveAssistData = true;
- }
- } else {
- Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- mService = IVoiceInteractionSessionService.Stub.asInterface(service);
- if (mActiveSession == this) {
- try {
- mService.newSession(mToken, mArgs, mFlags);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed adding window token", e);
- }
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
-
- public void cancel() {
- if (mBound) {
- if (mSession != null) {
- try {
- mSession.destroy();
- } catch (RemoteException e) {
- Slog.w(TAG, "Voice interation session already dead");
- }
- }
- if (mSession != null) {
- try {
- mAm.finishVoiceTask(mSession);
- } catch (RemoteException e) {
- }
- }
- mContext.unbindService(this);
- try {
- mIWindowManager.removeWindowToken(mToken);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed removing window token", e);
- }
- mBound = false;
- mService = null;
- mSession = null;
- mInteractor = null;
- }
- }
-
- public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mToken="); pw.println(mToken);
- pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
- pw.print(prefix); pw.print("mFlags=0x"); pw.println(Integer.toHexString(mFlags));
- pw.print(prefix); pw.print("mBound="); pw.println(mBound);
- if (mBound) {
- pw.print(prefix); pw.print("mService="); pw.println(mService);
- pw.print(prefix); pw.print("mSession="); pw.println(mSession);
- pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
- }
- pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
- if (mHaveAssistData) {
- pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
- }
- }
- };
-
VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
int userHandle, ComponentName service) {
mContext = context;
@@ -256,12 +134,16 @@
mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
}
- public void startSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
- if (mActiveSession != null) {
- mActiveSession.cancel();
- mActiveSession = null;
+ public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
+ if (mActiveSession == null) {
+ mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
+ mUser, mContext, this, callingPid, callingUid);
}
- mActiveSession = new SessionConnection(args, flags);
+ return mActiveSession.showLocked(args, flags);
+ }
+
+ public boolean hideSessionLocked(int callingPid, int callingUid) {
+ return mActiveSession.hideLocked();
}
public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
@@ -270,14 +152,7 @@
Slog.w(TAG, "deliverNewSession does not match active session");
return false;
}
- mActiveSession.mSession = session;
- mActiveSession.mInteractor = interactor;
- if (mActiveSession.mHaveAssistData) {
- try {
- session.handleAssist(mActiveSession.mAssistData);
- } catch (RemoteException e) {
- }
- }
+ mActiveSession.deliverNewSessionLocked(session, interactor);
return true;
}
@@ -367,4 +242,11 @@
Slog.w(TAG, "RemoteException while calling soundModelsChanged", e);
}
}
+
+ @Override
+ public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
+ synchronized (mLock) {
+ finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken);
+ }
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
new file mode 100644
index 0000000..e2b47c3
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.voiceinteraction;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.IVoiceInteractionSessionService;
+import android.service.voice.VoiceInteractionService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+
+final class VoiceInteractionSessionConnection implements ServiceConnection {
+ final static String TAG = "VoiceInteractionServiceManager";
+
+ final IBinder mToken = new Binder();
+ final Object mLock;
+ final ComponentName mSessionComponentName;
+ final Intent mBindIntent;
+ final int mUser;
+ final Context mContext;
+ final Callback mCallback;
+ final int mCallingPid;
+ final int mCallingUid;
+ final IActivityManager mAm;
+ final IWindowManager mIWindowManager;
+ boolean mShown;
+ Bundle mShowArgs;
+ int mShowFlags;
+ boolean mBound;
+ boolean mFullyBound;
+ boolean mCanceled;
+ IVoiceInteractionSessionService mService;
+ IVoiceInteractionSession mSession;
+ IVoiceInteractor mInteractor;
+ boolean mHaveAssistData;
+ Bundle mAssistData;
+
+ public interface Callback {
+ public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
+ }
+
+ final ServiceConnection mFullConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ };
+
+ final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ synchronized (mLock) {
+ if (mShown) {
+ if (mSession != null) {
+ try {
+ mSession.handleAssist(resultData);
+ } catch (RemoteException e) {
+ }
+ } else {
+ mHaveAssistData = true;
+ mAssistData = resultData;
+ }
+ }
+ }
+ }
+ };
+
+ public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
+ Context context, Callback callback, int callingPid, int callingUid) {
+ mLock = lock;
+ mSessionComponentName = component;
+ mUser = user;
+ mContext = context;
+ mCallback = callback;
+ mCallingPid = callingPid;
+ mCallingUid = callingUid;
+ mAm = ActivityManagerNative.getDefault();
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ mBindIntent.setComponent(mSessionComponentName);
+ mBound = mContext.bindServiceAsUser(mBindIntent, this,
+ Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+ if (mBound) {
+ try {
+ mIWindowManager.addWindowToken(mToken,
+ WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed adding window token", e);
+ }
+ } else {
+ Slog.w(TAG, "Failed binding to voice interaction session service "
+ + mSessionComponentName);
+ }
+ }
+
+ public boolean showLocked(Bundle args, int flags) {
+ if (mBound) {
+ if (!mFullyBound) {
+ mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
+ Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY,
+ new UserHandle(mUser));
+ }
+ mShown = true;
+ mShowArgs = args;
+ mShowFlags = flags;
+ if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
+ try {
+ mAm.requestAssistContextExtras(0, mAssistReceiver);
+ } catch (RemoteException e) {
+ }
+ } else {
+ mHaveAssistData = false;
+ mAssistData = null;
+ }
+ if (mSession != null) {
+ try {
+ mSession.show(mShowArgs, mShowFlags);
+ mShowArgs = null;
+ mShowFlags = 0;
+ } catch (RemoteException e) {
+ }
+ if (mHaveAssistData) {
+ try {
+ mSession.handleAssist(mAssistData);
+ mAssistData = null;
+ mHaveAssistData = false;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hideLocked() {
+ if (mBound) {
+ if (mShown) {
+ mShown = false;
+ mShowArgs = null;
+ mShowFlags = 0;
+ mHaveAssistData = false;
+ mAssistData = null;
+ if (mSession != null) {
+ try {
+ mSession.hide();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ if (mFullyBound) {
+ mContext.unbindService(mFullConnection);
+ mFullyBound = false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean deliverNewSessionLocked(IVoiceInteractionSession session,
+ IVoiceInteractor interactor) {
+ mSession = session;
+ mInteractor = interactor;
+ if (mShown) {
+ try {
+ session.show(mShowArgs, mShowFlags);
+ mShowArgs = null;
+ mShowFlags = 0;
+ } catch (RemoteException e) {
+ }
+ if (mHaveAssistData) {
+ try {
+ session.handleAssist(mAssistData);
+ mAssistData = null;
+ mHaveAssistData = false;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = IVoiceInteractionSessionService.Stub.asInterface(service);
+ if (!mCanceled) {
+ try {
+ mService.newSession(mToken, mShowArgs, mShowFlags);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed adding window token", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mCallback.sessionConnectionGone(this);
+ mService = null;
+ }
+
+ public void cancel() {
+ mCanceled = true;
+ if (mBound) {
+ if (mSession != null) {
+ try {
+ mSession.destroy();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Voice interation session already dead");
+ }
+ }
+ if (mSession != null) {
+ try {
+ mAm.finishVoiceTask(mSession);
+ } catch (RemoteException e) {
+ }
+ }
+ mContext.unbindService(this);
+ try {
+ mIWindowManager.removeWindowToken(mToken);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed removing window token", e);
+ }
+ mBound = false;
+ mService = null;
+ mSession = null;
+ mInteractor = null;
+ }
+ if (mFullyBound) {
+ mContext.unbindService(mFullConnection);
+ mFullyBound = false;
+ }
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mToken="); pw.println(mToken);
+ pw.print(prefix); pw.print("mShown="); pw.println(mShown);
+ pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs);
+ pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags));
+ pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+ if (mBound) {
+ pw.print(prefix); pw.print("mService="); pw.println(mService);
+ pw.print(prefix); pw.print("mSession="); pw.println(mSession);
+ pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
+ }
+ pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
+ if (mHaveAssistData) {
+ pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
+ }
+ }
+};
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 3378872..cfbebba 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -480,6 +480,11 @@
}
@Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public int checkPermission(String permission, int pid, int uid) {
throw new UnsupportedOperationException();
}
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index adf572c..36d5d98 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -16,7 +16,8 @@
android:label="Test Assist Proxy"
android:theme="@android:style/Theme.NoDisplay"
android:excludeFromRecents="true"
- android:noHistory="true">
+ android:noHistory="true"
+ android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.ASSIST" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
index c4e280e..f4648b57 100644
--- a/tests/VoiceInteraction/res/layout/test_interaction.xml
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -48,4 +48,11 @@
android:text="@string/abortVoice"
/>
+ <Button android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/cancelVoice"
+ />
+
</LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 7eec90c..9f99c97 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -22,6 +22,7 @@
<string name="complete">Complete</string>
<string name="abortVoice">Abort Voice</string>
<string name="completeVoice">Complete Voice</string>
+ <string name="cancelVoice">Cancel</string>
</resources>
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
index fc04ff5..6a99351 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
@@ -29,6 +29,6 @@
Intent intent = new Intent(this, MainInteractionService.class);
intent.setAction(Intent.ACTION_ASSIST);
intent.putExtras(getIntent());
- startService(new Intent(this, MainInteractionService.class));
+ startService(intent);
}
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 5d5ae2f..d35bc5c 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -57,6 +57,11 @@
}
}
+ public void clearAssistData() {
+ mAssistData = null;
+ mTextRects.clear();
+ }
+
void buildTextRects(AssistData.ViewNode root, int parentLeft, int parentTop) {
if (root.getVisibility() != View.VISIBLE) {
return;
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 1aeb98a..1e30aff 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -49,6 +49,7 @@
static final int STATE_COMMAND = 3;
static final int STATE_ABORT_VOICE = 4;
static final int STATE_COMPLETE_VOICE = 5;
+ static final int STATE_DONE=6;
int mState = STATE_IDLE;
Request mPendingRequest;
@@ -60,12 +61,26 @@
@Override
public void onCreate(Bundle args, int startFlags) {
super.onCreate(args);
- showWindow();
+ }
+
+ @Override
+ public void onShow(Bundle args, int showFlags) {
+ super.onShow(args, showFlags);
+ mState = STATE_IDLE;
mStartIntent = args.getParcelable("intent");
Bundle assist = args.getBundle("assist");
- if (assist != null) {
- parseAssistData(assist);
+ parseAssistData(assist);
+ updateState();
+ }
+
+ @Override
+ public void onHide() {
+ super.onHide();
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.clearAssistData();
}
+ mState = STATE_DONE;
+ updateState();
}
@Override
@@ -86,7 +101,6 @@
mCompleteButton.setOnClickListener(this);
mAbortButton = (Button)mContentView.findViewById(R.id.abort);
mAbortButton.setOnClickListener(this);
- updateState();
return mContentView;
}
@@ -100,23 +114,35 @@
}
void parseAssistData(Bundle assistBundle) {
- Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- mAssistData = AssistData.getAssistData(assistContext);
- mAssistData.dump();
- if (mAssistVisualizer != null) {
- mAssistVisualizer.setAssistData(mAssistData);
+ if (assistBundle != null) {
+ Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+ if (assistContext != null) {
+ mAssistData = AssistData.getAssistData(assistContext);
+ mAssistData.dump();
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.setAssistData(mAssistData);
+ }
+ return;
}
}
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.clearAssistData();
+ }
}
void updateState() {
if (mState == STATE_IDLE) {
mTopContent.setVisibility(View.VISIBLE);
mBottomContent.setVisibility(View.GONE);
+ mAssistVisualizer.setVisibility(View.VISIBLE);
+ } else if (mState == STATE_DONE) {
+ mTopContent.setVisibility(View.GONE);
+ mBottomContent.setVisibility(View.GONE);
+ mAssistVisualizer.setVisibility(View.GONE);
} else {
mTopContent.setVisibility(View.GONE);
mBottomContent.setVisibility(View.VISIBLE);
+ mAssistVisualizer.setVisibility(View.GONE);
}
mStartButton.setEnabled(mState == STATE_IDLE);
mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND);
@@ -136,18 +162,12 @@
mPendingRequest.sendCommandResult(true, null);
}
mPendingRequest = null;
- mState = STATE_IDLE;
- updateState();
} else if (v == mAbortButton) {
mPendingRequest.sendAbortVoiceResult(null);
mPendingRequest = null;
- mState = STATE_IDLE;
- updateState();
} else if (v== mCompleteButton) {
mPendingRequest.sendCompleteVoiceResult(null);
mPendingRequest = null;
- mState = STATE_IDLE;
- updateState();
}
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index 8522cdc..023e0ec 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -31,8 +31,10 @@
static final String TAG = "TestInteractionActivity";
VoiceInteractor mInteractor;
+ VoiceInteractor.Request mCurrentRequest = null;
Button mAbortButton;
Button mCompleteButton;
+ Button mCancelButton;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -56,9 +58,11 @@
mAbortButton.setOnClickListener(this);
mCompleteButton = (Button)findViewById(R.id.complete);
mCompleteButton.setOnClickListener(this);
+ mCancelButton = (Button)findViewById(R.id.cancel);
+ mCancelButton.setOnClickListener(this);
mInteractor = getVoiceInteractor();
- VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest(
+ mCurrentRequest = new VoiceInteractor.ConfirmationRequest(
"This is a confirmation", null) {
@Override
public void onCancel() {
@@ -72,7 +76,7 @@
getActivity().finish();
}
};
- mInteractor.submitRequest(req);
+ mInteractor.submitRequest(mCurrentRequest);
}
@Override
@@ -112,6 +116,9 @@
}
};
mInteractor.submitRequest(req);
+ } else if (v == mCancelButton && mCurrentRequest != null) {
+ Log.i(TAG, "Cancel request");
+ mCurrentRequest.cancel();
}
}
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 8af4f50..5c6d870 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -132,10 +132,14 @@
if "extends" in raw:
self.extends = raw[raw.index("extends")+1]
+ self.extends_path = self.extends.split(".")
else:
self.extends = None
+ self.extends_path = []
self.fullname = self.pkg.name + "." + self.fullname
+ self.fullname_path = self.fullname.split(".")
+
self.name = self.fullname[self.fullname.rindex(".")+1:]
def __repr__(self):
@@ -150,6 +154,7 @@
raw = raw.split()
self.name = raw[raw.index("package")+1]
+ self.name_path = self.name.split(".")
def __repr__(self):
return self.raw
@@ -760,7 +765,7 @@
if not clazz.name.endswith("Manager"): return
for c in clazz.ctors:
- error(clazz, c, None, "Managers must always be obtained from Context")
+ error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
def verify_boxed(clazz):
@@ -846,35 +851,26 @@
"""Verifies that methods adding listener/callback have overload
for specifying delivery thread."""
- # Ignore UI components which deliver things on main thread
+ # Ignore UI packages which assume main thread
skip = [
- "android.animation",
- "android.view",
- "android.graphics",
- "android.transition",
- "android.widget",
- "android.webkit",
+ "animation",
+ "view",
+ "graphics",
+ "transition",
+ "widget",
+ "webkit",
]
for s in skip:
- if clazz.fullname.startswith(s): return
- if clazz.extends and clazz.extends.startswith(s): return
+ if s in clazz.pkg.name_path: return
+ if s in clazz.extends_path: return
- skip = [
- "android.app.ActionBar",
- "android.app.AlertDialog",
- "android.app.AlertDialog.Builder",
- "android.app.Application",
- "android.app.Activity",
- "android.app.Dialog",
- "android.app.Fragment",
- "android.app.FragmentManager",
- "android.app.LoaderManager",
- "android.app.ListActivity",
- "android.app.AlertDialog.Builder"
- "android.content.Loader",
- ]
- for s in skip:
- if clazz.fullname == s or clazz.extends == s: return
+ # Ignore UI classes which assume main thread
+ if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
+ for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
+ if s in clazz.fullname: return
+ if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
+ for s in ["Loader"]:
+ if s in clazz.fullname: return
found = {}
by_name = collections.defaultdict(list)
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 2f62b93..d88a867 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -17,6 +17,7 @@
package com.android.layoutlib.bridge.android;
import android.os.IBinder;
+
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -73,6 +74,7 @@
import android.view.BridgeInflater;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -495,6 +497,34 @@
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ if (serviceClass.equals(LayoutInflater.class)) {
+ return LAYOUT_INFLATER_SERVICE;
+ }
+
+ if (serviceClass.equals(TextServicesManager.class)) {
+ return TEXT_SERVICES_MANAGER_SERVICE;
+ }
+
+ if (serviceClass.equals(WindowManager.class)) {
+ return WINDOW_SERVICE;
+ }
+
+ if (serviceClass.equals(PowerManager.class)) {
+ return POWER_SERVICE;
+ }
+
+ if (serviceClass.equals(DisplayManager.class)) {
+ return DISPLAY_SERVICE;
+ }
+
+ if (serviceClass.equals(AccessibilityManager.class)) {
+ return ACCESSIBILITY_SERVICE;
+ }
+
+ throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
+ }
@Override
public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {