Fix a bug resolving the correct icon/logo in action bars

Remove some abstraction-breaking magic in ActionBarView and replace it
with proper resolution of the icon/logo when creating a window. The
old implementation relied on the ActionBarView's context being an
Activity.

Bug 9171554

Change-Id: Idbbb1942622195dcb55e8119f2d64287b07bb509
This commit is contained in:
Adam Powell
2013-05-31 14:39:48 -07:00
parent c1e0ca9fee
commit 04fe6ebb9f
16 changed files with 158 additions and 54 deletions

View File

@ -6808,6 +6808,7 @@ package android.content.pm {
ctor public ComponentInfo(android.content.pm.ComponentInfo);
ctor protected ComponentInfo(android.os.Parcel);
method public final int getIconResource();
method public final int getLogoResource();
method public boolean isEnabled();
field public android.content.pm.ApplicationInfo applicationInfo;
field public int descriptionRes;
@ -27040,7 +27041,9 @@ package android.view {
method public void setFlags(int, int);
method public void setFormat(int);
method public void setGravity(int);
method public void setIcon(int);
method public void setLayout(int, int);
method public void setLogo(int);
method public void setSoftInputMode(int);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract void setTitleColor(int);

View File

@ -1877,9 +1877,12 @@ public class Activity extends ContextThemeWrapper
if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
return;
}
mActionBar = new ActionBarImpl(this);
mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
mWindow.setDefaultIcon(mActivityInfo.getIconResource());
mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
}
/**

View File

@ -16,6 +16,8 @@
package android.app;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.android.internal.app.ActionBarImpl;
import com.android.internal.policy.PolicyManager;
@ -264,6 +266,9 @@ public class Dialog implements DialogInterface, Window.Callback,
mDecor = mWindow.getDecorView();
if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
final ApplicationInfo info = mContext.getApplicationInfo();
mWindow.setDefaultIcon(info.icon);
mWindow.setDefaultLogo(info.logo);
mActionBar = new ActionBarImpl(this);
}

View File

@ -116,6 +116,17 @@ public class ComponentInfo extends PackageItemInfo {
public final int getIconResource() {
return icon != 0 ? icon : applicationInfo.icon;
}
/**
* Return the logo resource identifier to use for this component. If
* the component defines a logo, that is used; else, the application
* logo is used.
*
* @return The logo associated with this component.
*/
public final int getLogoResource() {
return logo != 0 ? logo : applicationInfo.logo;
}
protected void dumpFront(Printer pw, String prefix) {
super.dumpFront(pw, prefix);

View File

@ -97,7 +97,7 @@ interface IWindowManager
void executeAppTransition();
void setAppStartingWindow(IBinder token, String pkg, int theme,
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
void setAppWillBeHidden(IBinder token);
void setAppVisibility(IBinder token, boolean visible);
void startAppFreezingScreen(IBinder token, int configChanges);

View File

@ -1256,4 +1256,38 @@ public abstract class Window {
* @param mask Flags specifying which options should be modified. Others will remain unchanged.
*/
public void setUiOptions(int uiOptions, int mask) { }
/**
* Set the primary icon for this window.
*
* @param resId resource ID of a drawable to set
*/
public void setIcon(int resId) { }
/**
* Set the default icon for this window.
* This will be overridden by any other icon set operation which could come from the
* theme or another explicit set.
*
* @hide
*/
public void setDefaultIcon(int resId) { }
/**
* Set the logo for this window. A logo is often shown in place of an
* {@link #setIcon(int) icon} but is generally wider and communicates window title information
* as well.
*
* @param resId resource ID of a drawable to set
*/
public void setLogo(int resId) { }
/**
* Set the default logo for this window.
* This will be overridden by any other logo set operation which could come from the
* theme or another explicit set.
*
* @hide
*/
public void setDefaultLogo(int resId) { }
}

View File

@ -642,7 +642,7 @@ public interface WindowManagerPolicy {
*/
public View addStartingWindow(IBinder appToken, String packageName,
int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel,
int labelRes, int icon, int windowFlags);
int labelRes, int icon, int logo, int windowFlags);
/**
* Called when the first window of an application has been displayed, while

View File

@ -1210,6 +1210,10 @@ public class ActionBarImpl extends ActionBar {
mActionView.setIcon(icon);
}
public boolean hasIcon() {
return mActionView.hasIcon();
}
@Override
public void setLogo(int resId) {
mActionView.setLogo(resId);
@ -1220,6 +1224,10 @@ public class ActionBarImpl extends ActionBar {
mActionView.setLogo(logo);
}
public boolean hasLogo() {
return mActionView.hasLogo();
}
public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
if (!mDisplayHomeAsUpSet) {
setDisplayHomeAsUpEnabled(enable);

View File

@ -16,24 +16,12 @@
package com.android.internal.widget;
import com.android.internal.R;
import com.android.internal.view.menu.ActionMenuItem;
import com.android.internal.view.menu.ActionMenuPresenter;
import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.SubMenuBuilder;
import android.animation.LayoutTransition;
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@ -42,7 +30,6 @@ import android.os.Parcelable;
import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.CollapsibleActionView;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -62,6 +49,15 @@ import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.view.menu.ActionMenuItem;
import com.android.internal.view.menu.ActionMenuPresenter;
import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.SubMenuBuilder;
/**
* @hide
@ -188,34 +184,8 @@ public class ActionBarView extends AbsActionBarView {
ActionBar.NAVIGATION_MODE_STANDARD);
mTitle = a.getText(R.styleable.ActionBar_title);
mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
mLogo = a.getDrawable(R.styleable.ActionBar_logo);
if (mLogo == null) {
if (context instanceof Activity) {
try {
mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
} catch (NameNotFoundException e) {
Log.e(TAG, "Activity component name not found!", e);
}
}
if (mLogo == null) {
mLogo = appInfo.loadLogo(pm);
}
}
mIcon = a.getDrawable(R.styleable.ActionBar_icon);
if (mIcon == null) {
if (context instanceof Activity) {
try {
mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
} catch (NameNotFoundException e) {
Log.e(TAG, "Activity component name not found!", e);
}
}
if (mIcon == null) {
mIcon = appInfo.loadIcon(pm);
}
}
final LayoutInflater inflater = LayoutInflater.from(context);
@ -729,7 +699,11 @@ public class ActionBarView extends AbsActionBarView {
}
public void setIcon(int resId) {
setIcon(mContext.getResources().getDrawable(resId));
setIcon(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
}
public boolean hasIcon() {
return mIcon != null;
}
public void setLogo(Drawable logo) {
@ -740,7 +714,11 @@ public class ActionBarView extends AbsActionBarView {
}
public void setLogo(int resId) {
setLogo(mContext.getResources().getDrawable(resId));
setLogo(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
}
public boolean hasLogo() {
return mLogo != null;
}
public void setNavigationMode(int mode) {

View File

@ -139,6 +139,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private ActionMenuPresenterCallback mActionMenuPresenterCallback;
private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
static final int FLAG_RESOURCE_SET_LOGO = 1 << 1;
int mResourcesSetFlags;
int mIconRes;
int mLogoRes;
private DrawableFeatureState[] mDrawables;
private PanelFeatureState[] mPanels;
@ -1393,6 +1399,46 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
@Override
public void setIcon(int resId) {
mIconRes = resId;
mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
if (mActionBar != null) {
mActionBar.setIcon(resId);
}
}
@Override
public void setDefaultIcon(int resId) {
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) {
return;
}
mIconRes = resId;
if (mActionBar != null && !mActionBar.hasIcon()) {
mActionBar.setIcon(resId);
}
}
@Override
public void setLogo(int resId) {
mLogoRes = resId;
mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
if (mActionBar != null) {
mActionBar.setLogo(resId);
}
}
@Override
public void setDefaultLogo(int resId) {
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) {
return;
}
mLogoRes = resId;
if (mActionBar != null && !mActionBar.hasLogo()) {
mActionBar.setLogo(resId);
}
}
/**
* Request that key events come to this activity. Use this if your activity
* has no views with focus, but the activity still wants a chance to process
@ -2946,6 +2992,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
"incompatible window decor! Ignoring request.");
}
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
(mIconRes != 0 && !mActionBar.hasIcon())) {
mActionBar.setIcon(mIconRes);
}
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
(mLogoRes != 0 && !mActionBar.hasLogo())) {
mActionBar.setLogo(mLogoRes);
}
// Post the panel invalidate for later; avoid application onCreateOptionsMenu
// being called in the middle of onCreate or similar.
mDecor.post(new Runnable() {

View File

@ -1582,7 +1582,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public View addStartingWindow(IBinder appToken, String packageName, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int windowFlags) {
int icon, int logo, int windowFlags) {
if (!SHOW_STARTING_ANIMATIONS) {
return null;
}
@ -1639,6 +1639,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
}
win.setDefaultIcon(icon);
win.setDefaultLogo(logo);
win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);

View File

@ -86,6 +86,7 @@ final class ActivityRecord {
CharSequence nonLocalizedLabel; // the label information from the package mgr.
int labelRes; // the label information from the package mgr.
int icon; // resource identifier of activity's icon.
int logo; // resource identifier of activity's logo.
int theme; // resource identifier of activity's theme.
int realTheme; // actual theme resource we will use, never 0.
int windowFlags; // custom window flags for preview window.
@ -399,6 +400,7 @@ final class ActivityRecord {
labelRes = app.labelRes;
}
icon = aInfo.getIconResource();
logo = aInfo.getLogoResource();
theme = aInfo.getThemeResource();
realTheme = theme;
if (realTheme == 0) {

View File

@ -1465,8 +1465,8 @@ final class ActivityStack {
mWindowManager.setAppStartingWindow(
next.appToken, next.packageName, next.theme,
mService.compatibilityInfoForPackageLocked(next.info.applicationInfo),
next.nonLocalizedLabel, next.labelRes, next.icon, next.windowFlags,
null, true);
next.nonLocalizedLabel, next.labelRes, next.icon, next.logo,
next.windowFlags, null, true);
}
mStackSupervisor.startSpecificActivityLocked(next, true, false);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@ -1500,7 +1500,7 @@ final class ActivityStack {
mService.compatibilityInfoForPackageLocked(
next.info.applicationInfo),
next.nonLocalizedLabel,
next.labelRes, next.icon, next.windowFlags,
next.labelRes, next.icon, next.logo, next.windowFlags,
null, true);
}
if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
@ -1639,7 +1639,7 @@ final class ActivityStack {
r.appToken, r.packageName, r.theme,
mService.compatibilityInfoForPackageLocked(
r.info.applicationInfo), r.nonLocalizedLabel,
r.labelRes, r.icon, r.windowFlags,
r.labelRes, r.icon, r.logo, r.windowFlags,
prev != null ? prev.appToken : null, showStartingIcon);
}
} else {

View File

@ -25,17 +25,19 @@ final class StartingData {
final CharSequence nonLocalizedLabel;
final int labelRes;
final int icon;
final int logo;
final int windowFlags;
StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo,
CharSequence _nonLocalizedLabel,
int _labelRes, int _icon, int _windowFlags) {
int _labelRes, int _icon, int _logo, int _windowFlags) {
pkg = _pkg;
theme = _theme;
compatInfo = _compatInfo;
nonLocalizedLabel = _nonLocalizedLabel;
labelRes = _labelRes;
icon = _icon;
logo = _logo;
windowFlags = _windowFlags;
}
}

View File

@ -3878,7 +3878,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setAppStartingWindow(IBinder token, String pkg,
int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppStartingWindow()")) {
@ -4079,7 +4079,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData");
mStartingIconInTransition = true;
wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
labelRes, icon, windowFlags);
labelRes, icon, logo, windowFlags);
Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
// Note: we really want to do sendMessageAtFrontOfQueue() because we
// want to process the message ASAP, before any other queued
@ -7083,7 +7083,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
view = mPolicy.addStartingWindow(
wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, sd.windowFlags);
} catch (Exception e) {
Slog.w(TAG, "Exception when adding starting window", e);
}

View File

@ -304,7 +304,7 @@ public class IWindowManagerImpl implements IWindowManager {
@Override
public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
CharSequence arg4, int arg5, int arg6, int arg7, int arg8, IBinder arg9, boolean arg10)
throws RemoteException {
// TODO Auto-generated method stub
}