Merge "Fix isssue 2548710: Native AudioTrack resources never freed." into froyo
diff --git a/api/current.xml b/api/current.xml
index 6477fc4..34a0e00 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -25351,6 +25351,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="enableCarMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<method name="getCurrentModeType"
return="int"
abstract="false"
@@ -81445,7 +81458,7 @@
deprecated="not deprecated"
visibility="public"
>
-<method name="onAudioFocusChanged"
+<method name="onAudioFocusChange"
return="void"
abstract="true"
native="false"
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0007f58..a76dfb1 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -125,6 +125,22 @@
public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001;
/**
+ * Force device into car mode, like it had been placed in the car dock.
+ * This will cause the device to switch to the car home UI as part of
+ * the mode switch.
+ * @param flags Must be 0.
+ */
+ public void enableCarMode(int flags) {
+ if (mService != null) {
+ try {
+ mService.enableCarMode();
+ } catch (RemoteException e) {
+ Log.e(TAG, "disableCarMode: RemoteException", e);
+ }
+ }
+ }
+
+ /**
* Turn off special mode if currently in car mode.
* @param flags May be 0 or {@link #DISABLE_CAR_MODE_GO_HOME}.
*/
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 7f7d207..2a3f032 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -105,6 +105,7 @@
static final int KEEP_SCREEN_ON_MSG = 1;
static final int GET_NEW_SURFACE_MSG = 2;
+ static final int UPDATE_WINDOW_MSG = 3;
int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
@@ -120,6 +121,9 @@
case GET_NEW_SURFACE_MSG: {
handleGetNewSurface();
} break;
+ case UPDATE_WINDOW_MSG: {
+ updateWindow(false);
+ } break;
}
}
};
@@ -152,6 +156,9 @@
int mFormat = -1;
int mType = -1;
final Rect mSurfaceFrame = new Rect();
+ int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
+ boolean mUpdateWindowNeeded;
+ boolean mReportDrawNeeded;
private Translator mTranslator;
public SurfaceView(Context context) {
@@ -369,7 +376,8 @@
|| mNewSurfaceNeeded;
final boolean typeChanged = mType != mRequestedType;
if (force || creating || formatChanged || sizeChanged || visibleChanged
- || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
+ || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
+ || mUpdateWindowNeeded || mReportDrawNeeded) {
if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
@@ -425,28 +433,47 @@
mNewSurfaceNeeded = false;
- mSurfaceLock.lock();
- mDrawingStopped = !visible;
-
- final int relayoutResult = mSession.relayout(
- mWindow, mLayout, mWidth, mHeight,
- visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
- mVisibleInsets, mConfiguration, mSurface);
-
- if (localLOGV) Log.i(TAG, "New surface: " + mSurface
- + ", vis=" + visible + ", frame=" + mWinFrame);
+ boolean realSizeChanged;
+ boolean reportDrawNeeded;
- mSurfaceFrame.left = 0;
- mSurfaceFrame.top = 0;
- if (mTranslator == null) {
- mSurfaceFrame.right = mWinFrame.width();
- mSurfaceFrame.bottom = mWinFrame.height();
- } else {
- float appInvertedScale = mTranslator.applicationInvertedScale;
- mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
- mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
+ mSurfaceLock.lock();
+ try {
+ mUpdateWindowNeeded = false;
+ reportDrawNeeded = mReportDrawNeeded;
+ mReportDrawNeeded = false;
+ mDrawingStopped = !visible;
+
+ final int relayoutResult = mSession.relayout(
+ mWindow, mLayout, mWidth, mHeight,
+ visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
+ mVisibleInsets, mConfiguration, mSurface);
+ if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ mReportDrawNeeded = true;
+ }
+
+ if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+ + ", vis=" + visible + ", frame=" + mWinFrame);
+
+ mSurfaceFrame.left = 0;
+ mSurfaceFrame.top = 0;
+ if (mTranslator == null) {
+ mSurfaceFrame.right = mWinFrame.width();
+ mSurfaceFrame.bottom = mWinFrame.height();
+ } else {
+ float appInvertedScale = mTranslator.applicationInvertedScale;
+ mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
+ mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
+ }
+
+ final int surfaceWidth = mSurfaceFrame.right;
+ final int surfaceHeight = mSurfaceFrame.bottom;
+ realSizeChanged = mLastSurfaceWidth != surfaceWidth
+ || mLastSurfaceHeight != surfaceHeight;
+ mLastSurfaceWidth = surfaceWidth;
+ mLastSurfaceHeight = surfaceHeight;
+ } finally {
+ mSurfaceLock.unlock();
}
- mSurfaceLock.unlock();
try {
if (visible) {
@@ -465,9 +492,9 @@
}
}
if (creating || formatChanged || sizeChanged
- || visibleChanged) {
+ || visibleChanged || realSizeChanged) {
for (SurfaceHolder.Callback c : callbacks) {
- c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
+ c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
}
}
} else {
@@ -475,7 +502,7 @@
}
} finally {
mIsCreating = false;
- if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ if (creating || reportDrawNeeded) {
mSession.finishDrawing(mWindow);
}
}
@@ -533,17 +560,19 @@
if (localLOGV) Log.v(
"SurfaceView", surfaceView + " got resized: w=" +
w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
- synchronized (this) {
- if (mCurWidth != w || mCurHeight != h) {
- mCurWidth = w;
- mCurHeight = h;
- }
+ surfaceView.mSurfaceLock.lock();
+ try {
if (reportDraw) {
- try {
- surfaceView.mSession.finishDrawing(surfaceView.mWindow);
- } catch (RemoteException e) {
- }
+ surfaceView.mUpdateWindowNeeded = true;
+ surfaceView.mReportDrawNeeded = true;
+ surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
+ } else if (surfaceView.mWinFrame.width() != w
+ || surfaceView.mWinFrame.height() != h) {
+ surfaceView.mUpdateWindowNeeded = true;
+ surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
}
+ } finally {
+ surfaceView.mSurfaceLock.unlock();
}
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 8ef2aeb..66461a7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2483,16 +2483,9 @@
delta = Math.max(-(getHeight() - mPaddingBottom - mPaddingTop - 1), delta);
}
- // Check to see if we have bumped into the scroll limit
- View motionView = getChildAt(mMotionPosition - mFirstPosition);
- int oldTop = 0;
- if (motionView != null) {
- oldTop = motionView.getTop();
- }
+ final boolean atEnd = trackMotionScroll(delta, delta);
- trackMotionScroll(delta, delta);
-
- if (more) {
+ if (more && !atEnd) {
invalidate();
mLastFlingY = y;
post(this);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 20c2fe4..32a9146 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -1022,6 +1022,7 @@
onScrollChanged(x, y, oldX, oldY);
}
}
+ awakenScrollBars();
// Keep on drawing until the animation has finished.
postInvalidate();
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index a02aa00..873dc67 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1023,6 +1023,7 @@
onScrollChanged(x, y, oldX, oldY);
}
}
+ awakenScrollBars();
// Keep on drawing until the animation has finished.
postInvalidate();
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index ef9b66b..378bb6f 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -88,6 +88,8 @@
int envVer;
/* reference to our java self */
jobject me;
+ /* flag to indicate if the event loop thread is running */
+ bool running;
};
struct _Properties {
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 0e7fd66..259cc01 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -548,6 +548,8 @@
dbus_connection_set_watch_functions(nat->conn, dbusAddWatch,
dbusRemoveWatch, dbusToggleWatch, ptr, NULL);
+ nat->running = true;
+
while (1) {
for (int i = 0; i < nat->pollMemberCount; i++) {
if (!nat->pollData[i].revents) {
@@ -591,7 +593,7 @@
break;
}
}
- while (dbus_connection_dispatch(nat->conn) ==
+ while (dbus_connection_dispatch(nat->conn) ==
DBUS_DISPATCH_DATA_REMAINS) {
}
@@ -607,6 +609,8 @@
pthread_mutex_lock(&(nat->thread_mutex));
+ nat->running = false;
+
if (nat->pollData) {
LOGW("trying to start EventLoop a second time!");
pthread_mutex_unlock( &(nat->thread_mutex) );
@@ -703,6 +707,7 @@
nat->controlFdW = 0;
close(fd);
}
+ nat->running = false;
pthread_mutex_unlock(&(nat->thread_mutex));
#endif // HAVE_BLUETOOTH
}
@@ -713,7 +718,7 @@
native_data_t *nat = get_native_data(env, object);
pthread_mutex_lock(&(nat->thread_mutex));
- if (nat->pollData) {
+ if (nat->running) {
result = JNI_TRUE;
}
pthread_mutex_unlock(&(nat->thread_mutex));
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8eb5e96..9e3e8a4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -562,14 +562,6 @@
android:label="@string/permlab_changeConfiguration"
android:description="@string/permdesc_changeConfiguration" />
- <!-- Allows an application to enable the car mode.
- @hide -->
- <permission android:name="android.permission.ENABLE_CAR_MODE"
- android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signature"
- android:label="@string/permlab_enableCarMode"
- android:description="@string/permdesc_enableCarMode" />
-
<!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
API is no longer supported. -->
<permission android:name="android.permission.RESTART_PACKAGES"
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 76b58e1..c318577 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -46,5 +46,5 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
-
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index badcc1b..6475655 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -32,6 +32,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -58,6 +59,11 @@
public String mReason;
public boolean mScanResultIsAvailable = false;
public ConnectivityManager mCM;
+ public Object wifiObject = new Object();
+ public Object connectivityObject = new Object();
+ public int mWifiState;
+ public NetworkInfo mWifiNetworkInfo;
+ public String mBssid;
/*
* Control Wifi States
@@ -67,7 +73,7 @@
/*
* Verify connectivity state
*/
- public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE;
+ public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
/**
@@ -77,6 +83,7 @@
private class ConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
String action = intent.getAction();
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
@@ -100,10 +107,16 @@
mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
+
+ Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
+ if (mOtherNetworkInfo != null) {
+ Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
+ }
recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
if (mOtherNetworkInfo != null) {
recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
}
+ notifyNetworkConnectivityChange();
}
}
@@ -111,11 +124,25 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (!action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- Log.v(LOG_TAG, "onReceive() is calleld with " + intent);
+ Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
+ if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ notifyScanResult();
+ } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ mWifiNetworkInfo =
+ (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+ Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
+ if (mWifiNetworkInfo.getState() == State.CONNECTED) {
+ mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
+ }
+ notifyWifiState();
+ } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN);
+ notifyWifiState();
+ }
+ else {
return;
}
- notifyScanResult();
}
}
@@ -134,14 +161,19 @@
setContentView(contentView);
setTitle("ConnectivityManagerTestActivity");
- mConnectivityReceiver = new ConnectivityReceiver();
+
// register a connectivity receiver for CONNECTIVITY_ACTION;
+ mConnectivityReceiver = new ConnectivityReceiver();
registerReceiver(mConnectivityReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mWifiReceiver = new WifiReceiver();
- registerReceiver(mWifiReceiver,
- new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+ IntentFilter mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ registerReceiver(mWifiReceiver, mIntentFilter);
+
// Get an instance of ConnectivityManager
mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
// Get an instance of WifiManager
@@ -166,7 +198,7 @@
// deposit a network state
public void recordNetworkState(int networkType, State networkState) {
Log.v(LOG_TAG, "record network state for network " + networkType +
- " state is " + networkState);
+ ", state is " + networkState);
connectivityState[networkType].recordState(networkState);
}
@@ -190,6 +222,12 @@
return connectivityState[networkType].getReason();
}
+ private void notifyNetworkConnectivityChange() {
+ synchronized(connectivityObject) {
+ Log.v(LOG_TAG, "notify network connectivity changed");
+ connectivityObject.notifyAll();
+ }
+ }
private void notifyScanResult() {
synchronized (this) {
Log.v(LOG_TAG, "notify that scan results are available");
@@ -197,6 +235,13 @@
}
}
+ public void notifyWifiState() {
+ synchronized (wifiObject) {
+ Log.v(LOG_TAG, "notify wifi state changed");
+ wifiObject.notify();
+ }
+ }
+
// Return true if device is currently connected to mobile network
public boolean isConnectedToMobile() {
return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
@@ -259,9 +304,9 @@
config.SSID = sr.SSID;
config.allowedKeyManagement.set(KeyMgmt.NONE);
int networkId = mWifiManager.addNetwork(config);
- mWifiManager.saveConfiguration();
// Connect to network by disabling others.
mWifiManager.enableNetwork(networkId, true);
+ mWifiManager.saveConfiguration();
mWifiManager.reconnect();
break;
}
@@ -275,21 +320,17 @@
return true;
}
- /**
- * Disable Wifi
- * @return true if Wifi is disabled successfully
+ /*
+ * Disconnect from the current AP
*/
- public boolean disableWiFi() {
- return mWifiManager.setWifiEnabled(false);
- }
-
- /**
- * Disconnect from the current Wifi and clear the configuration list
- */
- public boolean clearWifi() {
- if (mWifiManager.isWifiEnabled()) {
+ public boolean disconnectAP() {
+ if (mWifiManager.isWifiEnabled()) {
//remove the current network Id
- int curNetworkId = mWifiManager.getConnectionInfo().getNetworkId();
+ WifiInfo curWifi = mWifiManager.getConnectionInfo();
+ if (curWifi == null) {
+ return false;
+ }
+ int curNetworkId = curWifi.getNetworkId();
mWifiManager.removeNetwork(curNetworkId);
mWifiManager.saveConfiguration();
@@ -303,16 +344,33 @@
mWifiManager.removeNetwork(conf.networkId);
}
}
- mWifiManager.saveConfiguration();
- // disable Wifi
+ }
+ mWifiManager.saveConfiguration();
+ return true;
+ }
+ /**
+ * Disable Wifi
+ * @return true if Wifi is disabled successfully
+ */
+ public boolean disableWifi() {
+ return mWifiManager.setWifiEnabled(false);
+ }
+
+ /**
+ * Disconnect from the current Wifi and clear the configuration list
+ */
+ public boolean clearWifi() {
+ if (!disconnectAP()) {
+ return false;
+ }
+ // Disable Wifi
if (!mWifiManager.setWifiEnabled(false)) {
return false;
}
- // wait for the actions to be completed
+ // Wait for the actions to be completed
try {
Thread.sleep(5*1000);
} catch (InterruptedException e) {}
- }
return true;
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
index 2e5a0f8..d586396 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
@@ -143,14 +143,14 @@
}
State lastState = mStateDepository.get(mStateDepository.size() - 1);
if ( lastState != mTransitionTarget) {
- mReason += " the last state should be CONNECTED, but it is " + lastState;
+ mReason += "The last state should be " + mTransitionTarget + ", but it is " + lastState;
return false;
}
for (int i = 1; i < mStateDepository.size(); i++) {
State preState = mStateDepository.get(i-1);
State curState = mStateDepository.get(i);
if ((preState == State.DISCONNECTED) && ((curState == State.CONNECTING) ||
- (curState == State.CONNECTED))) {
+ (curState == State.CONNECTED) || (curState == State.DISCONNECTED))) {
continue;
} else if ((preState == State.CONNECTING) && (curState == State.CONNECTED)) {
continue;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index ad564ae..7641afe 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-
-
package com.android.connectivitymanagertest.functional;
import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
import android.content.Intent;
import android.content.Context;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.app.Instrumentation;
import android.os.Handler;
import android.os.Message;
@@ -29,23 +29,24 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.NetworkInfo.DetailedState;
+import android.net.wifi.WifiManager;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import com.android.connectivitymanagertest.NetworkState;
import android.util.Log;
-import junit.framework.*;
public class ConnectivityManagerMobileTest
extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
-
private static final String LOG_TAG = "ConnectivityManagerMobileTest";
private static final String PKG_NAME = "com.android.connectivitymanagertest";
- private static final long WIFI_CONNECTION_TIMEOUT = 30 * 1000;
- private static final long WIFI_NOTIFICATION_TIMEOUT = 10 * 1000;
+ private static final long STATE_TRANSITION_SHORT_TIMEOUT = 5 * 1000;
+ private static final long STATE_TRANSITION_LONG_TIMEOUT = 30 * 1000;
+
private String TEST_ACCESS_POINT;
private ConnectivityManagerTestActivity cmActivity;
+ private WakeLock wl;
public ConnectivityManagerMobileTest() {
super(PKG_NAME, ConnectivityManagerTestActivity.class);
@@ -58,16 +59,22 @@
ConnectivityManagerTestRunner mRunner =
(ConnectivityManagerTestRunner)getInstrumentation();
TEST_ACCESS_POINT = mRunner.TEST_SSID;
+ PowerManager pm = (PowerManager)getInstrumentation().
+ getContext().getSystemService(Context.POWER_SERVICE);
+ wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "CMWakeLock");
+ wl.acquire();
// Each test case will start with cellular connection
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
verifyCellularConnection();
}
@Override
public void tearDown() throws Exception {
- // clear Wifi after each test case
- cmActivity.clearWifi();
cmActivity.finish();
- Log.v(LOG_TAG, "tear down ConnectivityManager test activity");
+ Log.v(LOG_TAG, "tear down ConnectivityManagerTestActivity");
+ wl.release();
+ cmActivity.clearWifi();
super.tearDown();
}
@@ -80,6 +87,66 @@
assertTrue("no data connection", cmActivity.mState.equals(State.CONNECTED));
}
+ // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
+ // DISCONNECTING, DISCONNECTED, UNKNOWN
+ private void waitForNetworkState(int networkType, State expectedState, long timeout) {
+ long startTime = System.currentTimeMillis();
+ // In case the broadcast is already sent out, no need to wait
+ if (cmActivity.mCM.getNetworkInfo(networkType).getState() == expectedState) {
+ return;
+ } else {
+ while (true) {
+ if ((System.currentTimeMillis() - startTime) > timeout) {
+ assertFalse("Wait for network state timeout", true);
+ }
+ Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+ " to be " + expectedState.toString());
+ synchronized (cmActivity.connectivityObject) {
+ try {
+ cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if ((cmActivity.mNetworkInfo.getType() != networkType) ||
+ (cmActivity.mNetworkInfo.getState() != expectedState)) {
+ Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
+ "is: " + cmActivity.mNetworkInfo.getState());
+ continue;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
+ // WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
+ private void waitForWifiState(int expectedState, long timeout) {
+ long startTime = System.currentTimeMillis();
+ if (cmActivity.mWifiState == expectedState) {
+ return;
+ } else {
+ while (true) {
+ if ((System.currentTimeMillis() - startTime) > timeout) {
+ assertFalse("Wait for Wifi state timeout", true);
+ }
+ Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+ synchronized (cmActivity.wifiObject) {
+ try {
+ cmActivity.wifiObject.wait(5*1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if (cmActivity.mWifiState != expectedState) {
+ Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
+ continue;
+ }
+ break;
+ }
+ }
+ }
+ }
+
// Test case 1: Test enabling Wifi without associating with any AP
@LargeTest
public void test3GToWifiNotification() {
@@ -94,7 +161,7 @@
// Eanble Wifi
cmActivity.enableWifi();
try {
- Thread.sleep(WIFI_NOTIFICATION_TIMEOUT);
+ Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT);
} catch (Exception e) {
Log.v(LOG_TAG, "exception: " + e.toString());
}
@@ -110,7 +177,7 @@
Log.v(LOG_TAG, "the state for MOBILE is changed");
Log.v(LOG_TAG, "reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
- assertTrue(false);
+ assertTrue("state validation fail", false);
}
// Verify that the device is still connected to MOBILE
verifyCellularConnection();
@@ -131,11 +198,13 @@
// Enable Wifi and connect to a test access point
assertTrue("failed to connect to " + TEST_ACCESS_POINT,
cmActivity.connectToWifi(TEST_ACCESS_POINT));
- try {
- Thread.sleep(WIFI_CONNECTION_TIMEOUT);
- } catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
- }
+
+ waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
+ Log.v(LOG_TAG, "wifi state is enabled");
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
// validate states
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -151,4 +220,318 @@
assertTrue(false);
}
}
+
+ // Test case 3: connect to Wifi with known AP
+ @LargeTest
+ public void testConnectToWifWithKnownAP() {
+ assertNotNull("SSID is null", TEST_ACCESS_POINT);
+ // Connect to TEST_ACCESS_POINT
+ assertTrue("failed to connect to " + TEST_ACCESS_POINT,
+ cmActivity.connectToWifi(TEST_ACCESS_POINT));
+ waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ try {
+ Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (Exception e) {
+ Log.v(LOG_TAG, "exception: " + e.toString());
+ }
+
+ // Disable Wifi
+ Log.v(LOG_TAG, "Disable Wifi");
+ if (!cmActivity.disableWifi()) {
+ Log.v(LOG_TAG, "disable Wifi failed");
+ return;
+ }
+
+ // Wait for the Wifi state to be DISABLED
+ waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ //Prepare for connectivity state verification
+ NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo.getState(), NetworkState.DO_NOTHING,
+ State.DISCONNECTED);
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ NetworkState.TO_CONNECTION, State.CONNECTED);
+
+ // Enable Wifi again
+ Log.v(LOG_TAG, "Enable Wifi again");
+ cmActivity.enableWifi();
+
+ // Wait for Wifi to be connected and mobile to be disconnected
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ // validate wifi states
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ Log.v(LOG_TAG, "Wifi state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ assertTrue(false);
+ }
+ }
+
+ // Test case 4: test disconnect Wifi
+ @LargeTest
+ public void testDisconnectWifi() {
+ assertNotNull("SSID is null", TEST_ACCESS_POINT);
+
+ // connect to Wifi
+ assertTrue("failed to connect to " + TEST_ACCESS_POINT,
+ cmActivity.connectToWifi(TEST_ACCESS_POINT));
+
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
+ try {
+ Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (Exception e) {
+ Log.v(LOG_TAG, "exception: " + e.toString());
+ }
+
+ NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo.getState(),
+ NetworkState.TO_CONNECTION,
+ State.CONNECTED);
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
+
+ // clear Wifi
+ cmActivity.clearWifi();
+
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ // validate states
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ Log.v(LOG_TAG, "Wifi state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ assertTrue(false);
+ }
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ Log.v(LOG_TAG, "Mobile state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ assertTrue(false);
+ }
+ }
+
+ // Test case 5: test connectivity from 3G to airplane mode, then to 3G again
+ @LargeTest
+ public void testDataConnectionWith3GToAmTo3G() {
+ //Prepare for state verification
+ NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo.getState(),
+ NetworkState.TO_DISCONNECTION,
+ State.DISCONNECTED);
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ assertEquals(State.DISCONNECTED, networkInfo.getState());
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ NetworkState.DO_NOTHING, State.DISCONNECTED);
+
+ // Enable airplane mode
+ cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+ try {
+ Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (Exception e) {
+ Log.v(LOG_TAG, "exception: " + e.toString());
+ }
+
+ // Validate the state transition
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ Log.v(LOG_TAG, "Wifi state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ assertTrue(false);
+ }
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ Log.v(LOG_TAG, "Mobile state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ assertTrue(false);
+ }
+
+ // reset state recorder
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo.getState(),
+ NetworkState.TO_CONNECTION,
+ State.CONNECTED);
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ NetworkState.DO_NOTHING, State.DISCONNECTED);
+
+ // disable airplane mode
+ cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ // Validate the state transition
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ Log.v(LOG_TAG, "Mobile state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ assertTrue(false);
+ }
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ Log.v(LOG_TAG, "Wifi state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ assertTrue(false);
+ }
+ }
+
+ // Test case 6: test connectivity with airplane mode Wifi connected
+ @LargeTest
+ public void testDataConnectionOverAMWithWifi() {
+ assertNotNull("SSID is null", TEST_ACCESS_POINT);
+ // Eanble airplane mode
+ cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo.getState(),
+ NetworkState.DO_NOTHING,
+ State.DISCONNECTED);
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ NetworkState.TO_CONNECTION, State.CONNECTED);
+
+ // Connect to Wifi
+ assertTrue("failed to connect to " + TEST_ACCESS_POINT,
+ cmActivity.connectToWifi(TEST_ACCESS_POINT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ // validate state and broadcast
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ Log.v(LOG_TAG, "state validate for Wifi failed");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ assertTrue("State validation failed", false);
+ }
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ Log.v(LOG_TAG, "state validation for Mobile failed");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ assertTrue("state validation failed", false);
+ }
+ cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ }
+
+ // Test case 7: test connectivity while transit from Wifi->AM->Wifi
+ @LargeTest
+ public void testDataConnectionWithWifiToAMToWifi () {
+ // Connect to TEST_ACCESS_POINT
+ assertNotNull("SSID is null", TEST_ACCESS_POINT);
+ // Connect to Wifi
+ assertTrue("failed to connect to " + TEST_ACCESS_POINT,
+ cmActivity.connectToWifi(TEST_ACCESS_POINT));
+
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ try {
+ Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (Exception e) {
+ Log.v(LOG_TAG, "exception: " + e.toString());
+ }
+
+ // Enable airplane mode without clearing Wifi
+ cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ try {
+ Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (Exception e) {
+ Log.v(LOG_TAG, "exception: " + e.toString());
+ }
+
+ // Prepare for state validation
+ NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo.getState(),NetworkState.DO_NOTHING,State.DISCONNECTED);
+ networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ assertEquals(State.DISCONNECTED, networkInfo.getState());
+ cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
+ networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);
+
+ // Disable airplane mode
+ cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ // validate the state transition
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ Log.v(LOG_TAG, "Wifi state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ assertTrue(false);
+ }
+ if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ Log.v(LOG_TAG, "Mobile state transition validation failed.");
+ Log.v(LOG_TAG, "reason: " +
+ cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ assertTrue(false);
+ }
+ }
+
+ // Test case 8: test wifi state change while connecting/disconnecting to/from an AP
+ @LargeTest
+ public void testWifiStateChange () {
+ assertNotNull("SSID is null", TEST_ACCESS_POINT);
+ //Connect to TEST_ACCESS_POINT
+ assertTrue("failed to connect to " + TEST_ACCESS_POINT,
+ cmActivity.connectToWifi(TEST_ACCESS_POINT));
+ waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+ assertNotNull("Not associated with any AP",
+ cmActivity.mWifiManager.getConnectionInfo().getBSSID());
+
+ try {
+ Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+ } catch (Exception e) {
+ Log.v(LOG_TAG, "exception: " + e.toString());
+ }
+
+ // Disconnect from the current AP
+ Log.v(LOG_TAG, "disconnect from the AP");
+ if (!cmActivity.disconnectAP()) {
+ Log.v(LOG_TAG, "failed to disconnect from " + TEST_ACCESS_POINT);
+ }
+
+ // Verify the connectivity state for Wifi is DISCONNECTED
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ STATE_TRANSITION_LONG_TIMEOUT);
+
+ if (!cmActivity.disableWifi()) {
+ Log.v(LOG_TAG, "disable Wifi failed");
+ return;
+ }
+ waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT);
+ }
}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index eb005ce..9972a8c 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -15,6 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:installLocation="internalOnly"
package="com.android.frameworks.coretests">
<permission android:name="com.android.frameworks.coretests.permission.TEST_GRANTED"
diff --git a/core/tests/coretests/res/raw/install_app1_cert1 b/core/tests/coretests/res/raw/install_app1_cert1
new file mode 100644
index 0000000..67eb2de
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app1_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert1_cert2 b/core/tests/coretests/res/raw/install_app1_cert1_cert2
new file mode 100644
index 0000000..dbafdc5
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app1_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert2 b/core/tests/coretests/res/raw/install_app1_cert2
new file mode 100644
index 0000000..e26c2eb
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert3 b/core/tests/coretests/res/raw/install_app1_cert3
new file mode 100644
index 0000000..fa10be7
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app1_cert3
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert3_cert4 b/core/tests/coretests/res/raw/install_app1_cert3_cert4
new file mode 100644
index 0000000..c2f6c81
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app1_cert3_cert4
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_unsigned b/core/tests/coretests/res/raw/install_app1_unsigned
new file mode 100644
index 0000000..18be5f8
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app1_unsigned
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert1 b/core/tests/coretests/res/raw/install_app2_cert1
new file mode 100644
index 0000000..b345732
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app2_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert1_cert2 b/core/tests/coretests/res/raw/install_app2_cert1_cert2
new file mode 100644
index 0000000..1faa257
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app2_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert2 b/core/tests/coretests/res/raw/install_app2_cert2
new file mode 100644
index 0000000..c3d5979
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app2_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert3 b/core/tests/coretests/res/raw/install_app2_cert3
new file mode 100644
index 0000000..ac0d9da
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app2_cert3
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_unsigned b/core/tests/coretests/res/raw/install_app2_unsigned
new file mode 100644
index 0000000..8d24e88
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_app2_unsigned
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert1 b/core/tests/coretests/res/raw/install_shared1_cert1
new file mode 100644
index 0000000..d702dab
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared1_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert12 b/core/tests/coretests/res/raw/install_shared1_cert12
new file mode 100644
index 0000000..b580b60
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared1_cert12
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert1_cert2 b/core/tests/coretests/res/raw/install_shared1_cert1_cert2
new file mode 100644
index 0000000..b580b60
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared1_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert2 b/core/tests/coretests/res/raw/install_shared1_cert2
new file mode 100644
index 0000000..a2de801
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_unsigned b/core/tests/coretests/res/raw/install_shared1_unsigned
new file mode 100644
index 0000000..35680be
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared1_unsigned
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert1 b/core/tests/coretests/res/raw/install_shared2_cert1
new file mode 100644
index 0000000..9064de7
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared2_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert12 b/core/tests/coretests/res/raw/install_shared2_cert12
new file mode 100644
index 0000000..26a250d
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared2_cert12
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert1_cert2 b/core/tests/coretests/res/raw/install_shared2_cert1_cert2
new file mode 100644
index 0000000..26a250d
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared2_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert2 b/core/tests/coretests/res/raw/install_shared2_cert2
new file mode 100644
index 0000000..7981308
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared2_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_unsigned b/core/tests/coretests/res/raw/install_shared2_unsigned
new file mode 100644
index 0000000..ad909fd
--- /dev/null
+++ b/core/tests/coretests/res/raw/install_shared2_unsigned
Binary files differ
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 7b9e95a..aec82afe 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -23,10 +23,18 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.DisplayMetrics;
+import android.util.Log;
import android.os.Environment;
import android.os.FileUtils;
import android.os.IBinder;
@@ -497,6 +505,15 @@
}
}
+ private PackageParser.Package getParsedPackage(String outFileName, int rawResId) {
+ PackageManager pm = mContext.getPackageManager();
+ File filesDir = mContext.getFilesDir();
+ File outFile = new File(filesDir, outFileName);
+ Uri packageURI = getInstallablePackage(rawResId, outFile);
+ PackageParser.Package pkg = parsePackage(packageURI);
+ return pkg;
+ }
+
/*
* Utility function that reads a apk bundled as a raw resource
* copies it into own data directory and invokes
@@ -529,7 +546,9 @@
if (fail) {
assertTrue(invokeInstallPackageFail(packageURI, flags,
pkg.packageName, result));
- assertNotInstalled(pkg.packageName);
+ if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
+ assertNotInstalled(pkg.packageName);
+ }
} else {
InstallReceiver receiver = new InstallReceiver(pkg.packageName);
assertTrue(invokeInstallPackage(packageURI, flags,
@@ -621,7 +640,7 @@
* PackageManager api to install first and then replace it
* again.
*/
- public void replaceFromRawResource(int flags) {
+ private void sampleReplaceFromRawResource(int flags) {
InstallParams ip = sampleInstallFromRawResource(flags, false);
boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
Log.i(TAG, "replace=" + replace);
@@ -648,28 +667,28 @@
}
public void testReplaceFailNormalInternal() {
- replaceFromRawResource(0);
+ sampleReplaceFromRawResource(0);
}
public void testReplaceFailFwdLockedInternal() {
- replaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
+ sampleReplaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
}
public void testReplaceFailSdcard() {
- replaceFromRawResource(PackageManager.INSTALL_EXTERNAL);
+ sampleReplaceFromRawResource(PackageManager.INSTALL_EXTERNAL);
}
public void testReplaceNormalInternal() {
- replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
+ sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
}
public void testReplaceFwdLockedInternal() {
- replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
+ sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
PackageManager.INSTALL_FORWARD_LOCK);
}
public void testReplaceSdcard() {
- replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
+ sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
PackageManager.INSTALL_EXTERNAL);
}
@@ -1014,6 +1033,19 @@
outFile.delete();
}
}
+ void cleanUpInstall(String pkgName) {
+ if (pkgName == null) {
+ return;
+ }
+ Log.i(TAG, "Deleting package : " + pkgName);
+ try {
+ ApplicationInfo info = getPm().getApplicationInfo(pkgName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ if (info != null) {
+ getPm().deletePackage(pkgName, null, 0);
+ }
+ } catch (NameNotFoundException e) {}
+ }
public void testManifestInstallLocationInternal() {
installFromRawResource("install.apk", R.raw.install_loc_internal,
@@ -2152,6 +2184,360 @@
}
}
+ /*
+ * The following series of tests are related to upgrading apps with
+ * different certificates.
+ */
+ private int APP1_UNSIGNED = R.raw.install_app1_unsigned;
+ private int APP1_CERT1 = R.raw.install_app1_cert1;
+ private int APP1_CERT2 = R.raw.install_app1_cert2;
+ private int APP1_CERT1_CERT2 = R.raw.install_app1_cert1_cert2;
+ private int APP1_CERT3_CERT4 = R.raw.install_app1_cert3_cert4;
+ private int APP1_CERT3 = R.raw.install_app1_cert3;
+ private int APP2_UNSIGNED = R.raw.install_app2_unsigned;
+ private int APP2_CERT1 = R.raw.install_app2_cert1;
+ private int APP2_CERT2 = R.raw.install_app2_cert2;
+ private int APP2_CERT1_CERT2 = R.raw.install_app2_cert1_cert2;
+ private int APP2_CERT3 = R.raw.install_app2_cert3;
+
+ private InstallParams replaceCerts(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode) {
+ int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+ String apk1Name = "install1.apk";
+ String apk2Name = "install2.apk";
+ PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
+ try {
+ InstallParams ip = installFromRawResource(apk1Name, apk1, 0, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ installFromRawResource(apk2Name, apk2, rFlags, false,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ return ip;
+ } catch (Exception e) {
+ failStr(e.getMessage());
+ } finally {
+ if (cleanUp) {
+ cleanUpInstall(pkg1.packageName);
+ }
+ }
+ return null;
+ }
+ /*
+ * Test that an app signed with two certificates can be upgraded by the
+ * same app signed with two certificates.
+ */
+ public void testReplaceMatchAllCerts() {
+ replaceCerts(APP1_CERT1_CERT2, APP1_CERT1_CERT2, true, false, -1);
+ }
+
+ /*
+ * Test that an app signed with two certificates cannot be upgraded
+ * by an app signed with a different certificate.
+ */
+ public void testReplaceMatchNoCerts1() {
+ replaceCerts(APP1_CERT1_CERT2, APP1_CERT3, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+ /*
+ * Test that an app signed with two certificates cannot be upgraded
+ * by an app signed with a different certificate.
+ */
+ public void testReplaceMatchNoCerts2() {
+ replaceCerts(APP1_CERT1_CERT2, APP1_CERT3_CERT4, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+ /*
+ * Test that an app signed with two certificates cannot be upgraded by
+ * an app signed with a subset of initial certificates.
+ */
+ public void testReplaceMatchSomeCerts1() {
+ replaceCerts(APP1_CERT1_CERT2, APP1_CERT1, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+ /*
+ * Test that an app signed with two certificates cannot be upgraded by
+ * an app signed with the last certificate.
+ */
+ public void testReplaceMatchSomeCerts2() {
+ replaceCerts(APP1_CERT1_CERT2, APP1_CERT2, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+ /*
+ * Test that an app signed with a certificate can be upgraded by app
+ * signed with a superset of certificates.
+ */
+ public void testReplaceMatchMoreCerts() {
+ replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+ /*
+ * Test that an app signed with a certificate can be upgraded by app
+ * signed with a superset of certificates. Then verify that the an app
+ * signed with the original set of certs cannot upgrade the new one.
+ */
+ public void testReplaceMatchMoreCertsReplaceSomeCerts() {
+ InstallParams ip = replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, false, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ try {
+ int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+ installFromRawResource("install.apk", APP1_CERT1, rFlags, false,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ } catch (Exception e) {
+ failStr(e.getMessage());
+ } finally {
+ if (ip != null) {
+ cleanUpInstall(ip);
+ }
+ }
+ }
+ /*
+ * The following tests are related to testing the checkSignatures
+ * api.
+ */
+ private void checkSignatures(int apk1, int apk2, int expMatchResult) {
+ checkSharedSignatures(apk1, apk2, true, false, -1, expMatchResult);
+ }
+ public void testCheckSignaturesAllMatch() {
+ int apk1 = APP1_CERT1_CERT2;
+ int apk2 = APP2_CERT1_CERT2;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
+ }
+ public void testCheckSignaturesNoMatch() {
+ int apk1 = APP1_CERT1;
+ int apk2 = APP2_CERT2;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
+ }
+ public void testCheckSignaturesSomeMatch1() {
+ int apk1 = APP1_CERT1_CERT2;
+ int apk2 = APP2_CERT1;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
+ }
+ public void testCheckSignaturesSomeMatch2() {
+ int apk1 = APP1_CERT1_CERT2;
+ int apk2 = APP2_CERT2;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
+ }
+ public void testCheckSignaturesMoreMatch() {
+ int apk1 = APP1_CERT1;
+ int apk2 = APP2_CERT1_CERT2;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
+ }
+ public void testCheckSignaturesUnknown() {
+ int apk1 = APP1_CERT1_CERT2;
+ int apk2 = APP2_CERT1_CERT2;
+ String apk1Name = "install1.apk";
+ String apk2Name = "install2.apk";
+ InstallParams ip1 = null;
+
+ try {
+ ip1 = installFromRawResource(apk1Name, apk1, 0, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ PackageManager pm = mContext.getPackageManager();
+ // Delete app2
+ File filesDir = mContext.getFilesDir();
+ File outFile = new File(filesDir, apk2Name);
+ int rawResId = apk2;
+ Uri packageURI = getInstallablePackage(rawResId, outFile);
+ PackageParser.Package pkg = parsePackage(packageURI);
+ getPm().deletePackage(pkg.packageName, null, 0);
+ // Check signatures now
+ int match = mContext.getPackageManager().checkSignatures(
+ ip1.pkg.packageName, pkg.packageName);
+ assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
+ } finally {
+ if (ip1 != null) {
+ cleanUpInstall(ip1);
+ }
+ }
+ }
+ public void testInstallNoCertificates() {
+ int apk1 = APP1_UNSIGNED;
+ String apk1Name = "install1.apk";
+ InstallParams ip1 = null;
+
+ try {
+ installFromRawResource(apk1Name, apk1, 0, false,
+ true, PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ } finally {
+ }
+ }
+ /* The following tests are related to apps using shared uids signed
+ * with different certs.
+ */
+ private int SHARED1_UNSIGNED = R.raw.install_shared1_unsigned;
+ private int SHARED1_CERT1 = R.raw.install_shared1_cert1;
+ private int SHARED1_CERT2 = R.raw.install_shared1_cert2;
+ private int SHARED1_CERT1_CERT2 = R.raw.install_shared1_cert1_cert2;
+ private int SHARED2_UNSIGNED = R.raw.install_shared2_unsigned;
+ private int SHARED2_CERT1 = R.raw.install_shared2_cert1;
+ private int SHARED2_CERT2 = R.raw.install_shared2_cert2;
+ private int SHARED2_CERT1_CERT2 = R.raw.install_shared2_cert1_cert2;
+ private void checkSharedSignatures(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode, int expMatchResult) {
+ String apk1Name = "install1.apk";
+ String apk2Name = "install2.apk";
+ PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
+ PackageParser.Package pkg2 = getParsedPackage(apk2Name, apk2);
+
+ try {
+ // Clean up before testing first.
+ cleanUpInstall(pkg1.packageName);
+ cleanUpInstall(pkg2.packageName);
+ installFromRawResource(apk1Name, apk1, 0, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ if (fail) {
+ installFromRawResource(apk2Name, apk2, 0, false,
+ true, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ } else {
+ installFromRawResource(apk2Name, apk2, 0, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ int match = mContext.getPackageManager().checkSignatures(
+ pkg1.packageName, pkg2.packageName);
+ assertEquals(expMatchResult, match);
+ }
+ } finally {
+ if (cleanUp) {
+ cleanUpInstall(pkg1.packageName);
+ cleanUpInstall(pkg2.packageName);
+ }
+ }
+ }
+ public void testCheckSignaturesSharedAllMatch() {
+ int apk1 = SHARED1_CERT1_CERT2;
+ int apk2 = SHARED2_CERT1_CERT2;
+ boolean fail = false;
+ int retCode = -1;
+ int expMatchResult = PackageManager.SIGNATURE_MATCH;
+ checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
+ }
+ public void testCheckSignaturesSharedNoMatch() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT2;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+ int expMatchResult = -1;
+ checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
+ }
+ /*
+ * Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert1 alone.
+ */
+ public void testCheckSignaturesSharedSomeMatch1() {
+ int apk1 = SHARED1_CERT1_CERT2;
+ int apk2 = SHARED2_CERT1;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+ int expMatchResult = -1;
+ checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
+ }
+ /*
+ * Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert2 alone.
+ */
+ public void testCheckSignaturesSharedSomeMatch2() {
+ int apk1 = SHARED1_CERT1_CERT2;
+ int apk2 = SHARED2_CERT2;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+ int expMatchResult = -1;
+ checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
+ }
+ public void testCheckSignaturesSharedUnknown() {
+ int apk1 = SHARED1_CERT1_CERT2;
+ int apk2 = SHARED2_CERT1_CERT2;
+ String apk1Name = "install1.apk";
+ String apk2Name = "install2.apk";
+ InstallParams ip1 = null;
+
+ try {
+ ip1 = installFromRawResource(apk1Name, apk1, 0, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ PackageManager pm = mContext.getPackageManager();
+ // Delete app2
+ PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
+ getPm().deletePackage(pkg.packageName, null, 0);
+ // Check signatures now
+ int match = mContext.getPackageManager().checkSignatures(
+ ip1.pkg.packageName, pkg.packageName);
+ assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
+ } finally {
+ if (ip1 != null) {
+ cleanUpInstall(ip1);
+ }
+ }
+ }
+
+ public void testReplaceFirstSharedMatchAllCerts() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT1;
+ int rapk1 = SHARED1_CERT1;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
+ replaceCerts(apk1, rapk1, true, false, -1);
+ }
+ public void testReplaceSecondSharedMatchAllCerts() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT1;
+ int rapk2 = SHARED2_CERT1;
+ checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
+ replaceCerts(apk2, rapk2, true, false, -1);
+ }
+ public void testReplaceFirstSharedMatchSomeCerts() {
+ int apk1 = SHARED1_CERT1_CERT2;
+ int apk2 = SHARED2_CERT1_CERT2;
+ int rapk1 = SHARED1_CERT1;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
+ installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ }
+ public void testReplaceSecondSharedMatchSomeCerts() {
+ int apk1 = SHARED1_CERT1_CERT2;
+ int apk2 = SHARED2_CERT1_CERT2;
+ int rapk2 = SHARED2_CERT1;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
+ installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ }
+ public void testReplaceFirstSharedMatchNoCerts() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT1;
+ int rapk1 = SHARED1_CERT2;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
+ installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ }
+ public void testReplaceSecondSharedMatchNoCerts() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT1;
+ int rapk2 = SHARED2_CERT2;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
+ installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ }
+ public void testReplaceFirstSharedMatchMoreCerts() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT1;
+ int rapk1 = SHARED1_CERT1_CERT2;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
+ installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ }
+ public void testReplaceSecondSharedMatchMoreCerts() {
+ int apk1 = SHARED1_CERT1;
+ int apk2 = SHARED2_CERT1;
+ int rapk2 = SHARED2_CERT1_CERT2;
+ boolean fail = true;
+ int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
+ installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
+ fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ }
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd
index e5a1b5e..26acf75 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd
@@ -1,4 +1,4 @@
-page.title=Icon Design Guidelines
+page.title=Icon Design Guidelines, Android 2.0
@jd:body
<div id="qv-wrapper">
@@ -8,9 +8,8 @@
<ul>
<li>You can use several types of icons in an Android application.</li>
-<li>Your icons should follow the specification in this document.</li>
-<li>A set of standard icons is provided by the Android platform. Your
-application can use the standard icons by referencing them as resources.</li>
+<li>Your icons should follow the general specification in this document.</li>
+<li>You should create separate icon sets for high-, medium-, and low-density screens.</li>
</ul>
<h2>In this document</h2>
@@ -23,13 +22,14 @@
<li><a href="#dialogstructure">Dialog icon</a></li>
<li><a href="#listviewstructure">List view icon</a></li>
-<li style="margin-top:4px;"><a href="#dodonts">General guidelines</a></li>
+<li style="margin-top:3px;"><a href="#design_tips">Tips for Designers</a></li>
<li><a href="#templatespack">Using the Icon Templates Pack</a></li>
+
<li><a href="#iconappendix">Icon appendix</a>
<ol>
- <li><a href="#launcherapx">Launcher icons</a></li>
- <li><a href="#menuapx">Menu icons</a></li>
- <li><a href="#statusbarapx">Status bar icons</a></li>
+ <li><a href="#launcherapx">Standard Launcher icons</a></li>
+ <li><a href="#menuapx">Standard Menu icons</a></li>
+ <li><a href="#statusbarapx">Standard Status bar icons</a></li>
</ol>
</li>
@@ -38,176 +38,560 @@
<h2>See also</h2>
<ol>
-<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
-Templates Pack »</a></li>
+<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a></li>
+<li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
+Templates Pack, v2.0 »</a></li>
</ol>
+<h2>Older versions</h2>
+
+<ol>
+<li style="margin-top:4px;"><a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design_1.html">Icon Design
+Guidelines, Android 1.0</a></li>
+<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
+Templates Pack, v1.0 »</a></li>
+</ol>
+
+
</div>
</div>
<p>Creating a unified look and feel throughout a user interface adds value to
your product. Streamlining the graphic style will also make the UI seem more
-professional to the user.</p>
+professional to users.</p>
-<p>This document shows you how to create icons for various parts
-of your application’s user interface that fit the style set by the Android UI
-team. Following these guidelines will help you to create a polished and unified
-experience for the user.</p>
+<p>This document provides information to help you create icons for various parts
+of your application’s user interface that match the general styles used by the
+Android 2.x framework. Following these guidelines will help you to create a
+polished and unified experience for the user.</p>
-<p>To get started creating conforming icons more quickly, you can download
+<p>To get started creating your icons more quickly, you can download
the Android Icon Templates Pack. For more information, see
<a href="#templatespack">Using the Android Icon Template Pack</a>.</p>
-<h2 id="launcherstructure">Launcher icon</h2>
-<p>A launcher icon is the graphic that represents your application on an Android
-device’s Home screen. It is a simplified 3D icon with a fixed perspective. The
-required perspective is shown in Figure 1.</p>
+<h2 id="icon-sets">Providing Density-Specific Icon Sets</h2>
-<h4 id="launcherstructure">Structure</h4>
+<p>Android is designed to run on a variety of devices that offer a range of
+screen sizes and resolutions. When you design the icons for your application,
+it's important keep in mind that your application may be installed on any of
+those devices. As described in the <a
+href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a> document, the Android platform makes it straightforward for you to
+provide icons in such a way that they will be displayed properly on any device,
+regardless of the device's screen size or resolution.</p>
-<ul>
-<li>The base of a launcher icon can face either the top view or the front
-view.</li>
+<p>In general, the recommended approach is to create a separate set of icons for
+each of the three generalized screen densities listed in Table 1, below, then
+store them in density-specific resource directories in your application. When
+your application runs, the Android platform will check the characteristics of
+the device screen and load icons from the appropriate density-specific
+resources. For more information about how to store density-specific resources in
+your application, see <a
+href="{@docRoot}guide/practices/screens_support.html#qualifiers">Resource
+directory qualifiers for screen size and density</a>. </p>
-<li>The majority of a launcher icon’s surface should be created using the
-launcher icon <a href="#launcherpalette">color palette</a>. To add emphasis, use
-one or more bright accent colors to highlight specific characteristics.</li>
-
-<li>All launcher icons must be created with rounded corners to make them look
-friendly and simple—as shown in Figure 2.</li>
-
-<li>All dimensions specified are based on a 250x250 pixel artboard size
-in a vector graphics editor like Adobe Illustrator, where the icon fits within
-the artboard boundaries.</li>
-
-<li><strong>Final art must be scaled down and exported as a transparent 48x48 px
-PNG file using a raster image editor such as Adobe Photoshop.</strong></li>
-
-<li>Templates for creating launcher icons in Adobe Illustrator and Photoshop are
-available in the Icon Templates Pack.</li>
-</ul>
-
-<table class="image-caption">
-<tr>
-<td class="image-caption-i" style="padding-right:0">
- <img src="{@docRoot}images/icon_design/launcher_structure.png" alt="A view of
-launcher icon corners and perspective angles" />
-</td>
-<td class="image-caption-c">
- <div class="caption grad-rule-top">
- <p><strong>Figure 1.</strong> Perspective angles for launcher icons (90° is
-vertical).</p>
- <div class="image-caption-nested">
- <table style="margin-top:0;">
- <tr><td style="padding-right:1em"><em>1.</em></td><td>92°</td></tr>
- <tr><td><em>2.</em></td><td>92°</td></tr>
- <tr><td><em>3.</em></td><td>173°</td></tr>
- <tr><td><em>4.</em></td><td>171°</td></tr>
- <tr><td><em>5.</em></td><td>49°</td></tr>
- <tr><td><em>6.</em></td><td>171°</td></tr>
- <tr><td><em>7.</em></td><td>64°</td></tr>
- <tr><td><em>8.</em></td><td>97°</td></tr>
- <tr><td><em>9.</em></td><td>75°</td></tr>
- <tr><td><em>10.</em></td><td>93°</td></tr>
- <tr><td><em>11.</em></td><td>169°</td></tr>
- </table>
- </div>
- </div>
- <div class="caption grad-rule-top">
- <p><strong>Figure 2.</strong> Rounded corners for launcher icons.</p>
- </div>
-</td>
-</tr>
-</table>
-
-<h4 id="launcherlight">Light, effects, and shadows</h4>
-
-<p>Launcher icons are simplified 3D icons using light and shadows for
-definition. A light source is placed slightly to the left in front of the icon,
-and therefore the shadow expands to the right and back.</p>
-
-<table class="image-caption">
-<tr>
-<td class="image-caption-i">
- <img src="{@docRoot}images/icon_design/launcher_light.png" alt="A view of
-light, effects, and shadows for launcher icons."/>
-</td>
-<td class="image-caption-c">
- <div class="caption grad-rule-top">
- <p><strong>Figure 3. </strong>Light, effects, and shadows for launcher icons.</p>
- <div class="image-caption-nested">
- <table style="margin-top:0;">
- <tr><td style="padding-right:1em"><em>1.</em></td><td>Edge highlight:</td><td>white</td></tr>
- <tr><td><em>2.</em></td><td>Icon shadow:</td><td>black | 20px blur<br>50% opacity | angle 67°</td></tr>
- <tr><td><em>3.</em></td><td>Front part:</td><td>Use light gradient from color palette</td></tr>
- <tr><td><em>4.</em></td><td>Detail shadow:</td><td>black | 10px blur<br>75% opacity</td></tr>
- <tr><td><em>5.</em></td><td> Side part:</td><td>Use medium gradient from color palette</td></tr>
- </table>
- </div>
- </div>
-</td>
-</tr>
-</table>
-
-<table style="margin:0px;padding:0px;">
-<tr>
-<td style="border:0;width:350px;">
-
-<h4 id="launcherpalette">Launcher icon color palette</h4>
-
-<table style="margin:0px;padding:0px;">
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_white.png" alt="Color palette, white" style="margin:.5em 0 0 0;" /></td>
-<td class="image-caption-c" style="padding-top:.5em;">White<br>r 0 | g 0 | b 0<br>Used for highlights on edges.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_light.png" alt="Color palette, light gradient" style="margin:.5em 0 0 0;" /></td>
-<td class="image-caption-c" style="padding-top:.5em;">Light gradient<br><em>1: </em>r 0 | g 0 | b 0<br><em>2: </em>r 217 | g 217 | b 217<br>Used on the front (lit) part of the icon.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_medium.png" alt="Color palette, medium gradien" style="margin:.5em 0 0 0;" /></td>
-<td class="image-caption-c" style="padding-top:.5em;">Medium gradient<br><em>1: </em>r 190 | g 190 | b 190<br><em>2: </em>r 115 | g 115 | b 115<br>Used on the side (shaded) part of the icon.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_dark.png" alt="Color palette, dark gradient" style="margin:.5em 0 0 0;" /></td>
-<td class="image-caption-c" style="padding-top:.5em;">Dark gradient<br><em>1: </em>r 100 | g 100 | b 100<br><em>2: </em>r 25 | g 25 | b 25<br>Used on details and parts in the shade of the icon.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_black.png" alt="Color palette, black" style="margin:.5em 0 0 0;" /></td>
-<td class="image-caption-c" style="padding-top:.5em;">Black<br>r 255 | g 255 | b 255<br>Used as base color in shadows.</td>
-</tr>
-
-</table>
-
-</td>
-
-<td style="border:0;width:350px">
-
-<h4 id="launchersteps">Step by step</h4>
+<p>The baseline screen density for Android devices is medium
+(<code>mdpi</code>). For this reason, a recommended approach to creating icon
+sets for multiple screen densities is to:</p>
<ol>
- <li>Create the basic shapes with a tool like Adobe Illustrator, using the
-angles described in <a href="#launcherstructure">Launcher icon: structure</a>.
-The shapes and effects must fit within a 250x250 pixel artboard.</li>
- <li>Add depth to shapes by extruding them and create the rounded corners as
-described for the launcher icon structure.</li>
- <li>Add details and colors. Gradients should be treated as if there is a light
-source placed slightly to the left in front of the icon.</li>
- <li>Create the shadows with the correct angle and blur effect.</li>
- <li>Import the icon into a tool like Adobe Photoshop and scale to fit an image
-size of 48x48 px on a transparent background.</li>
- <li>Export the icon at 48x48 as a PNG file with transparency enabled.</li>
+<li>Design the icons for the baseline density first (see Table 1 for the actual
+pixel dimensions at which to design the icons). </li>
+<li>Place the icons in the application's default drawable resources, then run
+the application on an Android Virtual Device (AVD) or an HVGA device such as the
+T-Mobile G1. </li>
+<li>Test and adjust your baseline icons as needed.</li>
+<li>When you are satisfied with the icons you've developed at the baseline
+density, create scaled copies for the other densities. </li>
+
+<ul>
+<li>Scale the baseline icons up 150% to create the high-density assets.</li>
+<li>Scale the baseline icons down 75% to create the low-density assets.</li>
+</ul></li>
+
+<li>Place the icons in density-specific resource directories in your
+application. For example:
+<ul>
+<li>Medium-density assets go in a <code>res/drawable-mdpi/</code>
+directory (or in the default <code>res/drawable/</code> directory),</li>
+<li>High-density assets go in a <code>res/drawable-hdpi/</code> directory,
+and</li>
+<li>Low-density assets go in a <code>res/drawable-ldpi/</code>
+directory.</li>
+</ul></li>
+<li>Test and adjust the high- and low-density icons if needed</li>
</ol>
+<p>For tips on how to create and manage icon sets for multiple densities, see
+<a href="#design_tips">Tips for Designers</a>.</p>
+
+
+<p class="caption"><strong>Table 1.</strong> Summary of finished icon
+dimensions for each of the three generalized screen densities, by
+icon type.</p>
+
+ <table id="screens-table" style="margin-top:2em;">
+ <tbody>
+<tr>
+<th>Icon Type</th><th colspan="3">Standard Asset Sizes (in Pixels), for
+Generalized Screen Densities</th></tr>
+ <tr>
+ <td></td>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ <nobr>Low density screen <em>(ldpi)</em></nobr>
+ </th>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ <nobr>Medium density screen <em>(mdpi)</em></nobr>
+ </th>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ <nobr>High density screen <em>(hdpi)</em><nobr>
+ </th>
+ </tr>
+
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Launcher
+ </th>
+ <td style="font-size:.9em;">
+ 36 x 36 px
+ </td>
+
+ <td style="font-size:.9em;">
+ 48 x 48 px
+ </td>
+ <td style="font-size:.9em;">
+ 72 x 72 px
+ </td>
+ </tr>
+
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Menu
+ </th>
+ <td style="font-size:.9em;">
+ 36 x 36 px
+ </td>
+
+ <td style="font-size:.9em;">
+ 48 x 48 px
+ </td>
+ <td style="font-size:.9em;">
+ 72 x 72 px
+ </td>
+ </tr>
+
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Status Bar
+ </th>
+ <td style="font-size:.9em;">
+ 24 x 24 px
+ </td>
+
+ <td style="font-size:.9em;">
+ 32 x 32 px
+ </td>
+ <td style="font-size:.9em;">
+ 48 x 48 px
+ </td>
+ </tr>
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Tab
+ </th>
+ <td style="font-size:.9em;">
+ 24 x 24 px
+ </td>
+
+ <td style="font-size:.9em;">
+ 32 x 32 px
+ </td>
+ <td style="font-size:.9em;">
+ 48 x 48 px
+ </td>
+ </tr>
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Dialog
+ </th>
+ <td style="font-size:.9em;">
+ 24 x 24 px
+ </td>
+
+ <td style="font-size:.9em;">
+ 32 x 32 px
+ </td>
+ <td style="font-size:.9em;">
+ 48 x 48 px
+ </td>
+ </tr>
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ List View
+ </th>
+ <td style="font-size:.9em;">
+ 24 x 24 px
+ </td>
+
+ <td style="font-size:.9em;">
+ 32 x 32 px
+ </td>
+ <td style="font-size:.9em;">
+ 48 x 48 px
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+<h2 id="launcherstructure">Launcher Icon</h2>
+
+<p>A Launcher icon is a graphic that represents your application on the device’s
+Home screen and in the Launcher window. </p>
+
+<p>The user opens the Launcher by touching the icon at the bottom of the Home
+screen. The Launcher opens and exposes the icons for all of the installed
+applications, which are arranged in a grid. The user selects an application and
+opens it by touching the Launcher icon or by means of any hardware navigation
+controls available, such as a trackball or d-pad. </p>
+
+<p>The user can also drag an icon out of the Launcher window and onto the Home
+screen itself, for more convenient access to the application. In this case, the
+system displays your application's Launcher icon against the Home screen
+wallpaper, rendering it at the same dimensions as it is rendered inside the
+Launcher.</p>
+
+<p>The system manages the scaling of all Launcher icons so that they rendered at
+a uniform height and width. The actual pixel dimensions of the rendered Launcher
+icons on any given device varies, based on the size and pixel-density
+characteristics of the device's screen. To ensure the best possible rendering
+for your icons, supply versions of the icons that are designed for low, medium,
+and high density screens. For information, see <a
+href="#icon_sets">Providing Density-Specific Icon Sets</a>, above, or <a
+href="#design_tips">Tips for Designers</a>, below.</p>
+
+<h3 id="style">Style</h3>
+
+<p>The launcher icons that you create should follow the general style principles
+below. The guidelines aren't meant to restrict what you can do with your icons,
+but rather they are meant to emphasize the common approaches that your icons can
+share with others on the device. Figure 1, at right, provides examples. </p>
+
+<div class="figure" style="padding:3em">
+ <img src="{@docRoot}images/icon_design/IconGraphic_Icons_i.png"
+ width="340">
+ <p class="caption" style="margin:0;padding:0;margin-left:36px;">
+ <strong>Figure 1.</strong> Illustration of Launcher icon style.</p>
+</div>
+
+<p>Clean and contemporary:</p>
+
+<ul>
+ <li>Launcher icons should be current and sometimes quirky, but they should not
+appear aged or ragged. You should avoid overused symbolic metaphors whenever
+possible.</li>
+</ul>
+
+<p>Simple and iconic:</p>
+<ul>
+ <li> Android Launcher icons are caricatural in nature; your icons should be
+highly simplified and exaggerated, so that they are appropriate for use at small
+sizes. Your icons should not be overly complicated. </li>
+ <li>Try featuring a single part of an application as a symbolic
+representation of the whole (for example, the Music icon features a speaker).
+</li>
+ <li>Consider using natural outlines and shapes, both geometric and organic,
+with a realistic (but never photorealistic) rendering. </li>
+ <li>Your icons <em>should not</em> present a cropped view of a larger
+image.</li>
+</ul>
+
+<p>Tactile and textured:</p>
+<ul>
+ <li>Icons should feature non-glossy, textured material. See
+ <a href="#materials-colors">Materials and colors</a>, below, for more
+ information.</li>
+</ul>
+
+<p>Forward-facing and top-lit:</p>
+<ul>
+ <li><em>New for Android 2.0 and later platforms</em>: Android Launcher
+icons should be forward-facing, with very little perspective, and they
+should be top-lit.</li>
+</ul>
+
+Additionally, note all icons will have separate text labels, so rather than
+working to include embedded text in the design of of your icons, focus your
+efforts on the icon's visual distinctiveness and memorability instead.</p>
+
+<p>To look at more examples of the Launcher icons used by built-in Android
+applications, see <a href="#launcherapx">Standard Launcher Icons</a> in the
+Icons Appendix of this document. </p>
+
+
+
+<h3 id="dodonts">Do's and Don'ts</h3>
+
+<p>Below are some "do and don't" examples to consider when creating icons for
+your application. </p>
+
+
+<table>
+<tr>
+<td style="border:0;width:50%;">
+
+<h4>Android Launcher icons are...</h4>
+
+<ul>
+<li>Modern, minimal, matte, tactile, and textured</li>
+<li>Forward-facing and top-lit, whole, limited in color
+palette</li>
+</ul>
+</td>
+<td style="border:0;width:50%;">
+
+<h4>Android Launcher icons are not...</h4>
+
+<ul>
+<li>Antique, over-complicated, glossy, flat vector</li>
+<li>Rotated, Cropped, Over-Saturated</li>
+</ul>
+</td>
+</tr>
+<tr>
+</table>
+
+<div style="margin-left:2em">
+<img src="{@docRoot}images/icon_design/IconGraphic_DosDonts.png" alt="Side-by-side examples
+of good/bad icon design." />
+<p class="caption" style="margin-top:.5em;">
+<strong>Figure 2.</strong> Side-by-side examples of "do's and don'ts" for
+Android launcher icons. </p>
+</div>
+
+<h3 id="materials-colors">Materials and colors</h3>
+
+<p>Launcher icons should make use of tactile, top-lit, textured materials. Even
+if your icon is just a simple shape, you should try to render in a way that
+makes it appear to be sculpted from some real-world material.</p>
+
+<p>The Launcher icons for the platform's default applications use the set of
+materials shown in Figure 3, below. Your icons can use these materials or you
+can create new materials.</p>
+
+<p>Android launcher icons usually consist of a smaller shape within a
+larger base shape and combine one neutral and one primary color. Icons may
+use a combination of neutral colors but should maintain a fairly high level of
+contrast. Icons should not use more than one primary color per icon, if
+possible.</p>
+
+<p>Launcher icons should use a limited color palette that includes a range
+of neutral and primary colors. The icons should not be over-saturated.</p>
+
+<p>The recommended color palette to use for Launcher icons is shown in Figure 4.
+You can use elements of the palette for both the base color and the highlight
+color. You can use the colors of the palette in conjunction with a
+white-to-black vertical linear gradient overlay. This creates the impression
+that the icon is lit from above and keeps the color less saturated.</p>
+
+
+
+<div style="margin:2em">
+<img src="{@docRoot}images/icon_design/IconGraphic_Materials.png" width="450" style="padding-top:2px;">
+<p class="caption" style="margin-top:.5em;">
+<strong>Figure 3.</strong> Example materials that you can use to create
+your icons.</p>
+</div>
+
+<div style="margin:2em">
+<img src="{@docRoot}images/icon_design/IconGraphic_AccentColor.png" width="450">
+<p class="caption" xstyle="margin-top:.5em;">
+<strong>Figure 4.</strong> Examples of materials combined with base
+and highlight colors from the recommended palette.</p>
+</div>
+
+
+<p>When you combine the materials above with a color highlight from the
+recommended pallete, you can create materials combinations such as those shown
+in Figure 5. To get you started, the <a href="#templatespack">icons pack</a>
+includes a Photoshop template file (<code>Launcher-icon-template.psd</code>)
+that provides all of the default materials, colors, and gradients. </p>
+
+<div style="margin:2em">
+<img src="{@docRoot}images/icon_design/IconGraphic_Colors.png" width="450" style="padding-top:2px;">
+<p class="caption" style="margin-top:.5em;">
+<strong>Figure 5.</strong> Recommended color palette for icons.</p>
+</div>
+
+
+<h3 id="size">Size and positioning</h3>
+
+<p>Launcher icons should use a variety of shapes and forms and those must be
+scaled and positioned to create consistent visual weight.</p>
+
+<p>Launcher icons should use a variety of shapes and forms and those must be
+scaled and positioned inside the asset to create consistent visual weight with
+other </p>
+
+<p>Figure 6 illustrates various ways of positioning the icon inside the asset.
+As detailed in the table below, you should size the icons <em>smaller than the
+actual bounds of the asset</em>, to create a consistent visual weight and to
+allow for the inclusion of shadows. If your icon is square or nearly square, it
+should be scaled even smaller.</p>
+
+
+<ul>
+<li>The bounding box for the full asset is shown in red.</li>
+<li>The recommended bounding box for the actual icon itself is shown in blue.
+The icon box is sized smaller than the full asset box so that there is space to
+include shadows and special icon treatments. </li>
+<li>The recommended bounding box for an icon that is square is shown in orange.
+The box for square icons is smaller than that for other icons to establish a
+consistent visual weight across the two types.</li>
+</ul>
+
+<table style="margin:2.5em 0 1em 0;">
+<tr>
+
+<td style="border:0;padding-left:72;">
+<ol class="nolist">
+ <li>Icon dimensions for high-density (<code>hdpi</code>) screens:</li>
+ <ol class="nolist">
+ <li>Full Asset: 72 x 72 px</li>
+ <li>Icon: 60 x 60 px</li>
+ <li>Square Icon: 56 x 56 px</li>
+ </ol>
+ </li>
+</ol>
+</td>
+<td style="border:0;">
+ <img src="{@docRoot}images/icon_design/IconGraphic_OpticalSize_l.png"
+ style="padding:0;margin:0;" width="450">
+</td>
+</tr>
+<tr>
+<td style="border:0;">
+ <ol class="nolist">
+ <li>Icon Dimensions for medium-density (<code>mdpi</code>) screens:</li>
+ <ol class="nolist">
+ <li>Full Asset: 48 x 48 px</li>
+ <li>Icon: 40 x 40 px</li>
+ <li>Square Icon: 38 x 38 px</li>
+ </ol>
+ </li>
+</ol>
+</td>
+
+<td style="border:0;padding-left:72;">
+ <img src="{@docRoot}images/icon_design/IconGraphic_OpticalSize_s.png"
+ style="padding:0;margin:0;" width="450">
+</td>
+</tr>
+<tr>
+<td style="border:0;">
+ <ol class="nolist">
+ <li>Icon Dimensions for low-density (<code>ldpi</code>) screens:</li>
+ <ol class="nolist">
+ <li>Full Asset: 36 x 36 px</li>
+ <li>Icon: 30 x 30 px</li>
+ <li>Square Icon: 28 x 28 px</li>
+ </ol>
+ </li>
+</ol>
+</td>
+
+<td style="border:0;padding-left:72;">
+ <img src="{@docRoot}images/icon_design/IconGraphic_OpticalSize_ldpi.png"
+ style="padding:0;margin:0;" width="450">
+
+ <p class="caption" style="margin:0;padding:0;margin-top:1.5em;"><strong>Figure
+ 6.</strong> Icon sizing and positioning inside the bounds of the
+ icon asset.</p>
+</td>
+</tr>
+
+</table>
+
+
+
+<h3>Using the Launcher Icon Template</h3>
+
+<p>Included in the Android Icon Templates Pack 2.0 is a template containing
+palettes for default icon materials and colors. The template is provided in .psd
+format for Adobe Photoshop or similar raster image editor. </p>
+
+<p>To get started, first <a
+href="{@docRoot}shareables/icon_templates-v2.0.zip">download the Android Icon
+Templates Pack 2.0 »</a>. </p>
+
+<p>Once you've downloaded the pack, unzip it and open the file
+<code>Launcher-icon-template.psd</code> in Adobe Photoshop or similar raster
+image editing program. Notice the palettes for materials and colors. You can
+use as the template as a starting point for creating your Launcher icons. </p>
+
+<p>After you create your icon, you can add a shadow effect according to the
+specification below, as appropriate for the size of image you are creating. </p>
+
+
+<table style="margin:2.5em 0 1em 0;">
+<tr>
+
+<td style="border:0;padding-left:72;">
+ <img src="{@docRoot}images/icon_design/IconGraphic_Shadow_WVGA.png"
+ style="padding:0;margin:0;" width="450">
+</td>
+<td style="border:0;">
+<p style="padding-top:.5em;">Shadow for WVGA (high density) sreens:</p>
+ <ol class="nolist">
+ <li>Effect: Drop Shadow</li>
+ <li>Color: #000000</li>
+ <li>Blend Mode: Multiply</li>
+ <li>Opacity: 75%</li>
+ <li>Angle: 90°</li>
+ <li>Distance: 2px</li>
+ <li>Spread: 0% </li>
+ <li>Size: 5px </li>
+ </ol>
+</li>
+</ol>
+</td>
+</tr>
+<tr>
+<td style="border:0;padding-left:72;">
+ <img src="{@docRoot}images/icon_design/IconGraphic_Shadow_HVGA.png"
+ style="padding:0;margin:0;" width="450">
+</td>
+
+<td style="border:0;">
+<p style="padding-top:.5em;">Shadow for HVGA (medium density) sreens:</p>
+ <ol class="nolist">
+ <li>Effect: Drop Shadow</li>
+ <li>Color: #000000</li>
+ <li>Blend Mode: Multiply</li>
+ <li>Opacity: 75%</li>
+ <li>Angle: 90°</li>
+ <li>Distance: 1px</li>
+ <li>Spread: 0% </li>
+ <li>Size: 3px </li>
+ </ol>
+</li>
+</ol>
</td>
</tr>
</table>
+<p>When the shadow is added and the icon is complete, export it as a PNG file
+with transparency enabled, ensuring that you size the icon at 72 x 72px for
+high-density screens and 48 x 48px for medium density screens. For more
+information about why you should provide different Launcher assets for high-,
+medium, and low-density screens, see <a
+href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a>.</p>
+
+
+
<h2 id="menustructure">Menu icon</h2>
<p>Menu icons are graphical elements placed in the pop-up menu shown to users
@@ -222,7 +606,7 @@
menu icon <a href="#menupalette">color palette</a>. </li>
<li>Menu icons should include rounded corners, but only when logically
-appropriate. For example, in Figure 3 the logical place for rounded corners is
+appropriate. For example, in Figure 7 the logical place for rounded corners is
the roof and not the rest of the building.</span></li>
<li>All dimensions specified on this page are based on a 48x48 pixel artboard
@@ -247,7 +631,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 4. </strong>Safeframe and corner-rounding for menu
+ <p><strong>Figure 7. </strong>Safeframe and corner-rounding for menu
icons. Icon size is 48x48.</p>
</div>
</td>
@@ -263,11 +647,11 @@
<table class="image-caption">
<tr>
<td class="image-caption-i">
- <img src="{@docRoot}images/icon_design/menu_light.png" alt="A view of light, effects, and shadows for launcher icons."/>
+ <img src="{@docRoot}images/icon_design/menu_light.png" alt="A view of light, effects, and shadows for menu icons."/>
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 5. </strong>Light, effects, and shadows for launcher icons.</p>
+ <p><strong>Figure 8. </strong>Light, effects, and shadows for menu icons.</p>
<div class="image-caption-nested">
<table style="margin-top:0;">
<tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>Use fill gradient from primary color palette</td></tr>
@@ -315,7 +699,7 @@
<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
<li>Import the shape into a tool like Adobe Photoshop and scale to fit an image
of 48x48 px on a transparent background. Mind the safeframe.</li>
-<li>Add the effects seen as described in Figure 5.</li>
+<li>Add the effects seen as described in Figure 8.</li>
<li>Export the icon at 48x48 as a PNG file with transparency enabled.</li>
</ol>
@@ -323,6 +707,14 @@
</tr>
</table>
+<h4 id="dodonts_menu">"Do's and don'ts"</h4>
+
+<p>Below are some "do and don't" examples to consider when creating menu icons for
+your application. </p>
+
+
+<img src="{@docRoot}images/icon_design/do_dont_menuicons.png" style="padding:0;margin:0;padding-right:30%" width="400">
+
<h2 id="statusbarstructure">Status bar icon</h2>
@@ -334,7 +726,7 @@
<ul>
<li>Rounded corners must always be applied to the base shape and to the details
-of a status bar icon shown Figure 7.</li>
+of a status bar icon shown Figure 9.</li>
<li>All dimensions specified are based on a 25x25 pixel artboard size with a 2
pixel safeframe.</li>
@@ -356,7 +748,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 6. </strong>Safeframe and corner-rounding for status bar
+ <p><strong>Figure 9. </strong>Safeframe and corner-rounding for status bar
icons. Icon size is 25x25.</p>
</div>
</td>
@@ -373,11 +765,11 @@
<tr>
<td class="image-caption-i">
<img src="{@docRoot}images/icon_design/statusbar_light.png" alt="A view of
-light, effects, and shadows for launcher icons."/>
+light, effects, and shadows for status bar icons."/>
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 7. </strong>Light, effects, and shadows for launcher icons.</p>
+ <p><strong>Figure 10. </strong>Light, effects, and shadows for status bar icons.</p>
<div class="image-caption-nested">
<table style="margin-top:0;">
<tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>Use fill gradient from primary color palette</td></tr>
@@ -432,8 +824,8 @@
<li>In a tool like Adobe Photoshop, create the base shape within a 25x25 px
image on a transparent background. Mind the safeframe, and keep the upper and
lower 2 pixels free.</li>
-<li>Add rounded corners as specified in Figure 6.</li>
-<li>Add light, effects, and shadows as specified in Figure 7.</li>
+<li>Add rounded corners as specified in Figure 9.</li>
+<li>Add light, effects, and shadows as specified in Figure 10.</li>
<li>Export the icon at 25x25 as a PNG file with transparency enabled.</li>
</ol>
@@ -442,6 +834,16 @@
</table>
+<h4 id="dodonts_status">"Do's and don'ts"</h4>
+
+<p>Below are some "do and don't" examples to consider when creating status bar icons for
+your application. </p>
+
+
+<img src="{@docRoot}images/icon_design/do_dont_statusicons.png" style="padding:0;margin:0;padding-right:30%" width="400">
+
+
+
<h2 id="tabstructure">Tab icon</h2>
<p>Tab icons are graphical elements used to represent individual tabs in a
@@ -477,7 +879,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 8. </strong>Safeframe and fill gradient for unselected tab
+ <p><strong>Figure 11. </strong>Safeframe and fill gradient for unselected tab
icons. Icon size is 32x32.</p>
</div>
</td>
@@ -489,7 +891,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 9. </strong>Safeframe and fill gradient for tab icons in
+ <p><strong>Figure 12. </strong>Safeframe and fill gradient for tab icons in
selected state. Icon size is 32x32.</p>
</div>
</td>
@@ -511,7 +913,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 10. </strong>Light, effects, and shadows for unselected
+ <p><strong>Figure 13. </strong>Light, effects, and shadows for unselected
tab icons.</p>
<div class="image-caption-nested">
<table style="margin-top:0;">
@@ -536,7 +938,7 @@
<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
<li>Import the shape to a tool like Adobe Photoshop and scale to fit an image of
32x32 px on a transparent background.</li>
-<li>Add the effects seen in Figure 10 for the unselected state filter.</li>
+<li>Add the effects seen in Figure 13 for the unselected state filter.</li>
<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
</ol>
@@ -557,7 +959,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 11. </strong>Light, effects, and shadows for selected tab
+ <p><strong>Figure 14. </strong>Light, effects, and shadows for selected tab
icons.</p>
<div class="image-caption-nested">
<table style="margin-top:0;">
@@ -595,7 +997,7 @@
<li>Create the basic shape using a tool like Adobe Illustrator.</li>
<li>Import the shape into a tool like Adobe Photoshop and scale to fit a 32x32
px artboard with a transparent background. </li>
-<li>Add the effects seen in Figure 11 for the selected state filter.</li>
+<li>Add the effects seen in Figure 14 for the selected state filter.</li>
<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
</ol>
@@ -635,7 +1037,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 12. </strong>Safeframe and fill gradient for dialog icons.
+ <p><strong>Figure 15. </strong>Safeframe and fill gradient for dialog icons.
Icon size is 32x32.</p>
</div>
</td>
@@ -656,7 +1058,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 13. </strong>Light, effects, and shadows for dialog
+ <p><strong>Figure 16. </strong>Light, effects, and shadows for dialog
icons.</p>
<div class="image-caption-nested">
<table style="margin-top:0;">
@@ -680,7 +1082,7 @@
<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
<li>Import the shape into a tool like Adobe Photoshop and scale to fit an image
of 32x32 px on a transparent background. </li>
-<li>Add the effects seen in Figure 13 for the proper filter.</li>
+<li>Add the effects seen in Figure 16 for the proper filter.</li>
<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
</ol>
@@ -693,8 +1095,9 @@
<p>List view icons look a lot like dialog icons, but they use an inner shadow
effect where the light source is above the object. They are also designed to be
-used only in a list view. Examples include the Android Market application home
-screen and the driving directions screen in the Maps application.</p>
+used only in a {@link android.widget.ListView}. Examples include the Android
+Market application home screen and the driving directions screen in the Maps
+application.</p>
<h4>Structure</h4>
@@ -720,7 +1123,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 14. </strong>Safeframe and fill gradient for list view
+ <p><strong>Figure 17. </strong>Safeframe and fill gradient for list view
icons. Icon size is 32x32.</p>
</div>
</td>
@@ -741,7 +1144,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 15. </strong>Light, effects, and shadows for list view
+ <p><strong>Figure 18. </strong>Light, effects, and shadows for list view
icons.</p>
<div class="image-caption-nested">
<table style="margin-top:0;">
@@ -762,7 +1165,7 @@
<h4 id="menusteps">Step by step</h4>
<ol>
-<li>Add the effects seen in Figure 15 for the proper filter.</li>
+<li>Add the effects seen in Figure 18 for the proper filter.</li>
<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
<li>Import the shape into a tool like Adobe Photoshop and scale to fit an image
@@ -773,48 +1176,266 @@
</tr>
</table>
+<h2 id="design_tips">Tips for Designers</h2>
-<h2 id="dodonts">General guidelines</h2>
+<p>Here are some tips that you might find useful as you develop icons or other
+drawable assets for your application. The tips assume that you are using
+Photoshop or similar raster image-editing program.</p>
-<p>Below are some "do and don't" guidelines to consider when creating icons for
-your application. By following the guidelines, you can ensure that your icons
-will work well with other parts of the Android platform UI and will meet the
-expectations of your application's users. </p>
+<h4>Use common naming conventions for icon assets</h4>
-<table style="margin:0px;padding:0px;">
+<p>Try to name files so that related assets will group together inside a
+directory when they are sorted alphabetically. In particular, it helps to use a
+common prefix for each icon type. For example:</p>
+
+<table>
<tr>
-<td style="border:0;width:350px;">
-
-<h4>Do...</h4>
-
-<ul>
-<li>Use a normal perspective. The depth of an object should be realistic.</li>
-<li>Keep it simple! By overdoing an icon, it loses it purpose and
-readability.</li>
-<li>Use colors only when necessary. Mind that the base of a launcher icon should
-be grey and feel solid. </li>
-<li>Use the correct angles for the specific icon types.</li>
-</ul>
-</td>
-<td style="border:0;width:350px;">
-
-<h4>Don’t...</h4>
-
-<ul>
-<li>Use open elements like text alone as icons. Instead place those elements on
-a base shape.</li>
-<li>Use colors for your status bar notifications. Those are reserved for
-specific phone-only functions.</li>
-</ul>
-</td>
+<th>Asset Type</th>
+<th>Prefix</th>
+<th>Example</th>
</tr>
<tr>
-<td colspan="2" style="border:0;">
-<img src="{@docRoot}images/icon_design/do_dont.png" alt="Side-by-side examples
-of good/bad icon design."/>
-</td>
+<td>Icons</td>
+<td><code>ic_</code></td>
+<td><code>ic_star.png</code></td>
+</tr>
+<tr>
+<td>Launcher icons</td>
+<td><code>ic_launcher</code></td>
+<td><code>ic_launcher_calendar.png</code></td>
+</tr>
+<tr>
+<td>Menu icons</td>
+<td><code>ic_menu</code></td>
+<td><code>ic_menu_archive.png</code></td>
+</tr>
+<tr>
+<td>Status bar icons</td>
+<td><code>ic_stat_sys</code> or <code>ic_stat_notify</code></td>
+<td><code>ic_stat_notify_msg.png</code></td>
+</tr>
+<tr>
+<td>Tab icons</td>
+<td><code>ic_tab</code></td>
+<td><code>ic_tab_recent.png</code></td>
+</tr>
+<tr>
+<td>Dialog icons</td>
+<td><code>ic_dialog</code></td>
+<td><code>ic_dialog_info.png</code></td>
+</tr>
</table>
+<p>Note that you are not required to use a shared prefix of any type —
+doing so is for your convenience only.</p>
+
+
+<h4>Set up a working space that organizes files for multiple densities</h4>
+
+<p>Developing multiple sets of assets for different screen densities means
+creating multiple copies of files. To help keep the multiple copies of files
+safe and easier to find, we recommend creating a directory structure in your
+working space that organizes asset files per resolution. For example:</p>
+
+<pre>assets/...
+ ldpi/...
+ _pre_production/...
+ <em>working_file</em>.psd
+ <em>finished_asset</em>.png
+ mdpi/...
+ _pre_production/...
+ <em>working_file</em>.psd
+ <em>finished_asset</em>.png
+ hdpi/...
+ _pre_production/...
+ <em>working_file</em>.psd
+ <em>finished_asset</em>.png</pre>
+
+<p>This structure parallels the density-specific structure in which you will
+ultimately store the finished assets in your application's resources. Because
+the structure in your working space is similar to that of the application, you
+can quickly determine which assets should be copied to each application
+resources directory. Separating assets by density also helps you detect any
+variances in filenames across densities, which is important because
+corresponding assets for different densities must share the same filename.</p>
+
+<p>For comparison, here's the resources directory structure of a typical
+application: </p>
+
+<pre>res/...
+ drawable-ldpi/...
+ <em>finished_asset</em>.png
+ drawable-mdpi/...
+ <em>finished_asset</em>.png
+ drawable-hdpi/...
+ <em>finished_asset</em>.png</pre>
+
+
+<h4>Create medium-density assets first</h4>
+
+<p>Since medium density is the baseline for Android, begin your designing work
+by creating the <code>mdpi</code> assets. See <a href="#screens-table">Table
+1</a>, above, for the actual pixel dimensions of various icon types. When
+possible, use vector art or paths within Photoshop layers so that it will be
+easier to scale the assets up or down later.</p>
+
+<p>For each discreet asset, or set of like assets that share the same bounding
+box dimensions, create a working Photoshop file and save it in the
+<code>_pre_production</code> directory. For example:
+<code>ic_tabs_phone_mdpi.psd</code>. This will make it easier to locate and edit
+individual assets if changes are required. It's also helpful to use a
+density-specific suffix in the filename for the working file, to avoid confusion
+when editing the files. For example: <code>_mdpi.psd</code>.</p>
+
+<p>From the <code>mdpi</code> working files, save individual flattened assets to
+the corresponding density-specific resource directory (in this case,
+<code>mdpi/</code>) in your working space.</p>
+
+
+<h4>Create high- and low-density assets from the medium-density sources</h4>
+
+<p>When you are finished working with your medium-density assets, copy the
+working files from the your workspace's <code>mdpi/_pre_production</code>
+directory to the corresponding locations in the <code>ldpi</code> and
+<code>hdpi</code> directories. If any of the working files use a
+density-specific suffix, rename the suffix to match the intended density.</p>
+
+<p>Next, open each working file in the high- and low-density directories and
+scale the image up or down to match the intended density. To create an
+<code>hdpi</code> asset, scale the image by 150%. To create an <code>ldpi</code>
+asset, scale the image down by 75%. To scale the images, follow these steps:</p>
+
+<ol>
+<li>Open the working file in Photoshop or similar program.</li>
+<li>Under the <strong>Image</strong> menu, choose <strong>Image Size</strong>.</li>
+<li>On the Image Size panel, change the Width pop up menu to "percent."</li>
+<li>Change the Width value to "150" for <code>hdpi</code> assets and "75" for <code>ldpi</code> assets.</li>
+<li>Select the Scale Styles checkbox.</li>
+<li>Select the Constrain Proportions checkbox.</li>
+<li>Select the Resample Image checkbox and set the pop up menu to "Bicubic (Best for smooth gradients)."</li>
+<li>Click <strong>OK</strong>.</li>
+</ol>
+
+<p>After you scale each image, save it to the target density-specific resource
+directory.</p>
+
+<p>If you are scaling a nine-patch image, see the section below for notes on how
+to handle the tick marks at the edge of the image. </p>
+
+
+<h4>After scaling, redraw bitmap layers as needed</h4>
+
+<p>If you scaled an image up from a bitmap layer, rather than from a vector
+layer, those layers may need to be redrawn manually to accommodate the higher
+density. For example if a 60x60 circle was painted as a bitmap for
+<code>mdpi</code> it will need to be repainted as a 90x90 circle for
+<code>hdpi</code>.</p>
+
+
+<h4>When scaling a 9-patch image, crop tick marks before scaling and replace
+them after</h4>
+
+<p>Nine-patch images include tick marks at the outer edge of the image. When you
+scale a nine-patch image, the tick marks are also scaled, which produces an
+inaccurate result. The recommended way to handle the scaling of nine-patch
+images is to remove the tick marks from the source image before scaling and then
+manually replace the tick marks at the proper size after scaling.</p>
+
+<p>To more easily determine the tick marks after the working file has been
+scaled to a new resolution, first create a temporary duplicate flattened image
+which includes the tick marks: </p>
+
+<ol>
+<li>Under the <strong>Select</strong> menu choose <strong>All</strong>.</li>
+<li>Under the <strong>Edit</strong> menu choose
+<strong>Copy Merged</strong>.</li>
+<li>Under the <strong>File</strong> menu choose <strong>New</strong> and then
+click <strong>OK</strong> on the new panel.</li>
+<li>Under the <strong>Edit</strong> choose <strong>Paste</strong>.</li>
+</ol>
+
+<p>After creating the temporary copy, go back to the working file and crop
+the tick marks out of the working file before scaling the image:</p>
+<ol>
+<li>Under the <strong>Image</strong> menu, choose the
+<strong>Canvas Size</strong> command.</li>
+<li>On the Canvas Size panel, subtract 2 pixels from the Width and
+Height values.</li>
+<li>Set the Anchor to "Center."</li>
+<li>Click <strong>OK</strong></li>
+</ol>
+
+<p>Scale the working file to the target density. With the working file scaled
+and the canvas enlarged so that the tick marks can be repainted:</p>
+
+<ol>
+<li>Under the <strong>Image</strong> menu, choose the
+<strong>Canvas Size</strong> command.</li>
+<li>On the <strong>Canvas Size</strong> panel, add 2 pixels to the Width
+and Height values.</li>
+<li>Set the Anchor to "Center."</li>
+<li>Click <strong>OK</strong>.</li>
+</ol>
+
+<p>To determine tick marks, go back to duplicate flattened image and scale it to
+the target resolution. </p>
+
+<p>Copy the scaled duplicate flattened image into a new layer in the working
+file to use as reference. Create a new layer in which to paint new tick marks at
+the single pixel outer edge of the image. Note tickmarks must be 100% opaque
+black, without transparency, and all other areas of the tick mark region must be
+100% transparent, otherwise the system will not interpret the 9-patch image
+correctly. </p>
+
+<p>Using the scaled duplicate flattened image as reference paint new tick marks
+in the new layer that align with the reference layer. Note round up pixels for
+tick marks. Any pixels that are partially opaque in the reference layer should
+be fully opaqe in the new layer.</p>
+
+
+<h4>Adjust stroke and drop shadow after scaling an image</h4>
+
+<p>While it is desirable to scale layer styles for the most part (such as for
+Gradient Overlay or Inner Glow), you may need to manually reset the Stroke and
+Drop Shadow in the scaled image to 1 px before saving, especially when scaling
+to <code>hdpi</code>.
+
+<h4>Save nine-patch images with the appropriate filename suffix</h4>
+
+<p>If an asset is a 9-patch asset (with tick marks), be sure to save the asset
+in PNG format with a filename that includes the <code>.9.png</code> suffix. If
+the filename does not use the suffix, the system won't recognize the image as a
+nine-patch asset and won't resize it as intended. </p>
+
+
+<h4>When saving image assets, remove the Photoshop header</h4>
+
+<p>To help keep each image asset as small as possible, make sure to remove the
+Photoshop headers from the file. To remove the Photoshop header, follow these
+steps: </p>
+
+<ol>
+<li>Under the <strong>File</strong> menu, choose the <strong>Save for Web &
+Devices</strong> command </li>
+<li>On the "Save for Web & Devices" panel, set the Preset pop-up to
+"PNG-24," set the pop-up under Presets to "PNG-24" as well, and select the
+Transparency box (if the image uses transparency)</li>
+<li>Select <strong>Save</strong>.</li>
+</ol>
+
+<h4>Make sure that corresponding assets for different densities use the same
+filenames</h4>
+
+<p>Corresponding icon asset files for each density must use the same filename,
+but be stored in density-specific resource directories. This allows the system
+to look up and load the proper resource according to the resource requested by
+the application and the screen characteristics of the device. For this reason,
+make sure that the set of assets in each density-specific is consistent and do
+not use density-specific suffixes in the filenames. For more information about
+how to manage density-specific resources, see <a
+href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a>. </p>
+
<h2 id="templatespack">Using the Android Icon Templates Pack</h2>
<p>The Android Icon Templates Pack is a collection of template designs, filters,
@@ -831,7 +1452,7 @@
<p>You can obtain the Icon Templates Pack archive using the link below: </p>
<p style="margin-left:2em"><a
-href="{@docRoot}shareables/icon_templates-v1.0.zip">Download the Icon Templates
+href="{@docRoot}shareables/icon_templates-v2.0.zip">Download the Icon Templates
Pack »</a>
@@ -843,148 +1464,20 @@
icons are provided for your reference only — please do not reuse these
icons in your applications.</code>.
-<table class="image-caption">
-<tr>
+<img src="{@docRoot}images/icon_design/IconGraphic_Icons.png" style="margin-top:2em;" />
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_alarmclock.png" alt="Android asset" />
- <div class="caption">Alarm Clock</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_browser.png" alt="Android asset" />
- <div class="caption">Browser</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_calculator.png" alt="Android asset" />
- <div class="caption">Calculator</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_calendar.png" alt="Android asset" />
- <div class="caption">Calendar</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_video_camera.png" alt="Android asset" />
- <div class="caption">Camcorder</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_camera.png" alt="Android asset" />
- <div class="caption">Camera</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_contacts.png" alt="Android asset" />
- <div class="caption">Contacts</div></td>
-
-</tr>
-<tr>
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_phone_dialer.png" alt="Android asset" />
- <div class="caption">Dialer</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_email_generic.png" alt="Android asset" />
- <div class="caption">Email</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_gallery.png" alt="Android asset" />
- <div class="caption">Gallery</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_generic_application.png" alt="Android asset" />
- <div class="caption">Generic application</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_email.png" alt="Android asset" />
- <div class="caption">Gmail</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_google_talk.png" alt="Android asset" />
- <div class="caption">Google Talk</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_IM.png" alt="Android asset" />
- <div class="caption">IM</div></td>
-
-</tr>
-<tr>
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_maps.png" alt="Android asset" />
- <div class="caption">Maps</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_marketplace.png" alt="Android asset" />
- <div class="caption">Market </div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_sms_mms.png" alt="Android asset" />
- <div class="caption">Messaging </div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_musicplayer_2.png" alt="Android asset" />
- <div class="caption">Music</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_settings.png" alt="Android asset" />
- <div class="caption">Settings</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_voicedial.png" alt="Android asset" />
- <div class="caption">Voice Dialer</div></td>
-
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_voicesearch.png" alt="Android asset" />
- <div class="caption">Voice Search</div></td>
-
-</tr>
-<tr>
-
-<td class="image-caption-i image-list">
- <img src="{@docRoot}images/icon_design/ic_launcher_youtube.png" alt="Android asset" />
- <div class="caption">YouTube</div></td>
-</tr>
-</table>
<h3 id="menuapx">Standard menu icons</h3>
-<p>Shown below are standard menu icons that are included in the Android platform
-(as of Android 1.5). You can reference any of these icon resources from your
-application as needed, but make sure that the action you assign to the icon is
-consistent with that listed. Note that this is not a complete list of icons and
-that the actual appearance of standard icons may change across platform
-versions.</p>
+<p>Shown below are standard menu icons that are used in the Android
+system. Because these resources can change between platform versions, you
+should not reference the system's copy of the resources. If you want
+use any icons or other internal drawable resources, you should store a
+local copy of those icons or drawables in your application resources,
+then reference the local copy from your application code. In that way, you can
+maintain control over the appearance of your icons, even if the system's
+copy changes. Note that the list below is not intended to be complete.</p>
-<p>To reference one of the icons from your code, use
-<code>android.R.drawable.<icon_resource_identifier></code>. For example,
-you can call a menu item's {@link android.view.MenuItem#setIcon(android.graphics.drawable.Drawable) setIcon()}
-method and pass the resource name:</p>
-
-<p style="margin-left:2em"><code>.setIcon(android.R.drawable.ic_menu_more);</code>.
-
-<p>You could reference the same icon from a layout file using
-<code>android:icon="@android:drawable/ic_menu_more"></code>.</p>
-
-<p>To determine the resource ID for an icon listed below, hover over the icon or
-simply look at image filenames, which use the format
-"<icon_resource_identifier>.png".</p>
<table class="image-caption">
<tr>
@@ -1115,24 +1608,14 @@
<h3 id="statusbarapx">Standard status bar icons</h3>
-<p>Shown below are standard status bar icons included in the Android platform
-(as of Android 1.5). You can reference any of these icon resources from your
-application as needed, but make sure that the meaning of the icon is consistent
-with the standard meaning listed. Note that this is not a complete list of icons
-and that the actual appearance of standard icons may change across platform
-versions.</p>
-
-<p>To reference one of the icons from your code, use
-<code>android.R.drawable.<icon_resource_identifier></code>. For example,
-you can construct a simple notification that references one of the icons like
-this: </p>
-
-<p style="margin-left:2em"><code>new Notification(R.drawable.stat_notify_calendar,
-"sample text", System.currentTimeMillis());</code></p>
-
-<p>To determine the resource ID for an icon listed below, hover over the icon
-or simply look at the image filename, which use the format
-"<icon_resource_identifier>.png".</p>
+<p>Shown below are standard status bar icons that are used in the Android
+platform. Because these resources can change between platform versions, you
+should not reference the system's copy of the resources. If you want
+use any icons or other internal drawable resources, you should store a
+local copy of those icons or drawables in your application resources,
+then reference the local copy from your application code. In that way, you can
+maintain control over the appearance of your icons, even if the system's
+copy changes. Note that the list below is not intended to be complete.</p>
<table class="image-caption">
@@ -1187,4 +1670,3 @@
</tr>
</table>
-
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_1.jd b/docs/html/guide/practices/ui_guidelines/icon_design_1.jd
new file mode 100644
index 0000000..039f301
--- /dev/null
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_1.jd
@@ -0,0 +1,1200 @@
+page.title=Icon Design Guidelines, Android 1.0
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Icon design quickview</h2>
+
+<ul>
+<li>You can use several types of icons in an Android application.</li>
+<li>Your icons should follow the specification in this document.</li>
+<li>A set of standard icons is provided by the Android platform. Your
+application can use the standard icons by referencing them as resources.</li>
+</ul>
+
+<h2>In this document</h2>
+
+<ol>
+<li><a href="#launcherstructure">Launcher icon</a></li>
+<li><a href="#menustructure">Menu icon</a></li>
+<li><a href="#statusbarstructure">Status bar icon</a></li>
+<li><a href="#tabstructure">Tab icon</a></li>
+<li><a href="#dialogstructure">Dialog icon</a></li>
+<li><a href="#listviewstructure">List view icon</a></li>
+
+<li style="margin-top:4px;"><a href="#dodonts">General guidelines</a></li>
+<li><a href="#templatespack">Using the Icon Templates Pack</a></li>
+<li><a href="#iconappendix">Icon appendix</a>
+ <ol>
+ <li><a href="#launcherapx">Launcher icons</a></li>
+ <li><a href="#menuapx">Menu icons</a></li>
+ <li><a href="#statusbarapx">Status bar icons</a></li>
+ </ol>
+</li>
+
+</ol>
+
+<h2>See also</h2>
+
+<ol>
+<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
+<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
+Templates Pack, v1.0 »</a></li>
+</ol>
+
+
+<h2>Newer versions</h2>
+
+<ol>
+<li style="margin-top:4px;"><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Icon Design Guidelines, Android 2.0</a></li>
+<li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
+Templates Pack, v2.0 »</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>Creating a unified look and feel throughout a user interface adds value to
+your product. Streamlining the graphic style will also make the UI seem more
+professional to the user.</p>
+
+<p>This document shows you how to create icons for various parts
+of your application’s user interface that fit the style set by the Android UI
+team. Following these guidelines will help you to create a polished and unified
+experience for the user.</p>
+
+<p>To get started creating conforming icons more quickly, you can download
+the Android Icon Templates Pack. For more information, see
+<a href="#templatespack">Using the Android Icon Template Pack</a>.</p>
+
+<h2 id="launcherstructure">Launcher icon</h2>
+
+<p>A launcher icon is the graphic that represents your application on an Android
+device’s Home screen. It is a simplified 3D icon with a fixed perspective. The
+required perspective is shown in Figure 1.</p>
+
+<h4 id="launcherstructure">Structure</h4>
+
+<ul>
+<li>The base of a launcher icon can face either the top view or the front
+view.</li>
+
+<li>The majority of a launcher icon’s surface should be created using the
+launcher icon <a href="#launcherpalette">color palette</a>. To add emphasis, use
+one or more bright accent colors to highlight specific characteristics.</li>
+
+<li>All launcher icons must be created with rounded corners to make them look
+friendly and simple—as shown in Figure 2.</li>
+
+<li>All dimensions specified are based on a 250x250 pixel artboard size
+in a vector graphics editor like Adobe Illustrator, where the icon fits within
+the artboard boundaries.</li>
+
+<li><strong>Final art must be scaled down and exported as a transparent 48x48 px
+PNG file using a raster image editor such as Adobe Photoshop.</strong></li>
+
+<li>Templates for creating launcher icons in Adobe Illustrator and Photoshop are
+available in the Icon Templates Pack.</li>
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/launcher_structure.png" alt="A view of
+launcher icon corners and perspective angles" />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 1.</strong> Perspective angles for launcher icons (90° is
+vertical).</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>92°</td></tr>
+ <tr><td><em>2.</em></td><td>92°</td></tr>
+ <tr><td><em>3.</em></td><td>173°</td></tr>
+ <tr><td><em>4.</em></td><td>171°</td></tr>
+ <tr><td><em>5.</em></td><td>49°</td></tr>
+ <tr><td><em>6.</em></td><td>171°</td></tr>
+ <tr><td><em>7.</em></td><td>64°</td></tr>
+ <tr><td><em>8.</em></td><td>97°</td></tr>
+ <tr><td><em>9.</em></td><td>75°</td></tr>
+ <tr><td><em>10.</em></td><td>93°</td></tr>
+ <tr><td><em>11.</em></td><td>169°</td></tr>
+ </table>
+ </div>
+ </div>
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 2.</strong> Rounded corners for launcher icons.</p>
+ </div>
+</td>
+</tr>
+</table>
+
+<h4 id="launcherlight">Light, effects, and shadows</h4>
+
+<p>Launcher icons are simplified 3D icons using light and shadows for
+definition. A light source is placed slightly to the left in front of the icon,
+and therefore the shadow expands to the right and back.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/launcher_light.png" alt="A view of
+light, effects, and shadows for launcher icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 3. </strong>Light, effects, and shadows for launcher icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Edge highlight:</td><td>white</td></tr>
+ <tr><td><em>2.</em></td><td>Icon shadow:</td><td>black | 20px blur<br>50% opacity | angle 67°</td></tr>
+ <tr><td><em>3.</em></td><td>Front part:</td><td>Use light gradient from color palette</td></tr>
+ <tr><td><em>4.</em></td><td>Detail shadow:</td><td>black | 10px blur<br>75% opacity</td></tr>
+ <tr><td><em>5.</em></td><td> Side part:</td><td>Use medium gradient from color palette</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="launcherpalette">Launcher icon color palette</h4>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_white.png" alt="Color palette, white" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">White<br>r 0 | g 0 | b 0<br>Used for highlights on edges.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_light.png" alt="Color palette, light gradient" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Light gradient<br><em>1: </em>r 0 | g 0 | b 0<br><em>2: </em>r 217 | g 217 | b 217<br>Used on the front (lit) part of the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_medium.png" alt="Color palette, medium gradien" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Medium gradient<br><em>1: </em>r 190 | g 190 | b 190<br><em>2: </em>r 115 | g 115 | b 115<br>Used on the side (shaded) part of the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_dark.png" alt="Color palette, dark gradient" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Dark gradient<br><em>1: </em>r 100 | g 100 | b 100<br><em>2: </em>r 25 | g 25 | b 25<br>Used on details and parts in the shade of the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_black.png" alt="Color palette, black" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Black<br>r 255 | g 255 | b 255<br>Used as base color in shadows.</td>
+</tr>
+
+</table>
+
+</td>
+
+<td style="border:0;width:350px">
+
+<h4 id="launchersteps">Step by step</h4>
+
+<ol>
+ <li>Create the basic shapes with a tool like Adobe Illustrator, using the
+angles described in <a href="#launcherstructure">Launcher icon: structure</a>.
+The shapes and effects must fit within a 250x250 pixel artboard.</li>
+ <li>Add depth to shapes by extruding them and create the rounded corners as
+described for the launcher icon structure.</li>
+ <li>Add details and colors. Gradients should be treated as if there is a light
+source placed slightly to the left in front of the icon.</li>
+ <li>Create the shadows with the correct angle and blur effect.</li>
+ <li>Import the icon into a tool like Adobe Photoshop and scale to fit an image
+size of 48x48 px on a transparent background.</li>
+ <li>Export the icon at 48x48 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+<h2 id="menustructure">Menu icon</h2>
+
+<p>Menu icons are graphical elements placed in the pop-up menu shown to users
+when they press the Menu button. They are drawn in a flat-front perspective.
+Elements in a menu icon must not be visualized in 3D or perspective.</p>
+
+<h4>Structure</h4>
+
+<ul>
+<li>In order to maintain consistency, all menu icons must use the same
+primary palette and the same effects. For more information, see the
+menu icon <a href="#menupalette">color palette</a>. </li>
+
+<li>Menu icons should include rounded corners, but only when logically
+appropriate. For example, in Figure 3 the logical place for rounded corners is
+the roof and not the rest of the building.</span></li>
+
+<li>All dimensions specified on this page are based on a 48x48 pixel artboard
+size with a 6 pixel safeframe.</li>
+
+<li>The menu icon effect (the outer glow) described in <a
+href="#menulight">Light, effects, and shadows</a> can overlap the 6px safeframe,
+but only when necessary. The base shape must always stay inside the
+safeframe.</li>
+
+<li><strong>Final art must be exported as a transparent PNG file.</strong></li>
+
+<li>Templates for creating menu icons in Adobe Photoshop are available in the
+Icon Templates Pack.</li>
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/menu_structure.png" alt="A view of menu
+icon structure." />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 4. </strong>Safeframe and corner-rounding for menu
+icons. Icon size is 48x48.</p>
+ </div>
+</td>
+</tr>
+</table>
+
+
+<h4 id="menulight">Light, effects, and shadows</h4>
+
+<p>Menu icons are flat and pictured face on. A slight deboss and some other
+effects, which are shown below, are used to create depth.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/menu_light.png" alt="A view of light, effects, and shadows for launcher icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 5. </strong>Light, effects, and shadows for launcher icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>Use fill gradient from primary color palette</td></tr>
+ <tr><td><em>2.</em></td><td>Inner shadow:</td><td>black | 20 % opacity<br>angle 90° | distance 2px<br>size 2px</td></tr>
+ <tr><td><em>3.</em></td><td>Outer glow:</td><td>white | 55% opacity <br>spread 10% | size 3px</td></tr>
+ <tr><td><em>5.</em></td><td>Inner bevel:</td><td>depth 1% | direction down size 0px<br>angle 90° | altitude 10°<br>highlight white 70% opacity<br>shadow black 25% opacity</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="menupalette">Color palette</h4>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/menu_palette_white.png" alt="Color palette, white" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">White<br>r 0 | g 0 | b 0<br>Used for outer glow and bevel highlight.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/menu_palette_gradient_medium.png" alt="Color palette, medium gradient" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Fill gradient<br><em>1: </em>r 163 | g 163 | b 163<br><em>2: </em>r 120 | g 120 | b 120<br>Used as color fill.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/menu_palette_black.png" alt="Color palette, black" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Black<br>r 255 | g 255 | b 255<br>Used for inner shadow and bevel shadow.</td>
+</tr>
+
+</table>
+
+</td>
+
+<td style="border:0;width:350px">
+
+<h4 id="menusteps">Step by step</h4>
+
+<ol>
+<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
+<li>Import the shape into a tool like Adobe Photoshop and scale to fit an image
+of 48x48 px on a transparent background. Mind the safeframe.</li>
+<li>Add the effects seen as described in Figure 5.</li>
+<li>Export the icon at 48x48 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<h2 id="statusbarstructure">Status bar icon</h2>
+
+<p>Status bar icons are used to represent notifications from your application in
+the status bar. Graphically, they are very similar to menu icons, but are
+smaller and higher in contrast.</p>
+
+<h4>Structure</h4>
+
+<ul>
+<li>Rounded corners must always be applied to the base shape and to the details
+of a status bar icon shown Figure 7.</li>
+
+<li>All dimensions specified are based on a 25x25 pixel artboard size with a 2
+pixel safeframe.</li>
+
+<li>Status bar icons can overlap the safeframe to the left and right when
+necessary, but must not overlap the safeframe at the top and bottom.</li>
+
+<li><strong>Final art must be exported as a transparent PNG file.</strong></li>
+
+<li>Templates for creating status bar icons using Adobe Photoshop are available
+in the Icon Templates Pack.</li>
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/statusbar_structure.png" alt="A view of
+status bar icon structure." />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 6. </strong>Safeframe and corner-rounding for status bar
+icons. Icon size is 25x25.</p>
+ </div>
+</td>
+</tr>
+</table>
+
+
+<h4 id="statusbarlight">Light, effects, and shadows</h4>
+
+<p>Status bar icons are slightly debossed, high in contrast, and pictured
+face-on to enhance clarity at small sizes.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/statusbar_light.png" alt="A view of
+light, effects, and shadows for launcher icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 7. </strong>Light, effects, and shadows for launcher icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>Use fill gradient from primary color palette</td></tr>
+ <tr><td><em>2.</em></td><td>Inner bevel:</td><td>depth 100% | direction down<br>size 0px | angle 90° |<br>altitude 30°<br>highlight white 75% opacity<br>shadow black 75% opacity</td></tr>
+ <tr><td><em>3.</em></td><td>Detail:</td><td>white</td></tr>
+ <tr><td><em>4.</em></td><td>Disabled detail:</td><td>grey gradient from palette<br>+ inner bevel: smooth | depth 1% | direction down | size 0px | angle 117° | <br>altitude 42° | highlight white 70% | no shadow</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="menupalette">Color palette</h4>
+
+<p>Only status bar icons related to the phone function use full color; all other status bar icons should remain monochromatic.</p>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/statusbar_palette_white.png" alt="Color palette, white" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">White<br>r 0 | g 0 | b 0<br>Used for details within the icons and bevel highlight.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/statusbar_palette_fill.png" alt="Color palette, grey gradient" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Grey gradient<br><em>1: </em>r 169 | g 169 | b 169<br><em>2: </em>r 126 | g 126 | b 126<br>Used for disabled details within the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/statusbar_palette_grey.png" alt="Color palette, fill gradient" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Fill gradient<br><em>1: </em>1 r 105 | g 105 | b 105<br><em>2: </em>r 10 | g 10 | b 10<br>Used as color fill.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/statusbar_palette_black.png" alt="Color palette, black" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Black<br>r 255 | g 255 | b 255<br>Used for bevel shadow.</td>
+</tr>
+
+</table>
+
+</td>
+
+<td style="border:0;width:350px">
+
+<h4 id="menusteps">Step by step</h4>
+
+<ol>
+<li>In a tool like Adobe Photoshop, create the base shape within a 25x25 px
+image on a transparent background. Mind the safeframe, and keep the upper and
+lower 2 pixels free.</li>
+<li>Add rounded corners as specified in Figure 6.</li>
+<li>Add light, effects, and shadows as specified in Figure 7.</li>
+<li>Export the icon at 25x25 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<h2 id="tabstructure">Tab icon</h2>
+
+<p>Tab icons are graphical elements used to represent individual tabs in a
+multi-tab interface. Each tab icon has two states: unselected and selected.</p>
+
+<h4>Structure</h4>
+
+<ul>
+<li>Unselected tab icons have the same fill gradient and effects as menu icons,
+but with no outer glow.</li>
+
+<li>Selected tab icons look just like unselected tab icons, but with a fainter
+inner shadow, and have the same front part gradient as dialog icons.</li>
+
+<li>Tab icons have a 1 px safeframe which should only be overlapped for the edge
+of the anti-alias of a round shape.</li>
+
+<li>All dimensions specified on this page are based on a 32x32 px artboard size.
+Keep 1 px of padding around the bounding box inside the Photoshop template.</li>
+
+<li><strong>Final art must be exported as a 32x32 px transparent PNG
+file.</strong></li>
+
+<li>Templates for creating tab icons in Adobe Photoshop are available in the
+Icon Templates Pack.</li>
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/tab_icon_unselected.png" alt="A view of
+unselected tab icon structure." />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 8. </strong>Safeframe and fill gradient for unselected tab
+icons. Icon size is 32x32.</p>
+ </div>
+</td>
+</tr>
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/tab_icon_selected.png" alt="A view of
+selected tab icon structure." />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 9. </strong>Safeframe and fill gradient for tab icons in
+selected state. Icon size is 32x32.</p>
+ </div>
+</td>
+</tr>
+</table>
+
+<h3 id="unselectedtabdetails">Unselected tab icon</h3>
+
+<h4 id="unselectedtablight">Light, effects, and shadows</h4>
+
+<p>Unselected tab icons look just like the selected tab icons, but with a
+fainter inner shadow, and the same front part gradient as the dialog icons.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/tab_unselected_light.png" alt="A view
+of light, effects, and shadows for unselected tab icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 10. </strong>Light, effects, and shadows for unselected
+tab icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>gradient overlay | angle 90°<br>bottom color: r 223 | g 223 | b 223<br>top color: r 249 | g 249 | b 249<br>bottom color location: 0%<br>top color location: 75%</td></tr>
+ <tr><td><em>2.</em></td><td>Inner shadow:</td><td>black | 10 % opacity | angle 90° distance 2px | size 2px</td></tr>
+ <tr><td><em>3.</em></td><td>Inner bevel:</td><td>depth 1% | direction down | size 0px | angle 90° | altitude 10°<br>highlight white 70% opacity<br>shadow black 25% opacity</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="menusteps">Step by step</h4>
+
+<ol>
+<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
+<li>Import the shape to a tool like Adobe Photoshop and scale to fit an image of
+32x32 px on a transparent background.</li>
+<li>Add the effects seen in Figure 10 for the unselected state filter.</li>
+<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+<h3 id="selectedtabdetails">Selected tab icon</h3>
+
+<p>The selected tab icons have the same fill gradient and effects as the menu
+icon, but with no outer glow.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/tab_selected_light.png" alt="A view of
+light, effects, and shadows for selected tab icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 11. </strong>Light, effects, and shadows for selected tab
+icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>Use fill gradient from color palette.</td></tr>
+ <tr><td><em>2.</em></td><td>Inner shadow:</td><td>black | 20% opacity | <br>angle 90° | distance 2px | <br>size 2px</td></tr>
+ <tr><td><em>3.</em></td><td>Inner bevel:</td><td>depth 1% | direction down | size 0px | angle 90° | <br>altitude 10°<br>highlight white 70% opacity<br>shadow black 25% opacity</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="menupalette">Color palette</h4>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/menu_palette_gradient_medium.png" alt="Color palette, fill gradient" style="margin:.5em 0 0 0;" /></td>
+<td class="image-caption-c" style="padding-top:.5em;">Fill gradient<br><em>1: </em>r 163 | g 163 | b 163<br><em>2: </em>r 120 | g 120 | b 120<br>Used as color fill on unselected tab icons.</td>
+</tr>
+
+</table>
+
+</td>
+
+<td style="border:0;width:350px">
+
+<h4 id="menusteps">Step by step</h4>
+
+<ol>
+<li>Create the basic shape using a tool like Adobe Illustrator.</li>
+<li>Import the shape into a tool like Adobe Photoshop and scale to fit a 32x32
+px artboard with a transparent background. </li>
+<li>Add the effects seen in Figure 11 for the selected state filter.</li>
+<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<h2 id="dialogstructure">Dialog icon</h2>
+
+<p>Dialog icons are shown in pop-up dialog boxes that prompt the user for
+interaction. They use a light gradient and inner
+shadow in order to stand out against a dark background.</p>
+
+<h4>Structure</h4>
+
+<ul>
+<li>Dialog icons have a 1 pixel safeframe. The base shape must fit within the
+safeframe, but the anti-alias of a round shape can overlap the safeframe. <span
+class="body-copy"></li>
+
+<li>All dimensions specified on this page are based on a 32x32 pixel artboard size
+in Adobe Photoshop. Keep 1 pixel of padding around the bounding box inside the
+Photoshop template.</li>
+
+<li><strong>Final art must be exported as a transparent PNG file.</strong></li>
+
+<li>Templates for creating dialog icons in Adobe Photoshop are available in the
+Icon Templates Pack.</li>
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/dialog_icon.png" alt="A view of dialog
+icon structure." />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 12. </strong>Safeframe and fill gradient for dialog icons.
+Icon size is 32x32.</p>
+ </div>
+</td>
+</tr>
+</table>
+
+
+<h4 id="dialoglight">Light, effects, and shadows</h4>
+
+<p>Dialog icons are flat and pictured face-on. In order to stand out against a
+dark background, they are built up using a light gradient and inner shadow.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/dialog_light.png" alt="A view of light,
+effects, and shadows for dialog icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 13. </strong>Light, effects, and shadows for dialog
+icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Front part:</td><td>gradient overlay | angle 90°<br>bottom: r 223 | g 223 | b 223<br>top: r 249 | g 249 | b 249<br>bottom color location: 0%<br>top color location: 75%</td></tr>
+ <tr><td><em>2.</em></td><td>Inner shadow:</td><td>black | 25% opacity | <br>angle -90° | distance 1px | size 0px</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="menusteps">Step by step</h4>
+
+<ol>
+<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
+<li>Import the shape into a tool like Adobe Photoshop and scale to fit an image
+of 32x32 px on a transparent background. </li>
+<li>Add the effects seen in Figure 13 for the proper filter.</li>
+<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<h2 id="listviewstructure">List view icon</h2>
+
+<p>List view icons look a lot like dialog icons, but they use an inner shadow
+effect where the light source is above the object. They are also designed to be
+used only in a list view. Examples include the Android Market application home
+screen and the driving directions screen in the Maps application.</p>
+
+<h4>Structure</h4>
+
+<ul>
+<li>A list view icon normally has a 1 px safeframe, but it is OK to use the
+safeframe area for the edge of the anti-alias of a round shape. </li>
+
+<li>All dimensions specified are based on a 32x32 pixel artboard size in
+Photoshop. Keep 1 pixel of padding around the bounding box inside the template.
+ </li>
+
+<li><strong>Final art must be exported as a transparent PNG file.</strong></li>
+
+<li>Templates for creating list view icons in Adobe Photoshop are available in
+the Icon Templates Pack. </li>
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i" style="padding-right:0">
+ <img src="{@docRoot}images/icon_design/listview_icon.png" alt="A view of list
+view icon structure." />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 14. </strong>Safeframe and fill gradient for list view
+icons. Icon size is 32x32.</p>
+ </div>
+</td>
+</tr>
+</table>
+
+<h4 id="listviewlight">Light, effects, and shadows</h4>
+
+<p>List view icons are flat and pictured face-on with an inner shadow. Built up
+by a light gradient and inner shadow, they stand out well on a dark
+background.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/listview_icon_details.png" alt="A view
+of light, effects, and shadows for list view icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 15. </strong>Light, effects, and shadows for list view
+icons.</p>
+ <div class="image-caption-nested">
+ <table style="margin-top:0;">
+ <tr><td style="padding-right:1em"><em>1.</em></td><td>Inner shadow:</td><td>black | 57 % opacity | angle 120° | blend mode normal | distance 1px | size 1px <td></tr>
+ <tr><td><em>2.</em></td><td>Background:</td><td>black | standard system color <br>These icons are displayed in list views only.</td></tr>
+ <tr><td colspan="2">Note: The list view icon sits on 32x32 px artboard in Photoshop, without a safeframe.</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4 id="menusteps">Step by step</h4>
+
+<ol>
+<li>Add the effects seen in Figure 15 for the proper filter.</li>
+<li>Export the icon at 32x32 as a PNG file with transparency enabled.</li>
+<li>Create the basic shapes using a tool like Adobe Illustrator.</li>
+<li>Import the shape into a tool like Adobe Photoshop and scale to fit an image
+of 32x32 px on a transparent background. </li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<h2 id="dodonts">General guidelines</h2>
+
+<p>Below are some "do and don't" guidelines to consider when creating icons for
+your application. By following the guidelines, you can ensure that your icons
+will work well with other parts of the Android platform UI and will meet the
+expectations of your application's users. </p>
+
+<table style="margin:0px;padding:0px;">
+<tr>
+<td style="border:0;width:350px;">
+
+<h4>Do...</h4>
+
+<ul>
+<li>Use a normal perspective. The depth of an object should be realistic.</li>
+<li>Keep it simple! By overdoing an icon, it loses it purpose and
+readability.</li>
+<li>Use colors only when necessary. Mind that the base of a launcher icon should
+be grey and feel solid. </li>
+<li>Use the correct angles for the specific icon types.</li>
+</ul>
+</td>
+<td style="border:0;width:350px;">
+
+<h4>Don’t...</h4>
+
+<ul>
+<li>Use open elements like text alone as icons. Instead place those elements on
+a base shape.</li>
+<li>Use colors for your status bar notifications. Those are reserved for
+specific phone-only functions.</li>
+</ul>
+</td>
+</tr>
+<tr>
+<td colspan="2" style="border:0;">
+<img src="{@docRoot}images/icon_design/do_dont.png" alt="Side-by-side examples
+of good/bad icon design."/>
+</td>
+</table>
+
+<h2 id="templatespack">Using the Android Icon Templates Pack</h2>
+
+<p>The Android Icon Templates Pack is a collection of template designs, filters,
+and settings that make it easier for you to create icons that conform to the
+general specifications given in this document. We recommend downloading the
+template pack archive before you get started with your icon design.</p>
+
+<p>The icon templates are provided in Adobe Photoshop and Adobe Illustrator file
+formats, which preserves the layers and design treatments we used when creating the
+standard icons for the Android platform. You can load the template files into any
+compatible image-editing program, although your ability to work directly with the
+layers and treatments may vary based on the program you are using.</p>
+
+<p>You can obtain the Icon Templates Pack archive using the link below: </p>
+
+<p style="margin-left:2em"><a
+href="{@docRoot}shareables/icon_templates-v1.0.zip">Download the Icon Templates
+Pack »</a>
+
+
+<h2 id="iconappendix">Icon appendix</p>
+
+<h3 id="launcherapx">Standard launcher icons</h3>
+
+<p>Shown below are examples of launcher icons used by Android applications. The
+icons are provided for your reference only — please do not reuse these
+icons in your applications.</code>.
+
+<table class="image-caption">
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_alarmclock.png" alt="Android asset" />
+ <div class="caption">Alarm Clock</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_browser.png" alt="Android asset" />
+ <div class="caption">Browser</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_calculator.png" alt="Android asset" />
+ <div class="caption">Calculator</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_calendar.png" alt="Android asset" />
+ <div class="caption">Calendar</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_video_camera.png" alt="Android asset" />
+ <div class="caption">Camcorder</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_camera.png" alt="Android asset" />
+ <div class="caption">Camera</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_contacts.png" alt="Android asset" />
+ <div class="caption">Contacts</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_phone_dialer.png" alt="Android asset" />
+ <div class="caption">Dialer</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_email_generic.png" alt="Android asset" />
+ <div class="caption">Email</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_gallery.png" alt="Android asset" />
+ <div class="caption">Gallery</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_generic_application.png" alt="Android asset" />
+ <div class="caption">Generic application</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_email.png" alt="Android asset" />
+ <div class="caption">Gmail</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_google_talk.png" alt="Android asset" />
+ <div class="caption">Google Talk</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_IM.png" alt="Android asset" />
+ <div class="caption">IM</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_maps.png" alt="Android asset" />
+ <div class="caption">Maps</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_marketplace.png" alt="Android asset" />
+ <div class="caption">Market </div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_sms_mms.png" alt="Android asset" />
+ <div class="caption">Messaging </div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_musicplayer_2.png" alt="Android asset" />
+ <div class="caption">Music</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_settings.png" alt="Android asset" />
+ <div class="caption">Settings</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_voicedial.png" alt="Android asset" />
+ <div class="caption">Voice Dialer</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_voicesearch.png" alt="Android asset" />
+ <div class="caption">Voice Search</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="/images/icon_design/ic_launcher_youtube.png" alt="Android asset" />
+ <div class="caption">YouTube</div></td>
+</tr>
+</table>
+
+<h3 id="menuapx">Standard menu icons</h3>
+
+<p>Shown below are standard menu icons that are included in the Android platform
+(as of Android 1.5). You can reference any of these icon resources from your
+application as needed, but make sure that the action you assign to the icon is
+consistent with that listed. Note that this is not a complete list of icons and
+that the actual appearance of standard icons may change across platform
+versions.</p>
+
+<p>To reference one of the icons from your code, use
+<code>android.R.drawable.<icon_resource_identifier></code>. For example,
+you can call a menu item's {@link android.view.MenuItem#setIcon(android.graphics.drawable.Drawable) setIcon()}
+method and pass the resource name:</p>
+
+<p style="margin-left:2em"><code>.setIcon(android.R.drawable.ic_menu_more);</code>.
+
+<p>You could reference the same icon from a layout file using
+<code>android:icon="@android:drawable/ic_menu_more"></code>.</p>
+
+<p>To determine the resource ID for an icon listed below, hover over the icon or
+simply look at image filenames, which use the format
+"<icon_resource_identifier>.png".</p>
+
+<table class="image-caption">
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_add.png" title="ic_menu_add" alt="Android asset" />
+ <div class="caption">Add</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_call.png" title="ic_menu_call" alt="Android asset" />
+ <div class="caption">Call</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_camera.png" title="ic_menu_camera" alt="Android asset" />
+ <div class="caption">Camera</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_close_clear_cancel.png" title="ic_menu_close_clear_cancel" alt="Android asset" />
+ <div class="caption">Clear / Close / Cancel / Discard </div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_compass.png" title="ic_menu_compass" alt="Android asset" />
+ <div class="caption">Compass</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_delete.png" title="ic_menu_delete" alt="Android asset" />
+ <div class="caption">Delete</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_directions.png" title="ic_menu_directions" alt="Android asset" />
+ <div class="caption">Directions</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_edit.png" title="ic_menu_edit" alt="Android asset" />
+ <div class="caption">Edit</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_gallery.png" title="ic_menu_gallery" alt="Android asset" />
+ <div class="caption">Gallery</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_help.png" title="ic_menu_help" alt="Android asset" />
+ <div class="caption">Help</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_info_details.png" title="ic_menu_info_details" alt="Android asset" />
+ <div class="caption">Info / details</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_mapmode.png" title="ic_menu_mapmode" alt="Android asset" />
+ <div class="caption">Map mode</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_mylocation.png" title="ic_menu_mylocation" alt="Android asset" />
+ <div class="caption">My Location</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_more.png" title="ic_menu_more" alt="Android asset" />
+ <div class="caption">More</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_preferences.png" title="ic_menu_preferences" alt="Android asset" />
+ <div class="caption">Preferences</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_rotate.png" title="ic_menu_rotate" alt="Android asset" />
+ <div class="caption">Rotate</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_save.png" title="ic_menu_save" alt="Android asset" />
+ <div class="caption">Save</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_send.png" title="ic_menu_send" alt="Android asset" />
+ <div class="caption">Send</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_search.png" title="ic_menu_search" alt="Android asset" />
+ <div class="caption">Search</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_share.png" title="ic_menu_share" alt="Android asset" />
+ <div class="caption">Share</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_upload.png" title="ic_menu_upload" alt="Android asset" />
+ <div class="caption">Upload</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_view.png" title="ic_menu_view" alt="Android asset" />
+ <div class="caption">View</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/ic_menu_zoom.png" title="ic_menu_zoom" alt="Android asset" />
+ <div class="caption">Zoom</div></td>
+
+</tr>
+</table>
+
+
+<h3 id="statusbarapx">Standard status bar icons</h3>
+
+<p>Shown below are standard status bar icons included in the Android platform
+(as of Android 1.5). You can reference any of these icon resources from your
+application as needed, but make sure that the meaning of the icon is consistent
+with the standard meaning listed. Note that this is not a complete list of icons
+and that the actual appearance of standard icons may change across platform
+versions.</p>
+
+<p>To reference one of the icons from your code, use
+<code>android.R.drawable.<icon_resource_identifier></code>. For example,
+you can construct a simple notification that references one of the icons like
+this: </p>
+
+<p style="margin-left:2em"><code>new Notification(R.drawable.stat_notify_calendar,
+"sample text", System.currentTimeMillis());</code></p>
+
+<p>To determine the resource ID for an icon listed below, hover over the icon
+or simply look at the image filename, which use the format
+"<icon_resource_identifier>.png".</p>
+
+
+<table class="image-caption">
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_sys_data_bluetooth.png" title="stat_sys_data_bluetooth" alt="Android asset" />
+ <div class="caption">Bluetooth</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_notify_email_generic.png" title="stat_notify_email_generic" alt="Android asset" />
+ <div class="caption">Email</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_notify_chat.png" title="stat_notify_chat" alt="Android asset" />
+ <div class="caption">IM</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_notify_voicemail.png" title="stat_notify_voicemail" alt="Android asset" />
+ <div class="caption">Voicemail</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_sys_warning.png" title="stat_sys_warning" alt="Android asset" />
+ <div class="caption">Warning</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_sys_phone_call.png" title="stat_sys_phone_call" alt="Android asset" />
+ <div class="caption">Call</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_sys_phone_call_forward.png" title="stat_sys_phone_call_forward" alt="Android asset" />
+ <div class="caption">Call forward</div></td>
+
+</tr>
+<tr>
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_sys_phone_call_on_hold.png" title="stat_sys_phone_call_on_hold" alt="Android asset" />
+ <div class="caption">Call on hold</div></td>
+
+
+<td class="image-caption-i image-list">
+ <img src="{@docRoot}images/icon_design/stat_notify_missed_call.png" title="stat_notify_missed_call" alt="Android asset" />
+ <div class="caption">Missed call</div></td>
+
+</tr>
+</table>
+
+
diff --git a/docs/html/guide/practices/ui_guidelines/index.jd b/docs/html/guide/practices/ui_guidelines/index.jd
index 2d14fa6..ea3551d 100644
--- a/docs/html/guide/practices/ui_guidelines/index.jd
+++ b/docs/html/guide/practices/ui_guidelines/index.jd
@@ -12,7 +12,7 @@
<dl>
<dt><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Icon
Design Guidelines</a> and <a
-href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon Templates Pack
+href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon Templates Pack
» </a></dt>
<dd>Your applications need a wide variety of icons, from a launcher icon to
icons in menus, dialogs, tabs, the status bar, and lists. The Icon Guidelines
diff --git a/docs/html/images/icon_design/IconGraphic_AccentColor.png b/docs/html/images/icon_design/IconGraphic_AccentColor.png
new file mode 100644
index 0000000..93ebf8d
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_AccentColor.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_Colors.png b/docs/html/images/icon_design/IconGraphic_Colors.png
new file mode 100644
index 0000000..f70eefc
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_Colors.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_DosDonts.png b/docs/html/images/icon_design/IconGraphic_DosDonts.png
new file mode 100644
index 0000000..db27ec1
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_DosDonts.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_Icons.png b/docs/html/images/icon_design/IconGraphic_Icons.png
new file mode 100644
index 0000000..ff17062
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_Icons.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_Icons_i.png b/docs/html/images/icon_design/IconGraphic_Icons_i.png
new file mode 100644
index 0000000..f389e14
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_Icons_i.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_Materials.png b/docs/html/images/icon_design/IconGraphic_Materials.png
new file mode 100644
index 0000000..52bb173
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_Materials.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_OpticalSize_l.png b/docs/html/images/icon_design/IconGraphic_OpticalSize_l.png
new file mode 100644
index 0000000..1572ced
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_OpticalSize_l.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_OpticalSize_ldpi.png b/docs/html/images/icon_design/IconGraphic_OpticalSize_ldpi.png
new file mode 100644
index 0000000..4f6fdaa
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_OpticalSize_ldpi.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_OpticalSize_s.png b/docs/html/images/icon_design/IconGraphic_OpticalSize_s.png
new file mode 100644
index 0000000..99704d2c
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_OpticalSize_s.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_Shadow_HVGA.png b/docs/html/images/icon_design/IconGraphic_Shadow_HVGA.png
new file mode 100644
index 0000000..0a7380b
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_Shadow_HVGA.png
Binary files differ
diff --git a/docs/html/images/icon_design/IconGraphic_Shadow_WVGA.png b/docs/html/images/icon_design/IconGraphic_Shadow_WVGA.png
new file mode 100644
index 0000000..0e9375b
--- /dev/null
+++ b/docs/html/images/icon_design/IconGraphic_Shadow_WVGA.png
Binary files differ
diff --git a/docs/html/images/icon_design/do_dont_menuicons.png b/docs/html/images/icon_design/do_dont_menuicons.png
new file mode 100644
index 0000000..b53db96
--- /dev/null
+++ b/docs/html/images/icon_design/do_dont_menuicons.png
Binary files differ
diff --git a/docs/html/images/icon_design/do_dont_statusicons.png b/docs/html/images/icon_design/do_dont_statusicons.png
new file mode 100644
index 0000000..20c6737
--- /dev/null
+++ b/docs/html/images/icon_design/do_dont_statusicons.png
Binary files differ
diff --git a/docs/html/shareables/icon_templates-v2.0.zip b/docs/html/shareables/icon_templates-v2.0.zip
new file mode 100644
index 0000000..1c4b4988
--- /dev/null
+++ b/docs/html/shareables/icon_templates-v2.0.zip
Binary files differ
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b56e638..47a1ec3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1245,7 +1245,7 @@
/**
* Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
* @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
*/
public static final int AUDIOFOCUS_GAIN = 1;
@@ -1253,7 +1253,7 @@
* Used to indicate a temporary gain or request of audio focus, anticipated to last a short
* amount of time. Examples of temporary changes are the playback of driving directions, or an
* event notification.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
* @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
*/
public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
@@ -1263,25 +1263,25 @@
* after having lowered their output level (also referred to as "ducking").
* Examples of temporary changes are the playback of driving directions where playback of music
* in the background is acceptable.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
* @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
*/
public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
/**
* Used to indicate a loss of audio focus of unknown duration.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
*/
public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
/**
* Used to indicate a transient loss of audio focus.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
*/
public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
/**
* Used to indicate a transient loss of audio focus where the loser of the audio focus can
* lower its output volume if it wants to continue playing (also referred to as "ducking"), as
* the new focus owner doesn't require others to be silent.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
*/
public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
-1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
@@ -1303,7 +1303,7 @@
* {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
* and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
*/
- public void onAudioFocusChanged(int focusChange);
+ public void onAudioFocusChange(int focusChange);
}
/**
@@ -1350,7 +1350,7 @@
listener = findFocusListener((String)msg.obj);
}
if (listener != null) {
- listener.onAudioFocusChanged(msg.what);
+ listener.onAudioFocusChange(msg.what);
}
}
};
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 1ffb427..e088417 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -400,7 +400,7 @@
}
public long timeToNextAlarm() {
- long nextAlarm = 0xfffffffffffffffl;
+ long nextAlarm = Long.MAX_VALUE;
synchronized (mLock) {
for (int i=AlarmManager.RTC_WAKEUP;
i<=AlarmManager.ELAPSED_REALTIME; i++) {
@@ -420,7 +420,18 @@
{
if (mDescriptor != -1)
{
- set(mDescriptor, alarm.type, (alarm.when * 1000 * 1000));
+ // The kernel never triggers alarms with negative wakeup times
+ // so we ensure they are positive.
+ long alarmSeconds, alarmNanoseconds;
+ if (alarm.when < 0) {
+ alarmSeconds = 0;
+ alarmNanoseconds = 0;
+ } else {
+ alarmSeconds = alarm.when / 1000;
+ alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
+ }
+
+ set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
}
else
{
@@ -499,7 +510,7 @@
private native int init();
private native void close(int fd);
- private native void set(int fd, int type, long nanoseconds);
+ private native void set(int fd, int type, long seconds, long nanoseconds);
private native int waitForAlarm(int fd);
private native int setKernelTimezone(int fd, int minuteswest);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 8788cd5..ef1738b 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1824,21 +1824,19 @@
if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
- final int N1 = s1.length;
- final int N2 = s2.length;
- for (int i=0; i<N1; i++) {
- boolean match = false;
- for (int j=0; j<N2; j++) {
- if (s1[i].equals(s2[j])) {
- match = true;
- break;
- }
- }
- if (!match) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
+ HashSet<Signature> set1 = new HashSet<Signature>();
+ for (Signature sig : s1) {
+ set1.add(sig);
}
- return PackageManager.SIGNATURE_MATCH;
+ HashSet<Signature> set2 = new HashSet<Signature>();
+ for (Signature sig : s2) {
+ set2.add(sig);
+ }
+ // Make sure s2 contains all signatures in s1.
+ if (set1.equals(set2)) {
+ return PackageManager.SIGNATURE_MATCH;
+ }
+ return PackageManager.SIGNATURE_NO_MATCH;
}
public String[] getPackagesForUid(int uid) {
@@ -2490,6 +2488,9 @@
mLastScanError = pp.getParseError();
return false;
}
+ } else {
+ // Lets implicitly assign existing certificates.
+ pkg.mSignatures = ps.signatures.mSignatures;
}
}
return true;
@@ -2618,28 +2619,27 @@
}
private boolean verifySignaturesLP(PackageSetting pkgSetting,
- PackageParser.Package pkg, int parseFlags, boolean updateSignature) {
- if (pkg.mSignatures != null) {
- if (!pkgSetting.signatures.updateSignatures(pkg.mSignatures,
- updateSignature)) {
- Slog.e(TAG, "Package " + pkg.packageName
- + " signatures do not match the previously installed version; ignoring!");
- mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
- return false;
- }
-
- if (pkgSetting.sharedUser != null) {
- if (!pkgSetting.sharedUser.signatures.mergeSignatures(
- pkg.mSignatures, updateSignature)) {
+ PackageParser.Package pkg) {
+ if (pkgSetting.signatures.mSignatures != null) {
+ // Already existing package. Make sure signatures match
+ if (checkSignaturesLP(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
+ PackageManager.SIGNATURE_MATCH) {
Slog.e(TAG, "Package " + pkg.packageName
- + " has no signatures that match those in shared user "
- + pkgSetting.sharedUser.name + "; ignoring!");
- mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+ + " signatures do not match the previously installed version; ignoring!");
+ mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
return false;
}
+ }
+ // Check for shared user signatures
+ if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
+ if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+ Slog.e(TAG, "Package " + pkg.packageName
+ + " has no signatures that match those in shared user "
+ + pkgSetting.sharedUser.name + "; ignoring!");
+ mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+ return false;
}
- } else {
- pkg.mSignatures = pkgSetting.signatures.mSignatures;
}
return true;
}
@@ -2973,10 +2973,8 @@
pkg.applicationInfo.uid = pkgSetting.userId;
pkg.mExtras = pkgSetting;
- if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
- (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
+ if (!verifySignaturesLP(pkgSetting, pkg)) {
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
return null;
}
// The signature has changed, but this package is in the system
@@ -2988,8 +2986,9 @@
// associated with an overall shared user, which doesn't seem all
// that unreasonable.
if (pkgSetting.sharedUser != null) {
- if (!pkgSetting.sharedUser.signatures.mergeSignatures(
- pkg.mSignatures, false)) {
+ if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+ Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return null;
}
@@ -5519,7 +5518,7 @@
// First find the old package info and check signatures
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
- if (checkSignaturesLP(pkg.mSignatures, oldPackage.mSignatures)
+ if (checkSignaturesLP(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
@@ -5547,7 +5546,6 @@
oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
}
- parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
// First delete the existing package while retaining the data directory
if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
res.removedInfo)) {
@@ -5571,20 +5569,7 @@
}
}
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- // If we deleted an exisiting package, the old source and resource files that we
- // were keeping around in case we needed them (see below) can now be deleted.
- // This info will be set on the res.removedInfo to clean up later on as post
- // install action.
-
- //update signature on the new package setting
- //this should always succeed, since we checked the
- //signature earlier.
- synchronized(mPackages) {
- verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
- parseFlags, true);
- }
- } else {
+ if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// remove package from internal structures. Note that we want deletePackageX to
// delete the package data and cache directories that it created in
// scanPackageLocked, unless those directories existed before we even tried to
@@ -5603,19 +5588,23 @@
Slog.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
return;
}
- PackageInstalledInfo restoreRes = new PackageInstalledInfo();
- restoreRes.removedInfo = new PackageRemovedInfo();
// Parse old package
- parseFlags &= ~PackageManager.INSTALL_REPLACE_EXISTING;
- scanPackageLI(restoreFile, parseFlags, scanMode);
+ boolean oldOnSd = isExternal(deletedPackage);
+ int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
+ (isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+ (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
+ int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE;
+ if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode) == null) {
+ Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
+ return;
+ }
+ // Restore of old package succeeded. Update permissions.
synchronized (mPackages) {
updatePermissionsLP(deletedPackage.packageName, deletedPackage,
true, false);
mSettings.writeLP();
}
- if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
- }
+ Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
}
}
}
@@ -5667,15 +5656,7 @@
updatedSettings = true;
}
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- //update signature on the new package setting
- //this should always succeed, since we checked the
- //signature earlier.
- synchronized(mPackages) {
- verifySignaturesLP(mSettings.mPackages.get(packageName), pkg,
- parseFlags, true);
- }
- } else {
+ if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// Re installation failed. Restore old information
// Remove new pkg information
if (newPackage != null) {
@@ -5757,7 +5738,7 @@
boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
boolean replace = false;
- int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
+ int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
| (newInstall ? SCAN_NEW_INSTALL : 0);
// Result object to be returned
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
@@ -5887,6 +5868,10 @@
return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
}
+ private boolean isExternal(PackageParser.Package pkg) {
+ return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
+ }
+
private void extractPublicFiles(PackageParser.Package newPackage,
File publicZipFile) throws IOException {
final ZipOutputStream publicZipOutStream =
@@ -7316,101 +7301,6 @@
}
}
- /**
- * If any of the given 'sigs' is contained in the existing signatures,
- * then completely replace the current signatures with the ones in
- * 'sigs'. This is used for updating an existing package to a newly
- * installed version.
- */
- boolean updateSignatures(Signature[] sigs, boolean update) {
- if (mSignatures == null) {
- if (update) {
- assignSignatures(sigs);
- }
- return true;
- }
- if (sigs == null) {
- return false;
- }
-
- for (int i=0; i<sigs.length; i++) {
- Signature sig = sigs[i];
- for (int j=0; j<mSignatures.length; j++) {
- if (mSignatures[j].equals(sig)) {
- if (update) {
- assignSignatures(sigs);
- }
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * If any of the given 'sigs' is contained in the existing signatures,
- * then add in any new signatures found in 'sigs'. This is used for
- * including a new package into an existing shared user id.
- */
- boolean mergeSignatures(Signature[] sigs, boolean update) {
- if (mSignatures == null) {
- if (update) {
- assignSignatures(sigs);
- }
- return true;
- }
- if (sigs == null) {
- return false;
- }
-
- Signature[] added = null;
- int addedCount = 0;
- boolean haveMatch = false;
- for (int i=0; i<sigs.length; i++) {
- Signature sig = sigs[i];
- boolean found = false;
- for (int j=0; j<mSignatures.length; j++) {
- if (mSignatures[j].equals(sig)) {
- found = true;
- haveMatch = true;
- break;
- }
- }
-
- if (!found) {
- if (added == null) {
- added = new Signature[sigs.length];
- }
- added[i] = sig;
- addedCount++;
- }
- }
-
- if (!haveMatch) {
- // Nothing matched -- reject the new signatures.
- return false;
- }
- if (added == null) {
- // Completely matched -- nothing else to do.
- return true;
- }
-
- // Add additional signatures in.
- if (update) {
- Signature[] total = new Signature[addedCount+mSignatures.length];
- System.arraycopy(mSignatures, 0, total, 0, mSignatures.length);
- int j = mSignatures.length;
- for (int i=0; i<added.length; i++) {
- if (added[i] != null) {
- total[j] = added[i];
- j++;
- }
- }
- mSignatures = total;
- }
- return true;
- }
-
private void assignSignatures(Signature[] sigs) {
if (sigs == null) {
mSignatures = null;
@@ -8191,6 +8081,15 @@
if (pkg.mVersionCode != p.versionCode) {
p.versionCode = pkg.mVersionCode;
}
+ // Update signatures if needed.
+ if (p.signatures.mSignatures == null) {
+ p.signatures.assignSignatures(pkg.mSignatures);
+ }
+ // If this app defines a shared user id initialize
+ // the shared user signatures as well.
+ if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
+ p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
+ }
addPackageSettingLP(p, pkg.packageName, p.sharedUser);
}
@@ -9619,22 +9518,12 @@
// Parse package
int parseFlags = PackageParser.PARSE_CHATTY |
PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
- PackageParser pp = new PackageParser(codePath);
- pp.setSeparateProcesses(mSeparateProcesses);
- final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
- codePath, mMetrics, parseFlags);
- pp = null;
doGc = true;
- // Check for parse errors
- if (pkg == null) {
- Slog.e(TAG, "Parse error when installing install pkg : "
- + args.cid + " from " + args.cachePath);
- continue;
- }
- setApplicationInfoPaths(pkg, codePath, codePath);
synchronized (mInstallLock) {
+ final PackageParser.Package pkg = scanPackageLI(new File(codePath),
+ parseFlags, 0);
// Scan the package
- if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
+ if (pkg != null) {
synchronized (mPackages) {
retCode = PackageManager.INSTALL_SUCCEEDED;
pkgList.add(pkg.packageName);
@@ -9642,8 +9531,8 @@
args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
}
} else {
- Slog.i(TAG, "Failed to install pkg: " +
- pkg.packageName + " from sdcard");
+ Slog.i(TAG, "Failed to install pkg from " +
+ codePath + " from sdcard");
}
}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index c40650a..1850b9a 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -19,14 +19,12 @@
import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
-import android.app.IActivityManager;
import android.app.IUiModeManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.UiModeManager;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -310,9 +308,6 @@
}
public void enableCarMode() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ENABLE_CAR_MODE,
- "Need ENABLE_CAR_MODE permission");
synchronized (mLock) {
setCarModeLocked(true);
if (mSystemReady) {
@@ -394,7 +389,7 @@
} else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
uiMode = Configuration.UI_MODE_TYPE_DESK;
}
- if (uiMode != 0) {
+ if (mCarModeEnabled) {
if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
updateTwilightLocked();
uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 0e4b38d..a1a8bf2 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -11269,6 +11269,8 @@
float mDimTargetAlpha;
float mDimDeltaPerMs;
long mLastDimAnimTime;
+
+ int mLastDimWidth, mLastDimHeight;
DimAnimator (SurfaceSession session) {
if (mDimSurface == null) {
@@ -11294,12 +11296,18 @@
dw + "x" + dh + ")");
mDimShown = true;
try {
+ mLastDimWidth = dw;
+ mLastDimHeight = dh;
mDimSurface.setPosition(0, 0);
mDimSurface.setSize(dw, dh);
mDimSurface.show();
} catch (RuntimeException e) {
Slog.w(TAG, "Failure showing dim surface", e);
}
+ } else if (mLastDimWidth != dw || mLastDimHeight != dh) {
+ mLastDimWidth = dw;
+ mLastDimHeight = dh;
+ mDimSurface.setSize(dw, dh);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d59dd21..3b655fa 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2996,7 +2996,7 @@
if (!ret.finishing) {
int index = indexOfTokenLocked(ret);
if (index >= 0) {
- finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
+ finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear");
}
return null;
@@ -8910,6 +8910,34 @@
removeProcessLocked(app, false);
return false;
}
+ } else {
+ HistoryRecord r = topRunningActivityLocked(null);
+ if (r.app == app) {
+ // If the top running activity is from this crashing
+ // process, then terminate it to avoid getting in a loop.
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ int index = indexOfTokenLocked(r);
+ finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed");
+ // Also terminate an activities below it that aren't yet
+ // stopped, to avoid a situation where one will get
+ // re-start our crashing activity once it gets resumed again.
+ index--;
+ if (index >= 0) {
+ r = (HistoryRecord)mHistory.get(index);
+ if (r.state == ActivityState.RESUMED
+ || r.state == ActivityState.PAUSING
+ || r.state == ActivityState.PAUSED) {
+ if (!r.isHomeActivity) {
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed");
+ }
+ }
+ }
+ }
}
// Bump up the crash count of any services currently running in the proc.
@@ -10228,12 +10256,10 @@
int count = mHistory.size();
// convert the token to an entry in the history.
- HistoryRecord r = null;
int index = -1;
for (int i=count-1; i>=0; i--) {
Object o = mHistory.get(i);
if (o == token) {
- r = (HistoryRecord)o;
index = i;
break;
}
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index 85d63c9..0e162bd 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -38,10 +38,6 @@
#include <linux/android_alarm.h>
#endif
-#define ONE_NANOSECOND 1000000000LL
-#define NANOSECONDS_TO_SECONDS(x) (x / ONE_NANOSECOND)
-#define SECONDS_TO_NANOSECONDS(x) (x * ONE_NANOSECOND)
-
namespace android {
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
@@ -82,17 +78,17 @@
#endif
}
-static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong nanoseconds)
+static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
{
#if HAVE_ANDROID_OS
struct timespec ts;
- ts.tv_sec = NANOSECONDS_TO_SECONDS(nanoseconds);
- ts.tv_nsec = nanoseconds - SECONDS_TO_NANOSECONDS(ts.tv_sec);
+ ts.tv_sec = seconds;
+ ts.tv_nsec = nanoseconds;
int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
if (result < 0)
{
- LOGE("Unable to set alarm to %lld: %s\n", nanoseconds, strerror(errno));
+ LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
}
#endif
}
@@ -121,7 +117,7 @@
/* name, signature, funcPtr */
{"init", "()I", (void*)android_server_AlarmManagerService_init},
{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
- {"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
+ {"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set},
{"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
};