1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.layoutlib.bridge.bars; 18 19 import com.android.ide.common.rendering.api.ActionBarCallback; 20 import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle; 21 import com.android.ide.common.rendering.api.RenderResources; 22 import com.android.ide.common.rendering.api.ResourceValue; 23 import com.android.ide.common.rendering.api.SessionParams; 24 import com.android.layoutlib.bridge.MockView; 25 import com.android.layoutlib.bridge.android.BridgeContext; 26 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.view.ViewGroup.LayoutParams; 33 import android.widget.FrameLayout; 34 import android.widget.RelativeLayout; 35 36 /** 37 * An abstraction over two implementations of the ActionBar - framework and appcompat. 38 */ 39 public abstract class BridgeActionBar { 40 // Store a reference to the context so that we don't have to cast it repeatedly. 41 @NonNull protected final BridgeContext mBridgeContext; 42 @NonNull protected final SessionParams mParams; 43 // A Layout that contains the inflated action bar. The menu popup is added to this layout. 44 @Nullable protected final ViewGroup mEnclosingLayout; 45 46 private final View mDecorContent; 47 private final ActionBarCallback mCallback; 48 49 @SuppressWarnings("NullableProblems") // Should be initialized by subclasses. 50 @NonNull private FrameLayout mContentRoot; 51 BridgeActionBar(@onNull BridgeContext context, @NonNull SessionParams params)52 public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params) { 53 mBridgeContext = context; 54 mParams = params; 55 mCallback = params.getLayoutlibCallback().getActionBarCallback(); 56 ResourceValue layoutName = getLayoutResource(context); 57 58 int layoutId = 0; 59 if (layoutName == null) { 60 assert false : "Unable to find the layout for Action Bar."; 61 } 62 else { 63 if (layoutName.isFramework()) { 64 layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(), 65 layoutName.getName(), 0); 66 } else { 67 layoutId = context.getProjectResourceValue(layoutName.getResourceType(), 68 layoutName.getName(), 0); 69 70 } 71 } 72 if (layoutId == 0) { 73 assert false : String.format("Unable to resolve attribute \"%1$s\" of type \"%2$s\"", 74 layoutName.getName(), layoutName.getResourceType()); 75 mDecorContent = new MockView(context); 76 mEnclosingLayout = null; 77 } 78 else { 79 if (mCallback.isOverflowPopupNeeded()) { 80 // Create a RelativeLayout around the action bar, to which the overflow popup may be 81 // added. 82 mEnclosingLayout = new RelativeLayout(mBridgeContext); 83 setMatchParent(mEnclosingLayout); 84 } else { 85 mEnclosingLayout = null; 86 } 87 88 // Inflate action bar layout. 89 mDecorContent = getInflater(context).inflate(layoutId, mEnclosingLayout, 90 mEnclosingLayout != null); 91 } 92 } 93 94 /** 95 * Returns the Layout Resource that should be used to inflate the action bar. This layout 96 * should cover the complete screen, and have a FrameLayout included, where the content will 97 * be inflated. 98 */ getLayoutResource(BridgeContext context)99 protected abstract ResourceValue getLayoutResource(BridgeContext context); 100 getInflater(BridgeContext context)101 protected LayoutInflater getInflater(BridgeContext context) { 102 return LayoutInflater.from(context); 103 } 104 setContentRoot(@onNull FrameLayout contentRoot)105 protected void setContentRoot(@NonNull FrameLayout contentRoot) { 106 mContentRoot = contentRoot; 107 } 108 109 @NonNull getContentRoot()110 public FrameLayout getContentRoot() { 111 return mContentRoot; 112 } 113 114 /** 115 * Returns the view inflated. This should contain both the ActionBar and the app content in it. 116 */ getDecorContent()117 protected View getDecorContent() { 118 return mDecorContent; 119 } 120 121 /** Setup things like the title, subtitle, icon etc. */ setupActionBar()122 protected void setupActionBar() { 123 setTitle(); 124 setSutTitle(); 125 setIcon(); 126 setHomeAsUp(mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP); 127 } 128 setTitle(CharSequence title)129 protected abstract void setTitle(CharSequence title); setSubtitle(CharSequence subtitle)130 protected abstract void setSubtitle(CharSequence subtitle); setIcon(String icon)131 protected abstract void setIcon(String icon); setHomeAsUp(boolean homeAsUp)132 protected abstract void setHomeAsUp(boolean homeAsUp); 133 setTitle()134 private void setTitle() { 135 RenderResources res = mBridgeContext.getRenderResources(); 136 137 String title = mParams.getAppLabel(); 138 ResourceValue titleValue = res.findResValue(title, false); 139 if (titleValue != null && titleValue.getValue() != null) { 140 setTitle(titleValue.getValue()); 141 } else { 142 setTitle(title); 143 } 144 } 145 setSutTitle()146 private void setSutTitle() { 147 String subTitle = mCallback.getSubTitle(); 148 if (subTitle != null) { 149 setSubtitle(subTitle); 150 } 151 } 152 setIcon()153 private void setIcon() { 154 String appIcon = mParams.getAppIcon(); 155 if (appIcon != null) { 156 setIcon(appIcon); 157 } 158 } 159 createMenuPopup()160 public abstract void createMenuPopup(); 161 162 /** 163 * The root view that represents the action bar and possibly the content included in it. 164 */ getRootView()165 public View getRootView() { 166 return mEnclosingLayout == null ? mDecorContent : mEnclosingLayout; 167 } 168 getCallBack()169 public ActionBarCallback getCallBack() { 170 return mCallback; 171 } 172 setMatchParent(View view)173 protected static void setMatchParent(View view) { 174 view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 175 LayoutParams.MATCH_PARENT)); 176 } 177 } 178