Add an icon to the user information.
Store the icon in the user folder under /data/system,
similar to how the wallpaper is stored.
Change-Id: Id8ccb55b9e2ba7b4c557505a7f69f04eca1518cf
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 191a696..9a50a41 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1206,7 +1206,8 @@
return mPM.getUsers();
} catch (RemoteException re) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>();
- UserInfo primary = new UserInfo(0, "Root!", UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
+ UserInfo primary = new UserInfo(0, "Root!", null,
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
users.add(primary);
return users;
}
@@ -1240,9 +1241,9 @@
* @hide
*/
@Override
- public void updateUserName(int id, String name) {
+ public void setUserName(int id, String name) {
try {
- mPM.updateUserName(id, name);
+ mPM.setUserName(id, name);
} catch (RemoteException re) {
}
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 70c0c48..6f00abd 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -41,6 +41,7 @@
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
+import android.os.ParcelFileDescriptor;
import android.content.IntentSender;
/**
@@ -359,7 +360,8 @@
UserInfo createUser(in String name, int flags);
boolean removeUser(int userId);
- void updateUserName(int userId, String name);
+ void setUserName(int userId, String name);
+ ParcelFileDescriptor setUserIcon(int userId);
void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer,
int flags, in String installerPackageName, in Uri verificationURI,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6de69b0..f9f7e2d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2646,7 +2646,7 @@
* @param name the new name for the user
* @hide
*/
- public abstract void updateUserName(int id, String name);
+ public abstract void setUserName(int id, String name);
/**
* Changes the user's properties specified by the flags.
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index ba5331c..68a7257 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -43,12 +43,18 @@
public int id;
public String name;
+ public String iconPath;
public int flags;
public UserInfo(int id, String name, int flags) {
+ this(id, name, null, flags);
+ }
+
+ public UserInfo(int id, String name, String iconPath, int flags) {
this.id = id;
this.name = name;
this.flags = flags;
+ this.iconPath = iconPath;
}
public boolean isPrimary() {
@@ -68,6 +74,7 @@
public UserInfo(UserInfo orig) {
name = orig.name;
+ iconPath = orig.iconPath;
id = orig.id;
flags = orig.flags;
}
@@ -84,6 +91,7 @@
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeInt(id);
dest.writeString(name);
+ dest.writeString(iconPath);
dest.writeInt(flags);
}
@@ -100,6 +108,7 @@
private UserInfo(Parcel source) {
id = source.readInt();
name = source.readString();
+ iconPath = source.readString();
flags = source.readInt();
}
}
diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml
index 694301e..009f37b 100644
--- a/core/res/res/layout/global_actions_item.xml
+++ b/core/res/res/layout/global_actions_item.xml
@@ -27,11 +27,11 @@
android:paddingBottom="6dip"
>
<ImageView android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
android:layout_gravity="center"
android:layout_marginRight="16dip"
- />
+ android:scaleType="center"/>
<LinearLayout
android:orientation="vertical"
diff --git a/core/res/res/layout/preference_holo.xml b/core/res/res/layout/preference_holo.xml
index e574219..8402b36 100644
--- a/core/res/res/layout/preference_holo.xml
+++ b/core/res/res/layout/preference_holo.xml
@@ -33,11 +33,12 @@
android:orientation="horizontal">
<ImageView
android:id="@+android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_gravity="center"
- android:minWidth="48dp"
- android:paddingRight="@dimen/preference_item_padding_inner" />
+ android:scaleType="centerCrop"
+ android:layout_marginRight="@dimen/preference_item_padding_inner"
+ />
</LinearLayout>
<RelativeLayout
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 5094df18..381e65b 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -19,6 +19,7 @@
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.TypedValue;
import java.io.BufferedInputStream;
@@ -303,6 +304,7 @@
/* do nothing.
If the exception happened on open, bm will be null.
*/
+ Log.e("BitmapFactory", "Unable to decode stream: " + e);
} finally {
if (stream != null) {
try {
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index f09c010..6eca3b6 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -246,6 +246,7 @@
throw new IllegalStateException(e);
}
}
+
};
public DefaultContainerService() {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index fc187ce..e9b8267 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -29,6 +29,8 @@
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ScaleDrawable;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Handler;
@@ -43,6 +45,7 @@
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;
+import android.view.Gravity;
import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.View;
@@ -52,6 +55,7 @@
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
import android.widget.TextView;
import java.util.ArrayList;
@@ -243,8 +247,10 @@
for (final UserInfo user : users) {
boolean isCurrentUser = currentUser == null
? user.id == 0 : (currentUser.id == user.id);
+ Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
+ : null;
SinglePressAction switchToUser = new SinglePressAction(
- com.android.internal.R.drawable.ic_menu_cc,
+ com.android.internal.R.drawable.ic_menu_cc, icon,
(user.name != null ? user.name : "Primary")
+ (isCurrentUser ? " \u2714" : "")) {
public void onPress() {
@@ -439,6 +445,7 @@
*/
private static abstract class SinglePressAction implements Action {
private final int mIconResId;
+ private final Drawable mIcon;
private final int mMessageResId;
private final CharSequence mMessage;
@@ -446,13 +453,23 @@
mIconResId = iconResId;
mMessageResId = messageResId;
mMessage = null;
+ mIcon = null;
+ }
+
+ protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
+ mIconResId = iconResId;
+ mMessageResId = 0;
+ mMessage = message;
+ mIcon = icon;
}
protected SinglePressAction(int iconResId, CharSequence message) {
mIconResId = iconResId;
mMessageResId = 0;
mMessage = message;
+ mIcon = null;
}
+
public boolean isEnabled() {
return true;
}
@@ -471,8 +488,12 @@
TextView messageView = (TextView) v.findViewById(R.id.message);
v.findViewById(R.id.status).setVisibility(View.GONE);
-
- icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
+ if (mIcon != null) {
+ icon.setImageDrawable(mIcon);
+ icon.setScaleType(ScaleType.CENTER_CROP);
+ } else if (mIconResId != 0) {
+ icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
+ }
if (mMessage != null) {
messageView.setText(mMessage);
} else {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index e71556e..fee55f3 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -9388,9 +9388,15 @@
}
@Override
- public void updateUserName(int userId, String name) {
+ public void setUserName(int userId, String name) {
enforceSystemOrRoot("Only the system can rename users");
- sUserManager.updateUserName(userId, name);
+ sUserManager.setUserName(userId, name);
+ }
+
+ @Override
+ public ParcelFileDescriptor setUserIcon(int userId) {
+ enforceSystemOrRoot("Only the system can update users");
+ return sUserManager.setUserIcon(userId);
}
@Override
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java
index 4e9e666..738ab08 100644
--- a/services/java/com/android/server/pm/UserManager.java
+++ b/services/java/com/android/server/pm/UserManager.java
@@ -16,6 +16,9 @@
package com.android.server.pm;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -24,6 +27,7 @@
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.UserId;
import android.util.Log;
@@ -34,6 +38,7 @@
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -44,10 +49,15 @@
import org.xmlpull.v1.XmlSerializer;
public class UserManager {
+
+ private static final String TAG = "UserManager";
+
private static final String TAG_NAME = "name";
private static final String ATTR_FLAGS = "flags";
+ private static final String ATTR_ICON_PATH = "icon";
+
private static final String ATTR_ID = "id";
private static final String TAG_USERS = "users";
@@ -58,6 +68,7 @@
private static final String USER_INFO_DIR = "system" + File.separator + "users";
private static final String USER_LIST_FILENAME = "userlist.xml";
+ private static final String USER_PHOTO_FILENAME = "photo.png";
private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
@@ -114,7 +125,7 @@
}
}
- public void updateUserName(int userId, String name) {
+ public void setUserName(int userId, String name) {
synchronized (mUsers) {
UserInfo info = mUsers.get(userId);
if (name != null && !name.equals(info.name)) {
@@ -124,6 +135,39 @@
}
}
+ public ParcelFileDescriptor setUserIcon(int userId) {
+ synchronized (mUsers) {
+ UserInfo info = mUsers.get(userId);
+ if (info == null) return null;
+ ParcelFileDescriptor fd = updateIconBitmapLocked(info);
+ if (fd != null) {
+ writeUserLocked(info);
+ }
+ return fd;
+ }
+ }
+
+ private ParcelFileDescriptor updateIconBitmapLocked(UserInfo info) {
+ try {
+ File dir = new File(mUsersDir, Integer.toString(info.id));
+ File file = new File(dir, USER_PHOTO_FILENAME);
+ if (!dir.exists()) {
+ dir.mkdir();
+ FileUtils.setPermissions(
+ dir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
+ MODE_CREATE|MODE_READ_WRITE);
+ info.iconPath = file.getAbsolutePath();
+ return fd;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Error setting photo for user ", e);
+ }
+ return null;
+ }
+
/**
* Returns an array of user ids. This array is cached here for quick access, so do not modify or
* cache it elsewhere.
@@ -187,7 +231,7 @@
private void fallbackToSingleUserLocked() {
// Create the primary user
- UserInfo primary = new UserInfo(0, "Primary",
+ UserInfo primary = new UserInfo(0, "Primary", null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
mUsers.put(0, primary);
updateUserIdsLocked();
@@ -219,6 +263,9 @@
serializer.startTag(null, TAG_USER);
serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
+ if (userInfo.iconPath != null) {
+ serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
+ }
serializer.startTag(null, TAG_NAME);
serializer.text(userInfo.name);
@@ -286,6 +333,7 @@
private UserInfo readUser(int id) {
int flags = 0;
String name = null;
+ String iconPath = null;
FileInputStream fis = null;
try {
@@ -312,6 +360,7 @@
}
String flagString = parser.getAttributeValue(null, ATTR_FLAGS);
flags = Integer.parseInt(flagString);
+ iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
@@ -324,7 +373,7 @@
}
}
- UserInfo userInfo = new UserInfo(id, name, flags);
+ UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
return userInfo;
} catch (IOException ioe) {
@@ -342,7 +391,7 @@
public UserInfo createUser(String name, int flags) {
int userId = getNextAvailableId();
- UserInfo userInfo = new UserInfo(userId, name, flags);
+ UserInfo userInfo = new UserInfo(userId, name, null, flags);
File userPath = new File(mBaseUserPath, Integer.toString(userId));
if (!createPackageFolders(userId, userPath)) {
return null;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index c23e868..416900f8 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -179,7 +179,7 @@
@Override
public List<UserInfo> getUsers() {
final ArrayList<UserInfo> users = new ArrayList<UserInfo>();
- users.add(new UserInfo(USER_ID, "Primary", UserInfo.FLAG_PRIMARY));
+ users.add(new UserInfo(USER_ID, "Primary", null, UserInfo.FLAG_PRIMARY));
users.add(new UserInfo(USER_ID_GUEST, "Guest", 0));
return users;
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 86689f3..0399b3b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -545,7 +545,7 @@
* @hide
*/
@Override
- public void updateUserName(int id, String name) {
+ public void setUserName(int id, String name) {
throw new UnsupportedOperationException();
}