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