1/* 2 * Copyright (C) 2014 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 android.support.v7.app; 18 19import android.app.Activity; 20import android.app.Dialog; 21import android.content.Context; 22import android.content.res.Configuration; 23import android.os.Build; 24import android.os.Bundle; 25import android.support.annotation.IntDef; 26import android.support.annotation.LayoutRes; 27import android.support.annotation.NonNull; 28import android.support.v4.app.FragmentActivity; 29import android.support.v4.view.WindowCompat; 30import android.support.v7.appcompat.R; 31import android.support.v7.view.ActionMode; 32import android.support.v7.widget.Toolbar; 33import android.util.AttributeSet; 34import android.view.MenuInflater; 35import android.view.View; 36import android.view.ViewGroup; 37import android.view.Window; 38 39import java.lang.annotation.Retention; 40import java.lang.annotation.RetentionPolicy; 41 42/** 43 * This class represents a delegate which you can use to extend AppCompat's support to any 44 * {@link android.app.Activity}. 45 * <p> 46 * When using an {@link AppCompatDelegate}, you should any methods exposed in it rather than the 47 * {@link android.app.Activity} method of the same name. This applies to: 48 * <ul> 49 * <li>{@link #addContentView(android.view.View, android.view.ViewGroup.LayoutParams)}</li> 50 * <li>{@link #setContentView(int)}</li> 51 * <li>{@link #setContentView(android.view.View)}</li> 52 * <li>{@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}</li> 53 * <li>{@link #requestWindowFeature(int)}</li> 54 * <li>{@link #invalidateOptionsMenu()}</li> 55 * <li>{@link #startSupportActionMode(android.support.v7.view.ActionMode.Callback)}</li> 56 * <li>{@link #setSupportActionBar(android.support.v7.widget.Toolbar)}</li> 57 * <li>{@link #getSupportActionBar()}</li> 58 * <li>{@link #getMenuInflater()}</li> 59 * </ul> 60 * There also some Activity lifecycle methods which should be proxied to the delegate: 61 * <ul> 62 * <li>{@link #onCreate(android.os.Bundle)}</li> 63 * <li>{@link #onPostCreate(android.os.Bundle)}</li> 64 * <li>{@link #onConfigurationChanged(android.content.res.Configuration)}</li> 65 * <li>{@link #setTitle(CharSequence)}</li> 66 * <li>{@link #onStop()}</li> 67 * <li>{@link #onDestroy()}</li> 68 * </ul> 69 * <p> 70 * An {@link Activity} can only be linked with one {@link AppCompatDelegate} instance, 71 * so the instance returned from {@link #create(Activity, AppCompatCallback)} should be kept 72 * until the Activity is destroyed. 73 */ 74public abstract class AppCompatDelegate { 75 76 static final String TAG = "AppCompatDelegate"; 77 78 /** 79 * Flag for enabling the support Action Bar. 80 * 81 * <p>This is enabled by default for some devices. The Action Bar replaces the title bar and 82 * provides an alternate location for an on-screen menu button on some devices. 83 */ 84 public static final int FEATURE_SUPPORT_ACTION_BAR = 100 + WindowCompat.FEATURE_ACTION_BAR; 85 86 /** 87 * Flag for requesting an support Action Bar that overlays window content. 88 * Normally an Action Bar will sit in the space above window content, but if this 89 * feature is requested along with {@link #FEATURE_SUPPORT_ACTION_BAR} it will be layered over 90 * the window content itself. This is useful if you would like your app to have more control 91 * over how the Action Bar is displayed, such as letting application content scroll beneath 92 * an Action Bar with a transparent background or otherwise displaying a transparent/translucent 93 * Action Bar over application content. 94 * 95 * <p>This mode is especially useful with {@code View.SYSTEM_UI_FLAG_FULLSCREEN}, which allows 96 * you to seamlessly hide the action bar in conjunction with other screen decorations. 97 * When an ActionBar is in this mode it will adjust the insets provided to 98 * {@link View#fitSystemWindows(android.graphics.Rect) View.fitSystemWindows(Rect)} 99 * to include the content covered by the action bar, so you can do layout within 100 * that space. 101 */ 102 public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 103 100 + WindowCompat.FEATURE_ACTION_BAR_OVERLAY; 104 105 /** 106 * Flag for specifying the behavior of action modes when an Action Bar is not present. 107 * If overlay is enabled, the action mode UI will be allowed to cover existing window content. 108 */ 109 public static final int FEATURE_ACTION_MODE_OVERLAY = WindowCompat.FEATURE_ACTION_MODE_OVERLAY; 110 111 /** 112 * Create a {@link android.support.v7.app.AppCompatDelegate} to use with {@code activity}. 113 * 114 * @param callback An optional callback for AppCompat specific events 115 */ 116 public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) { 117 return create(activity, activity.getWindow(), callback); 118 } 119 120 /** 121 * Create a {@link android.support.v7.app.AppCompatDelegate} to use with {@code dialog}. 122 * 123 * @param callback An optional callback for AppCompat specific events 124 */ 125 public static AppCompatDelegate create(Dialog dialog, AppCompatCallback callback) { 126 return create(dialog.getContext(), dialog.getWindow(), callback); 127 } 128 129 private static AppCompatDelegate create(Context context, Window window, 130 AppCompatCallback callback) { 131 final int sdk = Build.VERSION.SDK_INT; 132 if (sdk >= 23) { 133 return new AppCompatDelegateImplV23(context, window, callback); 134 } else if (sdk >= 14) { 135 return new AppCompatDelegateImplV14(context, window, callback); 136 } else if (sdk >= 11) { 137 return new AppCompatDelegateImplV11(context, window, callback); 138 } else { 139 return new AppCompatDelegateImplV7(context, window, callback); 140 } 141 } 142 143 /** 144 * Private constructor 145 */ 146 AppCompatDelegate() {} 147 148 /** 149 * Support library version of {@link Activity#getActionBar}. 150 * 151 * @return AppCompat's action bar, or null if it does not have one. 152 */ 153 public abstract ActionBar getSupportActionBar(); 154 155 /** 156 * Set a {@link Toolbar} to act as the {@link ActionBar} for this delegate. 157 * 158 * <p>When set to a non-null value the {@link #getSupportActionBar()} ()} method will return 159 * an {@link ActionBar} object that can be used to control the given toolbar as if it were 160 * a traditional window decor action bar. The toolbar's menu will be populated with the 161 * Activity's options menu and the navigation button will be wired through the standard 162 * {@link android.R.id#home home} menu select action.</p> 163 * 164 * <p>In order to use a Toolbar within the Activity's window content the application 165 * must not request the window feature 166 * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p> 167 * 168 * @param toolbar Toolbar to set as the Activity's action bar 169 */ 170 public abstract void setSupportActionBar(Toolbar toolbar); 171 172 /** 173 * Return the value of this call from your {@link Activity#getMenuInflater()} 174 */ 175 public abstract MenuInflater getMenuInflater(); 176 177 /** 178 * Should be called from {@link Activity#onCreate Activity.onCreate()} 179 */ 180 public abstract void onCreate(Bundle savedInstanceState); 181 182 /** 183 * Should be called from {@link Activity#onPostCreate(android.os.Bundle)} 184 */ 185 public abstract void onPostCreate(Bundle savedInstanceState); 186 187 /** 188 * Should be called from 189 * {@link Activity#onConfigurationChanged} 190 */ 191 public abstract void onConfigurationChanged(Configuration newConfig); 192 193 /** 194 * Should be called from {@link Activity#onStop Activity.onStop()} 195 */ 196 public abstract void onStop(); 197 198 /** 199 * Should be called from {@link Activity#onPostResume()} 200 */ 201 public abstract void onPostResume(); 202 203 /** 204 * Should be called instead of {@link Activity#setContentView(android.view.View)}} 205 */ 206 public abstract void setContentView(View v); 207 208 /** 209 * Should be called instead of {@link Activity#setContentView(int)}} 210 */ 211 public abstract void setContentView(@LayoutRes int resId); 212 213 /** 214 * Should be called instead of 215 * {@link Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}} 216 */ 217 public abstract void setContentView(View v, ViewGroup.LayoutParams lp); 218 219 /** 220 * Should be called instead of 221 * {@link Activity#addContentView(android.view.View, android.view.ViewGroup.LayoutParams)}} 222 */ 223 public abstract void addContentView(View v, ViewGroup.LayoutParams lp); 224 225 /** 226 * Should be called from {@link Activity#onTitleChanged(CharSequence, int)}} 227 */ 228 public abstract void setTitle(CharSequence title); 229 230 /** 231 * Should be called from {@link Activity#invalidateOptionsMenu()}} or 232 * {@link FragmentActivity#supportInvalidateOptionsMenu()}. 233 */ 234 public abstract void invalidateOptionsMenu(); 235 236 /** 237 * Should be called from {@link Activity#onDestroy()} 238 */ 239 public abstract void onDestroy(); 240 241 /** 242 * Returns an {@link ActionBarDrawerToggle.Delegate} which can be returned from your Activity 243 * if it implements {@link ActionBarDrawerToggle.DelegateProvider}. 244 */ 245 public abstract ActionBarDrawerToggle.Delegate getDrawerToggleDelegate(); 246 247 /** 248 * Enable extended window features. This should be called instead of 249 * {@link android.app.Activity#requestWindowFeature(int)} or 250 * {@link android.view.Window#requestFeature getWindow().requestFeature()}. 251 * 252 * @param featureId The desired feature as defined in {@link android.view.Window}. 253 * @return Returns true if the requested feature is supported and now 254 * enabled. 255 */ 256 public abstract boolean requestWindowFeature(int featureId); 257 258 /** 259 * Query for the availability of a certain feature. 260 * 261 * <p>This should be called instead of {@link android.view.Window#hasFeature(int)}.</p> 262 * 263 * @param featureId The feature ID to check 264 * @return true if the feature is enabled, false otherwise. 265 */ 266 public abstract boolean hasWindowFeature(int featureId); 267 268 /** 269 * Start an action mode. 270 * 271 * @param callback Callback that will manage lifecycle events for this context mode 272 * @return The ContextMode that was started, or null if it was canceled 273 */ 274 public abstract ActionMode startSupportActionMode(ActionMode.Callback callback); 275 276 /** 277 * Installs AppCompat's {@link android.view.LayoutInflater} Factory so that it can replace 278 * the framework widgets with compatible tinted versions. This should be called before 279 * {@code super.onCreate()} as so: 280 * <pre class="prettyprint"> 281 * protected void onCreate(Bundle savedInstanceState) { 282 * getDelegate().installViewFactory(); 283 * super.onCreate(savedInstanceState); 284 * getDelegate().onCreate(savedInstanceState); 285 * 286 * // ... 287 * } 288 * </pre> 289 * If you are using your own {@link android.view.LayoutInflater.Factory Factory} or 290 * {@link android.view.LayoutInflater.Factory2 Factory2} then you can omit this call, and instead call 291 * {@link #createView(android.view.View, String, android.content.Context, android.util.AttributeSet)} 292 * from your factory to return any compatible widgets. 293 */ 294 public abstract void installViewFactory(); 295 296 /** 297 * This should be called from a 298 * {@link android.support.v4.view.LayoutInflaterFactory LayoutInflaterFactory} in order 299 * to return tint-aware widgets. 300 * <p> 301 * This is only needed if you are using your own 302 * {@link android.view.LayoutInflater LayoutInflater} factory, and have therefore not 303 * installed the default factory via {@link #installViewFactory()}. 304 */ 305 public abstract View createView(View parent, String name, @NonNull Context context, 306 @NonNull AttributeSet attrs); 307 308 /** 309 * Whether AppCompat handles any native action modes itself. 310 * <p>This methods only takes effect on 311 * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and above. 312 * 313 * @param enabled whether AppCompat should handle native action modes. 314 */ 315 public abstract void setHandleNativeActionModesEnabled(boolean enabled); 316 317 /** 318 * Returns whether AppCompat handles any native action modes itself. 319 * 320 * @return true if AppCompat should handle native action modes. 321 */ 322 public abstract boolean isHandleNativeActionModesEnabled(); 323 324} 325