1224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta/* 2224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * Copyright (C) 2015 The Android Open Source Project 3224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * 4224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * you may not use this file except in compliance with the License. 6224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * You may obtain a copy of the License at 7224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * 8224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 9224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * 10224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 11224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * See the License for the specific language governing permissions and 14224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * limitations under the License. 15224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta */ 16224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 17224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptapackage com.android.layoutlib.bridge.bars; 18224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 19224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport com.android.ide.common.rendering.api.RenderResources; 20224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport com.android.ide.common.rendering.api.ResourceValue; 21224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport com.android.ide.common.rendering.api.SessionParams; 22ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Guptaimport com.android.ide.common.rendering.api.StyleResourceValue; 23224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport com.android.layoutlib.bridge.android.BridgeContext; 24224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport com.android.layoutlib.bridge.impl.ResourceHelper; 25224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport com.android.resources.ResourceType; 26224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 27476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull; 28476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable; 29ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Guptaimport android.content.Context; 30224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport android.graphics.drawable.Drawable; 31ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Guptaimport android.view.ContextThemeWrapper; 32ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Guptaimport android.view.LayoutInflater; 33224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport android.view.View; 34224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport android.widget.FrameLayout; 35224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 36224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport java.lang.reflect.InvocationTargetException; 37224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptaimport java.lang.reflect.Method; 38224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 39224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 40224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta/** 41224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * Assumes that the AppCompat library is present in the project's classpath and creates an 42224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * actionbar around it. 43224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta */ 44224e931fed1220f175805fdec71a882649270aa7Deepanshu Guptapublic class AppCompatActionBar extends BridgeActionBar { 45224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 46224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta private Object mWindowDecorActionBar; 47224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta private static final String WINDOW_ACTION_BAR_CLASS = "android.support.v7.internal.app.WindowDecorActionBar"; 48224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta private Class<?> mWindowActionBarClass; 49224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 50224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta /** 51224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta * Inflate the action bar and attach it to {@code parentView} 52224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta */ 53b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta public AppCompatActionBar(@NonNull BridgeContext context, @NonNull SessionParams params) { 54b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta super(context, params); 55224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta int contentRootId = context.getProjectResourceValue(ResourceType.ID, 56224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta "action_bar_activity_content", 0); 57224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta View contentView = getDecorContent().findViewById(contentRootId); 58224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (contentView != null) { 59224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta assert contentView instanceof FrameLayout; 602e4d93245764a1c1d7515361ddbb8fc1665f814eDeepanshu Gupta setContentRoot((FrameLayout) contentView); 61224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } else { 62224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta // Something went wrong. Create a new FrameLayout in the enclosing layout. 63224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta FrameLayout contentRoot = new FrameLayout(context); 64224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta setMatchParent(contentRoot); 65b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta if (mEnclosingLayout != null) { 66b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta mEnclosingLayout.addView(contentRoot); 67b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta } 68224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta setContentRoot(contentRoot); 69224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 70224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta try { 71224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Class[] constructorParams = {View.class}; 72224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Object[] constructorArgs = {getDecorContent()}; 7337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta mWindowDecorActionBar = params.getLayoutlibCallback().loadView(WINDOW_ACTION_BAR_CLASS, 74224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta constructorParams, constructorArgs); 75224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 76224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta mWindowActionBarClass = mWindowDecorActionBar == null ? null : 77224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta mWindowDecorActionBar.getClass(); 78224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta setupActionBar(); 79224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } catch (Exception e) { 80224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta e.printStackTrace(); 81224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 82224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 83224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 84224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Override 85224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta protected ResourceValue getLayoutResource(BridgeContext context) { 86224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta // We always assume that the app has requested the action bar. 87224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return context.getRenderResources().getProjectResource(ResourceType.LAYOUT, 88224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta "abc_screen_toolbar"); 89224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 90224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 91224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Override 92ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta protected LayoutInflater getInflater(BridgeContext context) { 93ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta // Other than the resource resolution part, the code has been taken from the support 94ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta // library. see code from line 269 onwards in 95ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta // https://android.googlesource.com/platform/frameworks/support/+/android-5.1.0_r1/v7/appcompat/src/android/support/v7/app/ActionBarActivityDelegateBase.java 96ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta Context themedContext = context; 97ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta RenderResources resources = context.getRenderResources(); 98ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta ResourceValue actionBarTheme = resources.findItemInTheme("actionBarTheme", false); 99ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta if (actionBarTheme != null) { 100ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta // resolve it, if needed. 101ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta actionBarTheme = resources.resolveResValue(actionBarTheme); 102ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta } 103ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta if (actionBarTheme instanceof StyleResourceValue) { 104ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta int styleId = context.getDynamicIdByStyle(((StyleResourceValue) actionBarTheme)); 105ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta if (styleId != 0) { 106ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta themedContext = new ContextThemeWrapper(context, styleId); 107ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta } 108ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta } 109ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta return LayoutInflater.from(themedContext); 110ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta } 111ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta 112ada8590547348b77d8cbd56abdb8fadb3e72c015Deepanshu Gupta @Override 113224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta protected void setTitle(CharSequence title) { 114224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (title != null && mWindowDecorActionBar != null) { 115224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Method setTitle = getMethod(mWindowActionBarClass, "setTitle", CharSequence.class); 116224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta invoke(setTitle, mWindowDecorActionBar, title); 117224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 118224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 119224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 120224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Override 121224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta protected void setSubtitle(CharSequence subtitle) { 122224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (subtitle != null && mWindowDecorActionBar != null) { 123224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Method setSubtitle = getMethod(mWindowActionBarClass, "setSubtitle", CharSequence.class); 124224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta invoke(setSubtitle, mWindowDecorActionBar, subtitle); 125224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 126224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 127224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 128224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Override 129224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta protected void setIcon(String icon) { 130224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta // Do this only if the action bar doesn't already have an icon. 131224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (icon != null && !icon.isEmpty() && mWindowDecorActionBar != null) { 1322e4d93245764a1c1d7515361ddbb8fc1665f814eDeepanshu Gupta if (invoke(getMethod(mWindowActionBarClass, "hasIcon"), mWindowDecorActionBar) 1332e4d93245764a1c1d7515361ddbb8fc1665f814eDeepanshu Gupta == Boolean.TRUE) { 134224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Drawable iconDrawable = getDrawable(icon, false); 135224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (iconDrawable != null) { 136224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Method setIcon = getMethod(mWindowActionBarClass, "setIcon", Drawable.class); 137224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta invoke(setIcon, mWindowDecorActionBar, iconDrawable); 138224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 139224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 140224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 141224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 142224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 143224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Override 144224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta protected void setHomeAsUp(boolean homeAsUp) { 145224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (mWindowDecorActionBar != null) { 146224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta Method setHomeAsUp = getMethod(mWindowActionBarClass, 147224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta "setDefaultDisplayHomeAsUpEnabled", boolean.class); 148224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta invoke(setHomeAsUp, mWindowDecorActionBar, homeAsUp); 149224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 150224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 151224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 152224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Override 153224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta public void createMenuPopup() { 154c77f9c76e4142db8dd76a28ad99b8f0395b82ebaDeepanshu Gupta // it's hard to add menus to appcompat's actionbar, since it'll use a lot of reflection. 155224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta // so we skip it for now. 156224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 157224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 158224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Nullable 159224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta private static Method getMethod(Class<?> owner, String name, Class<?>... parameterTypes) { 160224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta try { 161224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return owner == null ? null : owner.getMethod(name, parameterTypes); 162224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } catch (NoSuchMethodException e) { 163224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta e.printStackTrace(); 164224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 165224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return null; 166224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 167224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 168224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Nullable 169224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta private static Object invoke(Method method, Object owner, Object... args) { 170224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta try { 171224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return method == null ? null : method.invoke(owner, args); 172224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } catch (InvocationTargetException e) { 173224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta e.printStackTrace(); 174224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } catch (IllegalAccessException e) { 175224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta e.printStackTrace(); 176224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 177224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return null; 178224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 179224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta 180224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta // TODO: this is duplicated from FrameworkActionBarWrapper$WindowActionBarWrapper 181224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta @Nullable 182224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta private Drawable getDrawable(@NonNull String name, boolean isFramework) { 183224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta RenderResources res = mBridgeContext.getRenderResources(); 184224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta ResourceValue value = res.findResValue(name, isFramework); 185224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta value = res.resolveResValue(value); 186224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta if (value != null) { 187224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return ResourceHelper.getDrawable(value, mBridgeContext); 188224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 189224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta return null; 190224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta } 191224e931fed1220f175805fdec71a882649270aa7Deepanshu Gupta} 192