1 /* 2 * Copyright (C) 2016 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 package android.support.car.app; 17 18 import android.content.Context; 19 import android.content.Intent; 20 import android.content.res.Configuration; 21 import android.content.res.Resources; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.Parcelable; 26 import android.support.annotation.NonNull; 27 import android.support.annotation.Nullable; 28 import android.support.car.Car; 29 import android.support.v4.app.Fragment; 30 import android.support.v4.app.FragmentActivity; 31 import android.support.v4.app.FragmentController; 32 import android.support.v4.app.FragmentHostCallback; 33 import android.support.v4.app.FragmentManager; 34 import android.support.v4.app.LoaderManager; 35 import android.support.v4.util.SimpleArrayMap; 36 import android.util.AttributeSet; 37 import android.util.Log; 38 import android.view.LayoutInflater; 39 import android.view.Menu; 40 import android.view.View; 41 import android.view.ViewGroup; 42 import android.view.Window; 43 import java.io.FileDescriptor; 44 import java.io.PrintWriter; 45 import java.util.ArrayList; 46 import java.util.List; 47 48 /** 49 * Base class for CarActivities that want to use the support-based Fragment and Loader APIs. 50 * <p/> 51 * This is mostly a copy of {@link android.support.v4.app.FragmentActivity} retro fitted for use 52 * with {@link CarActivity}. 53 * 54 * @hide 55 */ 56 public class CarFragmentActivity extends CarActivity implements 57 CarActivity.RequestPermissionsRequestCodeValidator { 58 CarFragmentActivity(Proxy proxy, Context context, Car car)59 public CarFragmentActivity(Proxy proxy, Context context, Car car) { 60 super(proxy, context, car); 61 } 62 63 private static final String TAG = "CarFragmentActivity"; 64 65 static final String FRAGMENTS_TAG = "android:support:car:fragments"; 66 67 // This is the SDK API version of Honeycomb (3.0). 68 private static final int HONEYCOMB = 11; 69 70 static final int MSG_REALLY_STOPPED = 1; 71 static final int MSG_RESUME_PENDING = 2; 72 73 final Handler mHandler = new Handler() { 74 @Override 75 public void handleMessage(Message msg) { 76 switch (msg.what) { 77 case MSG_REALLY_STOPPED: 78 if (mStopped) { 79 doReallyStop(false); 80 } 81 break; 82 case MSG_RESUME_PENDING: 83 onResumeFragments(); 84 mFragments.execPendingActions(); 85 break; 86 default: 87 super.handleMessage(msg); 88 } 89 } 90 91 }; 92 final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); 93 94 boolean mCreated; 95 boolean mResumed; 96 boolean mStopped; 97 boolean mReallyStopped; 98 boolean mRetaining; 99 100 boolean mRequestedPermissionsFromFragment; 101 102 static final class NonConfigurationInstances { 103 Object custom; 104 List<Fragment> fragments; 105 SimpleArrayMap<String, LoaderManager> loaders; 106 } 107 setContentFragment(Fragment fragment, int containerId)108 public void setContentFragment(Fragment fragment, int containerId) { 109 getSupportFragmentManager().beginTransaction() 110 .replace(containerId, fragment) 111 .commit(); 112 } 113 114 // ------------------------------------------------------------------------ 115 // HOOKS INTO ACTIVITY 116 // ------------------------------------------------------------------------ 117 118 /** 119 * See {@link FragmentActivity#onActivityResult(int, int, Intent)} 120 */ 121 @Override onActivityResult(int requestCode, int resultCode, Intent data)122 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 123 mFragments.noteStateNotSaved(); 124 int index = requestCode>>16; 125 if (index > 0) { 126 index--; 127 final int activeFragmentsCount = mFragments.getActiveFragmentsCount(); 128 if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) { 129 Log.w(TAG, "Activity result fragment index out of range: 0x" 130 + Integer.toHexString(requestCode)); 131 return; 132 } 133 final List<Fragment> activeFragments = 134 mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount)); 135 Fragment frag = activeFragments.get(index); 136 if (frag == null) { 137 Log.w(TAG, "Activity result no fragment exists for index: 0x" 138 + Integer.toHexString(requestCode)); 139 } else { 140 frag.onActivityResult(requestCode&0xffff, resultCode, data); 141 } 142 return; 143 } 144 145 super.onActivityResult(requestCode, resultCode, data); 146 } 147 148 /** 149 * See {@link FragmentActivity#startActivityFromFragment(android.app.Fragment, Intent, int)} 150 */ startActivityFromFragment(Fragment fragment, Intent intent, int requestCode)151 public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { 152 if (requestCode == -1) { 153 startActivityForResult(intent, -1); 154 return; 155 } 156 if ((requestCode&0xffff0000) != 0) { 157 throw new IllegalArgumentException("Can only use lower 16 bits for requestCode"); 158 } 159 super.startActivityForResult(intent, 160 ((getFragmentIndex(fragment)+1)<<16) + (requestCode&0xffff)); 161 } 162 163 /** 164 * See {@link FragmentActivity#startActivityForResult(Intent, int)} 165 */ 166 @Override startActivityForResult(Intent intent, int requestCode)167 public void startActivityForResult(Intent intent, int requestCode) { 168 if (requestCode != -1 && (requestCode&0xffff0000) != 0) { 169 throw new IllegalArgumentException("Can only use lower 16 bits for requestCode"); 170 } 171 super.startActivityForResult(intent, requestCode); 172 } 173 174 /** 175 * See {@link FragmentActivity#onBackPressed()} 176 */ 177 @Override onBackPressed()178 public void onBackPressed() { 179 if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) { 180 supportFinishAfterTransition(); 181 } 182 } 183 184 /** 185 * See {@link FragmentActivity#supportFinishAfterTransition()} 186 */ supportFinishAfterTransition()187 public void supportFinishAfterTransition() { 188 super.finishAfterTransition(); 189 } 190 191 /** 192 * See {@link FragmentActivity#onConfigurationChanged(Configuration)} 193 */ 194 @Override onConfigurationChanged(Configuration newConfig)195 public void onConfigurationChanged(Configuration newConfig) { 196 super.onConfigurationChanged(newConfig); 197 mFragments.dispatchConfigurationChanged(newConfig); 198 } 199 200 /** 201 * Perform initialization of all fragments and loaders. 202 */ 203 @SuppressWarnings("deprecation") 204 @Override onCreate(@ullable Bundle savedInstanceState)205 protected void onCreate(@Nullable Bundle savedInstanceState) { 206 mFragments.attachHost(null /*parent*/); 207 208 super.onCreate(savedInstanceState); 209 210 NonConfigurationInstances nc = 211 (NonConfigurationInstances) getLastNonConfigurationInstance(); 212 if (nc != null) { 213 mFragments.restoreLoaderNonConfig(nc.loaders); 214 } 215 if (savedInstanceState != null) { 216 Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); 217 mFragments.restoreAllState(p, nc != null ? nc.fragments : null); 218 } 219 mFragments.dispatchCreate(); 220 } 221 222 /** 223 * See {@link FragmentActivity#onCreatePanelMenu(int, Menu)} 224 */ 225 @Override onCreatePanelMenu(int featureId, Menu menu)226 public boolean onCreatePanelMenu(int featureId, Menu menu) { 227 if (featureId == Window.FEATURE_OPTIONS_PANEL && getMenuInflater() != null) { 228 boolean show = super.onCreatePanelMenu(featureId, menu); 229 show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater()); 230 if (android.os.Build.VERSION.SDK_INT >= HONEYCOMB) { 231 return show; 232 } 233 // Prior to Honeycomb, the framework can't invalidate the options 234 // menu, so we must always say we have one in case the app later 235 // invalidates it and needs to have it shown. 236 return true; 237 } 238 return super.onCreatePanelMenu(featureId, menu); 239 } 240 241 /** 242 * See 243 * {@link FragmentActivity#dispatchFragmentsOnCreateView(View, String, Context, AttributeSet)} 244 */ dispatchFragmentsOnCreateView(View parent, String name, Context context, AttributeSet attrs)245 final View dispatchFragmentsOnCreateView(View parent, String name, Context context, 246 AttributeSet attrs) { 247 return mFragments.onCreateView(parent, name, context, attrs); 248 } 249 250 @Override onCreateView(View parent, String name, Context context, AttributeSet attrs)251 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { 252 if (!"fragment".equals(name)) { 253 return super.onCreateView(parent, name, context, attrs); 254 } 255 256 final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs); 257 if (v == null) { 258 return super.onCreateView(parent, name, context, attrs); 259 } 260 return v; 261 } 262 263 /** 264 * See {@link FragmentActivity#onDestroy()} 265 */ 266 @Override onDestroy()267 protected void onDestroy() { 268 super.onDestroy(); 269 270 doReallyStop(false); 271 272 mFragments.dispatchDestroy(); 273 mFragments.doLoaderDestroy(); 274 } 275 276 /** 277 * See {@link FragmentActivity#onLowMemory()} 278 */ 279 @Override onLowMemory()280 public void onLowMemory() { 281 mFragments.dispatchLowMemory(); 282 } 283 284 /** 285 * See {@link FragmentActivity#onPause()} 286 */ 287 @Override onPause()288 protected void onPause() { 289 super.onPause(); 290 mResumed = false; 291 if (mHandler.hasMessages(MSG_RESUME_PENDING)) { 292 mHandler.removeMessages(MSG_RESUME_PENDING); 293 onResumeFragments(); 294 } 295 mFragments.dispatchPause(); 296 } 297 298 /** 299 * See {@link FragmentActivity#onNewIntent(Intent)} 300 */ 301 @Override onNewIntent(Intent intent)302 protected void onNewIntent(Intent intent) { 303 super.onNewIntent(intent); 304 mFragments.noteStateNotSaved(); 305 } 306 307 /** 308 * See {@link FragmentActivity#onStateNotSaved()} 309 */ onStateNotSaved()310 public void onStateNotSaved() { 311 mFragments.noteStateNotSaved(); 312 } 313 314 /** 315 * See {@link FragmentActivity#onResume()} 316 */ 317 @Override onResume()318 protected void onResume() { 319 super.onResume(); 320 mHandler.sendEmptyMessage(MSG_RESUME_PENDING); 321 mResumed = true; 322 mFragments.execPendingActions(); 323 } 324 325 /** 326 * See {@link FragmentActivity#onPostResume()} 327 */ 328 @Override onPostResume()329 protected void onPostResume() { 330 super.onPostResume(); 331 mHandler.removeMessages(MSG_RESUME_PENDING); 332 onResumeFragments(); 333 mFragments.execPendingActions(); 334 } 335 336 /** 337 * See {@link FragmentActivity#onResumeFragments()} 338 */ onResumeFragments()339 protected void onResumeFragments() { 340 mFragments.dispatchResume(); 341 } 342 343 /** 344 * See {@link FragmentActivity#onRetainNonConfigurationInstance()} 345 */ 346 @Override onRetainNonConfigurationInstance()347 public final Object onRetainNonConfigurationInstance() { 348 if (mStopped) { 349 doReallyStop(true); 350 } 351 352 Object custom = onRetainCustomNonConfigurationInstance(); 353 354 List<Fragment> fragments = mFragments.retainNonConfig(); 355 SimpleArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig(); 356 357 if (fragments == null && loaders == null && custom == null) { 358 return null; 359 } 360 361 NonConfigurationInstances nci = new NonConfigurationInstances(); 362 nci.custom = custom; 363 nci.fragments = fragments; 364 nci.loaders = loaders; 365 return nci; 366 } 367 368 /** 369 * See {@link FragmentActivity#onSaveInstanceState(Bundle)} 370 */ 371 @Override onSaveInstanceState(Bundle outState)372 protected void onSaveInstanceState(Bundle outState) { 373 super.onSaveInstanceState(outState); 374 Parcelable p = mFragments.saveAllState(); 375 if (p != null) { 376 outState.putParcelable(FRAGMENTS_TAG, p); 377 } 378 } 379 380 /** 381 * See {@link FragmentActivity#onStart()} 382 */ 383 @Override onStart()384 protected void onStart() { 385 super.onStart(); 386 387 mStopped = false; 388 mReallyStopped = false; 389 mHandler.removeMessages(MSG_REALLY_STOPPED); 390 391 if (!mCreated) { 392 mCreated = true; 393 mFragments.dispatchActivityCreated(); 394 } 395 396 mFragments.noteStateNotSaved(); 397 mFragments.execPendingActions(); 398 399 mFragments.doLoaderStart(); 400 401 // NOTE: HC onStart goes here. 402 403 mFragments.dispatchStart(); 404 mFragments.reportLoaderStart(); 405 } 406 407 /** 408 * See {@link FragmentActivity#onStop()} 409 */ 410 @Override onStop()411 protected void onStop() { 412 super.onStop(); 413 414 mStopped = true; 415 mHandler.sendEmptyMessage(MSG_REALLY_STOPPED); 416 417 mFragments.dispatchStop(); 418 } 419 420 // ------------------------------------------------------------------------ 421 // NEW METHODS 422 // ------------------------------------------------------------------------ 423 424 /** 425 * See {@link FragmentActivity#onRetainNonConfigurationInstance()} 426 */ onRetainCustomNonConfigurationInstance()427 public Object onRetainCustomNonConfigurationInstance() { 428 return null; 429 } 430 431 /** 432 * See {@link FragmentActivity#getLastNonConfigurationInstance()} 433 */ 434 @SuppressWarnings("deprecation") getLastCustomNonConfigurationInstance()435 public Object getLastCustomNonConfigurationInstance() { 436 NonConfigurationInstances nc = (NonConfigurationInstances) 437 getLastNonConfigurationInstance(); 438 return nc != null ? nc.custom : null; 439 } 440 441 /** 442 * See {@link FragmentActivity#dump(String, FileDescriptor, PrintWriter, String[])} 443 */ dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)444 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 445 if (android.os.Build.VERSION.SDK_INT >= HONEYCOMB) { 446 // XXX This can only work if we can call the super-class impl. :/ 447 //ActivityCompatHoneycomb.dump(this, prefix, fd, writer, args); 448 } 449 writer.print(prefix); writer.print("Local FragmentActivity "); 450 writer.print(Integer.toHexString(System.identityHashCode(this))); 451 writer.println(" State:"); 452 String innerPrefix = prefix + " "; 453 writer.print(innerPrefix); writer.print("mCreated="); 454 writer.print(mCreated); writer.print("mResumed="); 455 writer.print(mResumed); writer.print(" mStopped="); 456 writer.print(mStopped); writer.print(" mReallyStopped="); 457 writer.println(mReallyStopped); 458 mFragments.dumpLoaders(innerPrefix, fd, writer, args); 459 mFragments.getSupportFragmentManager().dump(prefix, fd, writer, args); 460 writer.print(prefix); writer.println("View Hierarchy:"); 461 dumpViewHierarchy(prefix + " ", writer, getWindow().getDecorView()); 462 } 463 viewToString(View view)464 private static String viewToString(View view) { 465 StringBuilder out = new StringBuilder(128); 466 out.append(view.getClass().getName()); 467 out.append('{'); 468 out.append(Integer.toHexString(System.identityHashCode(view))); 469 out.append(' '); 470 switch (view.getVisibility()) { 471 case View.VISIBLE: out.append('V'); break; 472 case View.INVISIBLE: out.append('I'); break; 473 case View.GONE: out.append('G'); break; 474 default: out.append('.'); break; 475 } 476 out.append(view.isFocusable() ? 'F' : '.'); 477 out.append(view.isEnabled() ? 'E' : '.'); 478 out.append(view.willNotDraw() ? '.' : 'D'); 479 out.append(view.isHorizontalScrollBarEnabled()? 'H' : '.'); 480 out.append(view.isVerticalScrollBarEnabled() ? 'V' : '.'); 481 out.append(view.isClickable() ? 'C' : '.'); 482 out.append(view.isLongClickable() ? 'L' : '.'); 483 out.append(' '); 484 out.append(view.isFocused() ? 'F' : '.'); 485 out.append(view.isSelected() ? 'S' : '.'); 486 out.append(view.isPressed() ? 'P' : '.'); 487 out.append(' '); 488 out.append(view.getLeft()); 489 out.append(','); 490 out.append(view.getTop()); 491 out.append('-'); 492 out.append(view.getRight()); 493 out.append(','); 494 out.append(view.getBottom()); 495 final int id = view.getId(); 496 if (id != View.NO_ID) { 497 out.append(" #"); 498 out.append(Integer.toHexString(id)); 499 final Resources r = view.getResources(); 500 if (id != 0 && r != null) { 501 try { 502 String pkgname; 503 switch (id&0xff000000) { 504 case 0x7f000000: 505 pkgname="app"; 506 break; 507 case 0x01000000: 508 pkgname="android"; 509 break; 510 default: 511 pkgname = r.getResourcePackageName(id); 512 break; 513 } 514 String typename = r.getResourceTypeName(id); 515 String entryname = r.getResourceEntryName(id); 516 out.append(" "); 517 out.append(pkgname); 518 out.append(":"); 519 out.append(typename); 520 out.append("/"); 521 out.append(entryname); 522 } catch (Resources.NotFoundException e) { 523 } 524 } 525 } 526 out.append("}"); 527 return out.toString(); 528 } 529 dumpViewHierarchy(String prefix, PrintWriter writer, View view)530 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) { 531 writer.print(prefix); 532 if (view == null) { 533 writer.println("null"); 534 return; 535 } 536 writer.println(viewToString(view)); 537 if (!(view instanceof ViewGroup)) { 538 return; 539 } 540 ViewGroup grp = (ViewGroup)view; 541 final int N = grp.getChildCount(); 542 if (N <= 0) { 543 return; 544 } 545 prefix = prefix + " "; 546 for (int i=0; i<N; i++) { 547 dumpViewHierarchy(prefix, writer, grp.getChildAt(i)); 548 } 549 } 550 doReallyStop(boolean retaining)551 void doReallyStop(boolean retaining) { 552 if (!mReallyStopped) { 553 mReallyStopped = true; 554 mRetaining = retaining; 555 mHandler.removeMessages(MSG_REALLY_STOPPED); 556 onReallyStop(); 557 } 558 } 559 560 /** 561 * Pre-HC, we didn't have a way to determine whether an activity was 562 * being stopped for a config change or not until we saw 563 * onRetainNonConfigurationInstance() called after onStop(). However 564 * we need to know this, to know whether to retain fragments. This will 565 * tell us what we need to know. 566 */ onReallyStop()567 void onReallyStop() { 568 mFragments.doLoaderStop(mRetaining); 569 570 mFragments.dispatchReallyStop(); 571 } 572 573 // ------------------------------------------------------------------------ 574 // FRAGMENT SUPPORT 575 // ------------------------------------------------------------------------ 576 577 /** 578 * Returns the index of a fragment inside {@link #mFragments}. 579 * 580 * This is a workaround for getting {@link android.support.v4.app.Fragment}'s internal index, 581 * which is package visible. 582 */ 583 @SuppressWarnings("ReferenceEquality") getFragmentIndex(Fragment f)584 private int getFragmentIndex(Fragment f) { 585 List<Fragment> fragments = mFragments.getActiveFragments(null); 586 int index = 0; 587 boolean found = false; 588 for (Fragment frag : fragments) { 589 if (frag == f) { 590 found = true; 591 break; 592 } 593 index++; 594 } 595 if (found) { 596 return index; 597 } 598 return -1; 599 } 600 601 @Override validateRequestPermissionsRequestCode(int requestCode)602 public final void validateRequestPermissionsRequestCode(int requestCode) { 603 // We use 8 bits of the request code to encode the fragment id when 604 // requesting permissions from a fragment. Hence, requestPermissions() 605 // should validate the code against that but we cannot override it as 606 // we can not then call super and also the ActivityCompat would call 607 // back to this override. To handle this we use dependency inversion 608 // where we are the validator of request codes when requesting 609 // permissions in ActivityCompat. 610 if (mRequestedPermissionsFromFragment) { 611 mRequestedPermissionsFromFragment = false; 612 } else if ((requestCode & 0xffffff00) != 0) { 613 throw new IllegalArgumentException("Can only use lower 8 bits for requestCode"); 614 } 615 } 616 617 /** 618 * See {@link FragmentActivity#onRequestPermissionsResult(int, String[], int[])} 619 */ 620 @Override onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)621 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 622 @NonNull int[] grantResults) { 623 int index = (requestCode>>8)&0xff; 624 if (index != 0) { 625 index--; 626 final int activeFragmentsCount = mFragments.getActiveFragmentsCount(); 627 if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) { 628 Log.w(TAG, "Activity result fragment index out of range: 0x" 629 + Integer.toHexString(requestCode)); 630 return; 631 } 632 final List<Fragment> activeFragments = 633 mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount)); 634 Fragment frag = activeFragments.get(index); 635 if (frag == null) { 636 Log.w(TAG, "Activity result no fragment exists for index: 0x" 637 + Integer.toHexString(requestCode)); 638 } else { 639 frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults); 640 } 641 } 642 } 643 644 /** 645 * Called by Fragment.requestPermissions() to implement its behavior. 646 */ requestPermissionsFromFragment(Fragment fragment, String[] permissions, int requestCode)647 private void requestPermissionsFromFragment(Fragment fragment, String[] permissions, 648 int requestCode) { 649 if (requestCode == -1) { 650 super.requestPermissions(permissions, requestCode); 651 return; 652 } 653 654 if ((requestCode&0xffffff00) != 0) { 655 throw new IllegalArgumentException("Can only use lower 8 bits for requestCode"); 656 } 657 mRequestedPermissionsFromFragment = true; 658 super.requestPermissions(permissions, 659 ((getFragmentIndex(fragment) + 1) << 8) + (requestCode & 0xff)); 660 } 661 662 /** 663 * See {@link FragmentActivity#getSupportFragmentManager()} 664 */ getSupportFragmentManager()665 public FragmentManager getSupportFragmentManager() { 666 return mFragments.getSupportFragmentManager(); 667 } 668 669 class HostCallbacks extends FragmentHostCallback<CarFragmentActivity> { HostCallbacks()670 public HostCallbacks() { 671 super(CarFragmentActivity.this.getContext(), mHandler, 0 /*window animation*/); 672 } 673 674 @Override onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)675 public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 676 CarFragmentActivity.this.dump(prefix, fd, writer, args); 677 } 678 679 @Override onShouldSaveFragmentState(Fragment fragment)680 public boolean onShouldSaveFragmentState(Fragment fragment) { 681 return !isFinishing(); 682 } 683 684 @Override onGetLayoutInflater()685 public LayoutInflater onGetLayoutInflater() { 686 return CarFragmentActivity.this.getLayoutInflater() 687 .cloneInContext(CarFragmentActivity.this.getContext()); 688 } 689 690 @Override onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode)691 public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { 692 CarFragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode); 693 } 694 695 @Override onRequestPermissionsFromFragment(@onNull Fragment fragment, @NonNull String[] permissions, int requestCode)696 public void onRequestPermissionsFromFragment(@NonNull Fragment fragment, 697 @NonNull String[] permissions, int requestCode) { 698 CarFragmentActivity.this.requestPermissionsFromFragment(fragment, 699 permissions, requestCode); 700 } 701 702 @Override onGetHost()703 public CarFragmentActivity onGetHost() { 704 return CarFragmentActivity.this; 705 } 706 707 @Override onHasWindowAnimations()708 public boolean onHasWindowAnimations() { 709 return getWindow() != null; 710 } 711 712 @Override onGetWindowAnimations()713 public int onGetWindowAnimations() { 714 final Window w = getWindow(); 715 return (w == null) ? 0 : w.getAttributes().windowAnimations; 716 } 717 718 @Nullable 719 @Override onFindViewById(int id)720 public View onFindViewById(int id) { 721 return CarFragmentActivity.this.findViewById(id); 722 } 723 724 @Override onHasView()725 public boolean onHasView() { 726 final Window w = getWindow(); 727 return (w != null && w.peekDecorView() != null); 728 } 729 } 730 } 731