知者何南 发表于 2024-8-6 10:16:33

Android 14 transtion 动画流程

1.接口

shell入口通过TransitionPlayerImpl与wm core 通信

   @BinderThread
    private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
      @Override
      public void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,
                SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)
                throws RemoteException {
            mMainExecutor.execute(() -> Transitions.this.onTransitionReady(
                  iBinder, transitionInfo, t, finishT));
      }

      @Override
      public void requestStartTransition(IBinder iBinder,
                TransitionRequestInfo request) throws RemoteException {
            mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
      }
    }
} 分为

1. requestStartTransition

2.onTransitionReady

两个阶段



1.requestStartTransition
wm services

new 一个动画放进mActiveSyncs中



04-23 18:43:25.195 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet s.mSyncId:6
04-23 18:43:25.195 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet s:com.android.server.wm.BLASTSyncEngine$SyncGroup@3ee8531
04-23 18:43:25.195 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet mActiveSyncs++++:0
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet mActiveSyncs---:1
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.startSyncSet(BLASTSyncEngine.java:327)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.startSyncSet(BLASTSyncEngine.java:305)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.Transition.startCollecting(Transition.java:422)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.moveToCollecting(TransitionController.java:222)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.moveToCollecting(TransitionController.java:203)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.createTransition(TransitionController.java:197)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.createTransition(TransitionController.java:179)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.findTaskToMoveToFront(ActivityTaskSupervisor.java:1577)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked(ActivityTaskManagerService.java:2497)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.startActivityFromRecents(ActivityTaskSupervisor.java:3034)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents(ActivityTaskManagerService.java:1918)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1434)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5840)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransactInternal(Binder.java:1348)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransact(Binder.java:1279)

new出来后调用task.mTransitionController.collect(task);

04-24 16:06:47.682 1815 2160 D jinyanmeiani: ChangeInfo 111111111 this:Task{fa5361 #69 type=standard A=10143:comgallery.home}
04-24 16:06:47.682 1815 2160 D jinyanmeiani: ChangeInfo 111111111 mVisible:true
04-24 16:06:47.682 1815 2160 D jinyanmeiani: ChangeInfo 111111111 mWindowingMode:5
04-24 16:06:47.682 1815 2160 D jinyanmeiani: java.lang.RuntimeException: jinyanmeiani
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.Transition$ChangeInfo.<init>(Transition.java:2258)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.Transition.collect(Transition.java:492)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.TransitionController.collect(TransitionController.java:568)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskSupervisor.findTaskToMoveToFront(ActivityTaskSupervisor.java:1529)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked(ActivityTaskManagerService.java:2464)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskSupervisor.startActivityFromRecents(ActivityTaskSupervisor.java:2901)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents(ActivityTaskManagerService.java:1931)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1430)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5786)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at android.os.Binder.execTransactInternal(Binder.java:1348)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at android.os.Binder.execTransact(Binder.java:1279) /** @see Transition#collect */
void collect(@NonNull WindowContainer wc) {
    if (mCollectingTransition == null) return;
    mCollectingTransition.collect(wc);
} 计算所有的到mChanges
根据WindowContainer new 一个ChangeInfo
ChangeInfo(@NonNull WindowContainer origState) {
    mContainer = origState;
    mVisible = origState.isVisibleRequested();
    mWindowingMode = origState.getWindowingMode();
    mAbsoluteBounds.set(origState.getBounds());
    mShowWallpaper = origState.showWallpaper();
    mRotation = origState.getWindowConfiguration().getRotation();
    mStartParent = origState.getParent();
} 把changeinfo放入mChanges
mChanges是一个map
key:WindowContainer
value:由key:WindowContainer构成的ChangeInfo
此列表在开始做动画时间会判断里面的key,value是否满足做动画的条件
void collect(@NonNull WindowContainer wc) {
      if (mState < STATE_COLLECTING) {
          throw new IllegalStateException("Transition hasn't started collecting.");
      }
      if (!isCollecting()) {
          // Too late, transition already started playing, so don't collect.
          return;
      }
      ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Collecting in transition %d: %s",
            mSyncId, wc);
      // "snapshot" all parents (as potential promotion targets). Do this before checking
      // if this is already a participant in case it has since been re-parented.
      for (WindowContainer<?> curr = getAnimatableParent(wc);
            curr != null && !mChanges.containsKey(curr);
            curr = getAnimatableParent(curr)) {
          mChanges.put(curr, new ChangeInfo(curr)); // 放入队列中
          if (isReadyGroup(curr)) {
            mReadyTracker.addGroup(curr);
            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Creating Ready-group for"
                              + " Transition %d with root=%s", mSyncId, curr);
          }
      }
      if (mParticipants.contains(wc)) return;
      // Wallpaper is like in a static drawn state unless display may have changes, so exclude
      // the case to reduce transition latency waiting for the unchanged wallpaper to redraw.
      final boolean needSyncDraw = !isWallpaper(wc) || mParticipants.contains(wc.mDisplayContent);
      if (needSyncDraw) {
          mSyncEngine.addToSyncSet(mSyncId, wc);
      }
      ChangeInfo info = mChanges.get(wc);
      if (info == null) {
          info = new ChangeInfo(wc);
          Slog.d("jinyanmeiainima","collect                  wc:" + wc );
          Slog.d("jinyanmeiainima","collect             info:" + info );

          Slog.d("jinyanmeiainima","collect mChanges.size()+++:" + mChanges.size() );
          mChanges.put(wc, info);
          Slog.d("jinyanmeiainima","collect mChanges.size()---:" + mChanges.size() );

      }
      mParticipants.add(wc);
      if (wc.getDisplayContent() != null && !mTargetDisplays.contains(wc.getDisplayContent())) {
          mTargetDisplays.add(wc.getDisplayContent());
      }
      if (info.mShowWallpaper) {
          // Collect the wallpaper token (for isWallpaper(wc)) so it is part of the sync set.
          final WindowState wallpaper =
                  wc.getDisplayContent().mWallpaperController.getTopVisibleWallpaper();
          if (wallpaper != null) {
            collect(wallpaper.mToken);
          }
      }
} 把new出来的动画申请开始动画requestStartTransition

04-23 18:43:25.211 2077 4588 D jinyanmeiainima: requestStartTransition displayChange:
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.requestStartTransition(TransitionController.java:548)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.findTaskToMoveToFront(ActivityTaskSupervisor.java:1622)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked(ActivityTaskManagerService.java:2497)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.startActivityFromRecents(ActivityTaskSupervisor.java:3034)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents(ActivityTaskManagerService.java:1918)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1434)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5840)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransactInternal(Binder.java:1348)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransact(Binder.java:1279) Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,
      @Nullable RemoteTransition remoteTransition,
      @Nullable TransitionRequestInfo.DisplayChange displayChange) {
    Slog.d("jinyanmeiainima","requestStartTransition transition:" + transition );
    Slog.d("jinyanmeiainima","requestStartTransition startTask:" + startTask );
    Slog.d("jinyanmeiainima","requestStartTransition remoteTransition:" + remoteTransition );
    Slog.d("jinyanmeiainima","requestStartTransition displayChange:" + displayChange );

    if (mIsWaitingForDisplayEnabled) {
      ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Disabling player for transition"
                + " #%d because display isn't enabled yet", transition.getSyncId());
      transition.mIsPlayerEnabled = false;
      transition.mLogger.mRequestTimeNs = SystemClock.uptimeNanos();
      mAtm.mH.post(() -> mAtm.mWindowOrganizerController.startTransition(
                transition.getToken(), null));
      return transition;
    }
    if (mTransitionPlayer == null || transition.isAborted()) {
      // Apparently, some tests will kill(and restart) systemui, so there is a chance that
      // the player might be transiently null.
      if (transition.isCollecting()) {
            transition.abort();
      }
      return transition;
    }
    try {
      ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                "Requesting StartTransition: %s", transition);
      ActivityManager.RunningTaskInfo info = null;
      if (startTask != null) {
            info = new ActivityManager.RunningTaskInfo();
            startTask.fillTaskInfo(info);
      }
      final TransitionRequestInfo request = new TransitionRequestInfo(
                transition.mType, info, remoteTransition, displayChange);
      transition.mLogger.mRequestTimeNs = SystemClock.elapsedRealtimeNanos();
      transition.mLogger.mRequest = request;
      Slog.d("jinyanmeiainima","requestStartTransition transition.getToken():" + transition.getToken() );
      Slog.d("jinyanmeiainima","requestStartTransition               request:" + request);

      Slog.d("jinyanmeiainima","requestStartTransition displayChange:" ,new RuntimeException("jinyanmeiainima") );
      mTransitionPlayer.requestStartTransition(transition.getToken(), request);
      transition.setRemoteTransition(remoteTransition);
    } catch (RemoteException e) {
      Slog.e(TAG, "Error requesting transition", e);
      transition.start();
    }
    return transition;
} 转到shell:
Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,
requestStartTransition
            mTransitionPlayer.requestStartTransition(transition.getToken(), request);
            transition.setRemoteTransition(remoteTransition); shell

   @BinderThread
    private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
      @Override
      public void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,
                SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)
                throws RemoteException {
            mMainExecutor.execute(() -> Transitions.this.onTransitionReady(
                  iBinder, transitionInfo, t, finishT));
      }

      @Override
      public void requestStartTransition(IBinder iBinder,
                TransitionRequestInfo request) throws RemoteException {
            mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
      }
    }
} void requestStartTransition(@NonNull IBinder transitionToken,
      @Nullable TransitionRequestInfo request) {
    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: %s %s",
            transitionToken, request);
    if (isTransitionKnown(transitionToken)) {
      throw new RuntimeException("Transition already started " + transitionToken);
    }
    final ActiveTransition active = new ActiveTransition();
    WindowContainerTransaction wct = null;

    // If we have sleep, we use a special handler and we try to finish everything ASAP.
    if (request.getType() == TRANSIT_SLEEP) {
      mSleepHandler.handleRequest(transitionToken, request);
      active.mHandler = mSleepHandler;
    } else {
      for (int i = mHandlers.size() - 1; i >= 0; --i) {
            wct = mHandlers.get(i).handleRequest(transitionToken, request);
            if (wct != null) {
                active.mHandler = mHandlers.get(i);
                break;
            }
      }
      if (request.getDisplayChange() != null) {
            TransitionRequestInfo.DisplayChange change = request.getDisplayChange();
            if (change.getEndRotation() != change.getStartRotation()) {
                // Is a rotation, so dispatch to all displayChange listeners
                if (wct == null) {
                  wct = new WindowContainerTransaction();
                }
                mDisplayController.getChangeController().dispatchOnDisplayChange(wct,
                        change.getDisplayId(), change.getStartRotation(),
                        change.getEndRotation(), null /* newDisplayAreaInfo */);
            }
      }
    }
    mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct);
    active.mToken = transitionToken;
    // Currently, WMCore only does one transition at a time. If it makes a requestStart, it
    // is already collecting that transition on core-side, so it will be the next one to
    // become ready. There may already be pending transitions added as part of direct
    // `startNewTransition` but if we have a request now, it means WM created the request
    // transition before it acknowledged any of the pending `startNew` transitions. So, insert
    // it at the front.
    mPendingTransitions.add(0, active);// 添加到mPendingTransitions
} private static final class ActiveTransition {
    IBinder mToken;
    TransitionHandler mHandler;
    boolean mAborted;
    TransitionInfo mInfo;
    SurfaceControl.Transaction mStartT;
    SurfaceControl.Transaction mFinishT;

    /** Ordered list of transitions which have been merged into this one. */
    private ArrayList<ActiveTransition> mMerged;
} 转到wm core

04-23 18:43:22.342 2980 3221 D jinyanmeiainima: WindowOrganizer transitionToken transitionToken:android.os.BinderProxy@3268f3
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: WindowOrganizer startTransition t:null
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.window.WindowOrganizer.startTransition(WindowOrganizer.java:112)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.requestStartTransition(Transitions.java:891)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.lambda$requestStartTransition$1(Transitions.java:1129)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.$r8$lambda$FkH1M0vUh3zDx8R5iMruInPEXLI(Unknown Source:0)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl$$ExternalSyntheticLambda1.run(Unknown Source:6)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Handler.handleCallback(Handler.java:958)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Looper.loopOnce(Looper.java:216)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Looper.loop(Looper.java:305)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.HandlerThread.run(HandlerThread.java:67) WindowOrganizer.java
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
   public void startTransition(@NonNull IBinder transitionToken,
         @Nullable WindowContainerTransaction t) {
       try {
         getWindowOrganizerController().startTransition(transitionToken, t);
       } catch (RemoteException e) {
         throw e.rethrowFromSystemServer();
       }
   } 转到 wm services
WindowOrganizerController WindowOrganizerController.java   
private IBinder startTransition(@WindowManager.TransitionType int type,
            @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) {
      enforceTaskPermission("startTransition()");
      final CallerInfo caller = new CallerInfo();
      final long ident = Binder.clearCallingIdentity();
      try {
            synchronized (mGlobalLock) {
                Transition transition = Transition.fromBinder(transitionToken);
                if (mTransitionController.getTransitionPlayer() == null && transition == null) {
                  Slog.w(TAG, "Using shell transitions API for legacy transitions.");
                  if (t == null) {
                        throw new IllegalArgumentException("Can't use legacy transitions in"
                              + " compatibility mode with no WCT.");
                  }
                  applyTransaction(t, -1 /* syncId */, null, caller);
                  return null;
                }
                // In cases where transition is already provided, the "readiness lifecycle" of the
                // transition is determined outside of this transaction. However, if this is a
                // direct call from shell, the entire transition lifecycle is contained in the
                // provided transaction and thus we can setReady immediately after apply.
                final boolean needsSetReady = transition == null && t != null;
                final WindowContainerTransaction wct =
                        t != null ? t : new WindowContainerTransaction();
                if (transition == null) {
                  if (type < 0) {
                        throw new IllegalArgumentException("Can't create transition with no type");
                  }
                  // If there is already a collecting transition, queue up a new transition and
                  // return that. The actual start and apply will then be deferred until that
                  // transition starts collecting. This should almost never happen except during
                  // tests.
                  if (mService.mWindowManager.mSyncEngine.hasActiveSync()) {
                        Slog.w(TAG, "startTransition() while one is already collecting.");
                        final Transition nextTransition = new Transition(type, 0 /* flags */,
                              mTransitionController, mService.mWindowManager.mSyncEngine);
                        ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                              "Creating Pending Transition: %s", nextTransition);
                        mService.mWindowManager.mSyncEngine.queueSyncSet(
                              // Make sure to collect immediately to prevent another transition
                              // from sneaking in before it. Note: moveToCollecting internally
                              // calls startSyncSet.
                              () -> mTransitionController.moveToCollecting(nextTransition),
                              () -> {
                                    nextTransition.start();
                                    applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
                                    if (needsSetReady) {
                                        nextTransition.setAllReady();
                                    }
                              });
                        return nextTransition.getToken();
                  }
                  transition = mTransitionController.createTransition(type);
                }
                if (!transition.isCollecting() && !transition.isForcePlaying()) {
                  Slog.e(TAG, "Trying to start a transition that isn't collecting. This probably"
                            + " means Shell took too long to respond to a request. WM State may be"
                            + " incorrect now, please file a bug");
                  applyTransaction(wct, -1 /*syncId*/, null /*transition*/, caller);
                  return transition.getToken();
                }
                transition.start();/到这里
                transition.mLogger.mStartWCT = wct;
                applyTransaction(wct, -1 /*syncId*/, transition, caller);
                if (needsSetReady) {
                  transition.setAllReady();
                }
                return transition.getToken();
            }
      } finally {
            Binder.restoreCallingIdentity(ident);
      }
    } 04-23 18:44:02.186 2107 2323 D jinyanmeiainima: BLASTSyncEngine setReady ready:true
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: java.lang.RuntimeException: setReady
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.setReady(BLASTSyncEngine.java:240)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.-$$Nest$msetReady(Unknown Source:0)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.setReady(BLASTSyncEngine.java:356)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.Transition.applyReady(Transition.java:657)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.Transition.start(Transition.java:446)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.WindowOrganizerController.startTransition(WindowOrganizerController.java:335)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.WindowOrganizerController.startTransition(WindowOrganizerController.java:267)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at android.window.IWindowOrganizerController$Stub.onTransact(IWindowOrganizerController.java:264)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.WindowOrganizerController.onTransact(WindowOrganizerController.java:185)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at android.os.Binder.execTransactInternal(Binder.java:1343)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at android.os.Binder.execTransact(Binder.java:1279)
然后调用到BLASTSyncEngine setReady 将动画状态置为ready
开始刷新
BLASTSyncEngine.java   
private void setReady(boolean ready) {

            if (mReady == ready) {
                return;
            }
            Slog.d("jinyanmeiainima","BLASTSyncEngine setReady            ready:" + ready, new RuntimeException("setReady"));

            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId);
            mReady = ready;
            if (!ready) return;
            mWm.mWindowPlacerLocked.requestTraversal();
      } private static final class ActiveTransition {
    IBinder mToken;
    TransitionHandler mHandler;
    boolean mAborted;
    TransitionInfo mInfo;
    SurfaceControl.Transaction mStartT;
    SurfaceControl.Transaction mFinishT;

    /** Ordered list of transitions which have been merged into this one. */
    private ArrayList<ActiveTransition> mMerged;
} onTransactionReady阶段

2.1 数据准备,筛选要做动画的对象

刷新时调用到 wm services. onTransactionReady 
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady mToken:Token{a674b32 TransitionRecord{d9c7094 id=6 type=TO_FRONT flags=0}}

04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady info:{t=TO_FRONT f=0x0 ro=Point(0, 0) c=[{WCT{RemoteToken{2a5ead1 Task{c299c5e #39 type=standard A=10245:com..notes}}} m=SHOW f=TRANSLUCENT leash=Surface(name=Task=39)/@0x2c4c3d4 sb=Rect(0, 0 - 1800, 2880) eb=Rect(799, 141 - 1759, 1848) eo=Point(799, 141)}]}
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady transaction:android.view.SurfaceControl$Transaction@65dbba
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady mFinishTransaction:android.view.SurfaceControl$Transaction@2d6a6b
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.Transition.onTransactionReady(Transition.java:1215)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.finishNow(BLASTSyncEngine.java:206) //这里会从队列移除
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.onSurfacePlacement(BLASTSyncEngine.java:148)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.-$$Nest$monSurfacePlacement(Unknown Source:0)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.onSurfacePlacement(BLASTSyncEngine.java:382)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:893)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:836)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:200)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:149)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:138)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:80)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Handler.handleCallback(Handler.java:958)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Looper.loopOnce(Looper.java:216)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Looper.loop(Looper.java:305)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.HandlerThread.run(HandlerThread.java:67)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.ServiceThread.run(ServiceThread.java:46)
BLASTSyncEngine.java
private void finishNow() {
            mActiveSyncs.remove(mSyncId); //从队列移除
} Transition.onTransactionReady
mTargets = calculateTargets(mParticipants, mChanges); //计算mTargets
根据target 计算info
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
Transition.java
public void onTransactionReady(int syncId, SurfaceControl.Transaction transaction) {
            
final ArrayMap<WindowContainer, ChangeInfo> mChanges = new ArrayMap<>(); //这里的mChanges 也是一个map

      mTargets = calculateTargets(mParticipants, mChanges);
      final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
      
                mController.getTransitionPlayer().onTransitionReady(
                        mToken, info, transaction, mFinishTransaction);
                if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                  Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
            
    } wm.services.Transition.calculateTargets
两个条件不添加动画:
1:!wc.isAttached()
2:!changeInfo.hasChanged()
将符合条件的changeInfo添加到targets 返回
@VisibleForTesting
@NonNull
static ArrayList<ChangeInfo> calculateTargets(ArraySet<WindowContainer> participants,
      ArrayMap<WindowContainer, ChangeInfo> changes) {
    ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
            "Start calculating TransitionInfo based on participants: %s", participants);

    // Add all valid participants to the target container.
    final Targets targets = new Targets();
    for (int i = participants.size() - 1; i >= 0; --i) {
      final WindowContainer<?> wc = participants.valueAt(i);
      if (!wc.isAttached()) {   
            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                  "Rejecting as detached: %s", wc);
            continue;
      }
      // The level of transition target should be at least window token.
      if (wc.asWindowState() != null) continue;

      final ChangeInfo changeInfo = changes.get(wc); // changes即mChanges,由onTransitionReady时添加到changes 的map //这里的changeInfo 与TransitionInfo不是一个

      // Reject no-ops
      if (!changeInfo.hasChanged()) {
            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                  "Rejecting as no-op: %s", wc);
            continue;
      }
      targets.add(changeInfo);
    }
    ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Initial targets: %s",
            targets.mArray);
    // Combine the targets from bottom to top if possible.
    tryPromote(targets, changes);
    // Establish the relationship between the targets and their top changes.
    populateParentChanges(targets, changes);

    final ArrayList<ChangeInfo> targetList = targets.getListSortedByZ();
    ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Final targets: %s", targetList);
    return targetList;
}
boolean hasChanged() {
         // the task including transient launch must promote to root task
         if ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0
               || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
             return true;
         }
         // If it's invisible and hasn't changed visibility, always return false since even if
         // something changed, it wouldn't be a visible change.
         final boolean currVisible = mContainer.isVisibleRequested();
         if (currVisible == mVisible && !mVisible) return false;
         return currVisible != mVisible
               || mKnownConfigChanges != 0
               // if mWindowingMode is 0, this container wasn't attached at collect time, so
               // assume no change in windowing-mode.
               || (mWindowingMode != 0 && mContainer.getWindowingMode() != mWindowingMode)
               || !mContainer.getBounds().equals(mAbsoluteBounds)
               || mRotation != mContainer.getWindowConfiguration().getRotation();
   } 根据上步计算出来的sortedTargets计算要做的动画TransitionInfo
TransitionInfo中有个mChanges
public final class TransitionInfo implements Parcelable {

    /**
   * Modes are only a sub-set of all the transit-types since they are per-container
   * @hide
   */
    @IntDef(prefix = { "TRANSIT_" }, value = {
            TRANSIT_NONE,
            TRANSIT_OPEN,
            TRANSIT_CLOSE,
            // Note: to_front/to_back really mean show/hide respectively at the container level.
            TRANSIT_TO_FRONT,
            TRANSIT_TO_BACK,
            TRANSIT_CHANGE
    })
    public @interface TransitionMode {}
    private final ArrayList<Change> mChanges = new ArrayList<>(); public static final class Change implements Parcelable {
    private final WindowContainerToken mContainer;
    private WindowContainerToken mParent;
    private WindowContainerToken mLastParent;
    private final SurfaceControl mLeash;
    private @TransitionMode int mMode = TRANSIT_NONE;
    private @ChangeFlags int mFlags = FLAG_NONE;
    private final Rect mStartAbsBounds = new Rect();
    private final Rect mEndAbsBounds = new Rect();
    private final Point mEndRelOffset = new Point();
    private ActivityManager.RunningTaskInfo mTaskInfo = null;
    private boolean mAllowEnterPip;
    private @Surface.Rotation int mStartRotation = ROTATION_UNDEFINED;
    private @Surface.Rotation int mEndRotation = ROTATION_UNDEFINED;
    /**
   * The end rotation of the top activity after fixed rotation is finished. If the top
   * activity is not in fixed rotation, it will be {@link ROTATION_UNDEFINED}.
   */
    private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
    private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
    private @ColorInt int mBackgroundColor;
    private SurfaceControl mSnapshot = null;
    private float mSnapshotLuma; static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,
      ArrayList<ChangeInfo> sortedTargets,
      @Nullable SurfaceControl.Transaction startT) {
    final TransitionInfo out = new TransitionInfo(type, flags);//根据type 和flags 构建新的TransitionInfo 对象

    WindowContainer<?> topApp = null;
    for (int i = 0; i < sortedTargets.size(); i++) {
      final WindowContainer<?> wc = sortedTargets.get(i).mContainer;
      if (!isWallpaper(wc)) {
            topApp = wc;
            break;
      }
    }
    if (topApp == null) {
      out.setRootLeash(new SurfaceControl(), 0, 0);
      return out;
    }

    WindowContainer<?> ancestor = findCommonAncestor(sortedTargets, topApp);

    // Make leash based on highest (z-order) direct child of ancestor with a participant.
    // TODO(b/261418859): Handle the case when the target contains window containers which
    // belong to a different display. As a workaround we use topApp, from which wallpaper
    // window container is removed, instead of sortedTargets here.
    WindowContainer leashReference = topApp;
    while (leashReference.getParent() != ancestor) {
      leashReference = leashReference.getParent();
    }
    final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
            "Transition Root: " + leashReference.getName()).build();
    startT.setLayer(rootLeash, leashReference.getLastLayer());                              // 设置layer
    out.setRootLeash(rootLeash, ancestor.getBounds().left, ancestor.getBounds().top);    //设置leash

    // Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
    final int count = sortedTargets.size();                      //遍历上一步筛选出来的sortedTargets
    for (int i = 0; i < count; ++i) {
      final ChangeInfo info = sortedTargets.get(i);
      final WindowContainer target = info.mContainer;
      final TransitionInfo.Change change = new TransitionInfo.Change(
                target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()   //根据windwoContainer的成员变量mWindowContainerToken 构建一个change所以每个windwoContainer都有一个change
                        : null, getLeashSurface(target, startT));
      // TODO(shell-transitions): Use leash for non-organized windows.
      if (info.mEndParent != null) {
            change.setParent(info.mEndParent.mRemoteToken.toWindowContainerToken());
      }
      if (info.mStartParent != null && info.mStartParent.mRemoteToken != null
                && target.getParent() != info.mStartParent) {
            change.setLastParent(info.mStartParent.mRemoteToken.toWindowContainerToken());
      }
      change.setMode(info.getTransitMode(target));
      change.setStartAbsBounds(info.mAbsoluteBounds);
      change.setFlags(info.getChangeFlags(target));


      final Task task = target.asTask();
      final TaskFragment taskFragment = target.asTaskFragment();
      final ActivityRecord activityRecord = target.asActivityRecord();

      if (task != null) {
            final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
            task.fillTaskInfo(tinfo);
            change.setTaskInfo(tinfo);
            change.setRotationAnimation(getTaskRotationAnimation(task));
            final ActivityRecord topMostActivity = task.getTopMostActivity();
            change.setAllowEnterPip(topMostActivity != null
                  && topMostActivity.checkEnterPictureInPictureAppOpsState());
            final ActivityRecord topRunningActivity = task.topRunningActivity();
            if (topRunningActivity != null && task.mDisplayContent != null
                  // Display won't be rotated for multi window Task, so the fixed rotation
                  // won't be applied. This can happen when the windowing mode is changed
                  // before the previous fixed rotation is applied.
                  && !task.inMultiWindowMode()) {
                // If Activity is in fixed rotation, its will be applied with the next rotation,
                // when the Task is still in the previous rotation.
                final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
                final int activityRotation = topRunningActivity.getWindowConfiguration()
                        .getDisplayRotation();
                if (taskRotation != activityRotation) {
                  change.setEndFixedRotation(activityRotation);
                }
            }
      } else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {
            change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);
      }

      final WindowContainer<?> parent = target.getParent();
      final Rect bounds = target.getBounds();
      final Rect parentBounds = parent.getBounds();
      change.setEndRelOffset(bounds.left - parentBounds.left,
                bounds.top - parentBounds.top);
      int endRotation = target.getWindowConfiguration().getRotation();
      if (activityRecord != null) {
            // TODO(b/227427984): Shell needs to aware letterbox.
            // Always use parent bounds of activity because letterbox area (e.g. fixed aspect
            // ratio or size compat mode) should be included in the animation.
            change.setEndAbsBounds(parentBounds);
            if (activityRecord.getRelativeDisplayRotation() != 0
                  && !activityRecord.mTransitionController.useShellTransitionsRotation()) {
                // Use parent rotation because shell doesn't know the surface is rotated.
                endRotation = parent.getWindowConfiguration().getRotation();
            }
      } else {
            change.setEndAbsBounds(bounds);
      }

      if (activityRecord != null || (taskFragment != null && taskFragment.isEmbedded())) {
            final int backgroundColor;
            final TaskFragment organizedTf = activityRecord != null
                  ? activityRecord.getOrganizedTaskFragment()
                  : taskFragment.getOrganizedTaskFragment();
            if (organizedTf != null && organizedTf.getAnimationParams()
                  .getAnimationBackgroundColor() != DEFAULT_ANIMATION_BACKGROUND_COLOR) {
                // This window is embedded and has an animation background color set on the
                // TaskFragment. Pass this color with this window, so the handler can use it as
                // the animation background color if needed,
                backgroundColor = organizedTf.getAnimationParams()
                        .getAnimationBackgroundColor();
            } else {
                // Set background color to Task theme color for activity and embedded
                // TaskFragment in case we want to show background during the animation.
                final Task parentTask = activityRecord != null
                        ? activityRecord.getTask()
                        : taskFragment.getTask();
                backgroundColor = parentTask.getTaskDescription().getBackgroundColor();
            }
            // Set to opaque for animation background to prevent it from exposing the blank
            // background or content below.
            change.setBackgroundColor(ColorUtils.setAlphaComponent(backgroundColor, 255));
      }

      change.setRotation(info.mRotation, endRotation);
      if (info.mSnapshot != null) {
            change.setSnapshot(info.mSnapshot, info.mSnapshotLuma);
      }

      out.addChange(change);//最后把widowContainer的change放入mChanger中out(TransitionInfo)中
    }

    TransitionInfo.AnimationOptions animOptions = null;
    if (topApp.asActivityRecord() != null) {
      final ActivityRecord topActivity = topApp.asActivityRecord();
      animOptions = addCustomActivityTransition(topActivity, true/* open */, null);
      animOptions = addCustomActivityTransition(topActivity, false/* open */, animOptions);
    }
    final WindowManager.LayoutParams animLp =
            getLayoutParamsForAnimationsStyle(type, sortedTargets);
    if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
            && animLp.windowAnimations != 0) {
      // Don't send animation options if no windowAnimations have been set or if the we are
      // running an app starting animation, in which case we don't want the app to be able to
      // change its animation directly.
      if (animOptions != null) {
            animOptions.addOptionsFromLayoutParameters(animLp);
      } else {
            animOptions = TransitionInfo.AnimationOptions
                  .makeAnimOptionsFromLayoutParameters(animLp);
      }
    }
    if (animOptions != null) {
      out.setAnimationOptions(animOptions);
    }

    return out;
} 2.2 开始动画

到shell.onTransitionReady
@BinderThread
private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
    @Override
    public void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,
            SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)
            throws RemoteException {
      mMainExecutor.execute(() -> Transitions.this.onTransitionReady(
                iBinder, transitionInfo, t, finishT));
    }

    @Override
    public void requestStartTransition(IBinder iBinder,
            TransitionRequestInfo request) throws RemoteException {
      mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
    }
} void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
      ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
                transitionToken, info);
      final int activeIdx = findByToken(mPendingTransitions, transitionToken);
      if (activeIdx < 0) {
            throw new IllegalStateException("Got transitionReady for non-pending transition "
                  + transitionToken + ". expecting one of "
                  + Arrays.toString(mPendingTransitions.stream().map(
                            activeTransition -> activeTransition.mToken).toArray()));
      }
      if (activeIdx > 0) {
            Log.e(TAG, "Transition became ready out-of-order " + transitionToken + ". Expected"
                  + " order: " + Arrays.toString(mPendingTransitions.stream().map(
                            activeTransition -> activeTransition.mToken).toArray()));
      }
      // Move from pending to ready
      final ActiveTransition active = mPendingTransitions.remove(activeIdx);//从 mPendingTransitions 移除
      mReadyTransitions.add(active); //添加至 mReadyTransitions
      active.mInfo = info;
      active.mStartT = t;
      active.mFinishT = finishT;

      for (int i = 0; i < mObservers.size(); ++i) {
            mObservers.get(i).onTransitionReady(transitionToken, info, t, finishT);
      }

      if (info.getType() == TRANSIT_SLEEP) {
            if (activeIdx > 0) {
                if (!info.getRootLeash().isValid()) {
                  // Shell has some debug settings which makes calling binders with invalid
                  // surfaces crash, so replace it with a "real" one.
                  info.setRootLeash(new SurfaceControl.Builder().setName("Invalid")
                            .setContainerLayer().build(), 0, 0);
                }
                // Sleep starts a process of forcing all prior transitions to finish immediately
                finishForSleep(null /* forceFinish */);
                return;
            }
      }

      // Allow to notify keyguard un-occluding state to KeyguardService, which can happen while
      // screen-off, so there might no visibility change involved.
      if (!info.getRootLeash().isValid() && info.getType() != TRANSIT_KEYGUARD_UNOCCLUDE) {
            // Invalid root-leash implies that the transition is empty/no-op, so just do
            // housekeeping and return.
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Invalid root leash (%s): %s",
                  transitionToken, info);
            onAbort(active);
            return;
      }

      final int changeSize = info.getChanges().size(); //找到带有change的info
      boolean taskChange = false;
      boolean transferStartingWindow = false;
      boolean allOccluded = changeSize > 0;
      for (int i = changeSize - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            taskChange |= change.getTaskInfo() != null;
            transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);
            if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
                allOccluded = false;
            }
      }
      // There does not need animation when:
      // A. Transfer starting window. Apply transfer starting window directly if there is no other
      // task change. Since this is an activity->activity situation, we can detect it by selecting
      // transitions with only 2 changes where neither are tasks and one is a starting-window
      // recipient.
      if (!taskChange && transferStartingWindow && changeSize == 2
                // B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all
                // changes are underneath another change.
                || ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)
                && allOccluded)) {
            // Treat this as an abort since we are bypassing any merge logic and effectively
            // finishing immediately.
            onAbort(active);
            return;
      }

      setupStartState(active.mInfo, active.mStartT, active.mFinishT);    //开始置状态

      if (mReadyTransitions.size() > 1) {
            // There are already transitions waiting in the queue, so just return.
            return;
      }
      processReadyQueue();//开始动画
    } 04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow s.mSyncId:5
04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow mActiveSyncs++++:1
04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow s.mSyncId:5
04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow mActiveSyncs++++:0
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: startAnimation TRANSIT_CHANGE:
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.dispatchTransition(Transitions.java:708)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.playTransition(Transitions.java:693)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.processReadyQueue(Transitions.java:627)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.onTransitionReady(Transitions.java:600)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.lambda$onTransitionReady$0(Transitions.java:1122)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.$r8$lambda$qsRfWn1ItrZqnFeABBdxU50jPc4(Unknown Source:0)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl$$ExternalSyntheticLambda0.run(Unknown Source:10)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Handler.handleCallback(Handler.java:958)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Looper.loopOnce(Looper.java:216)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Looper.loop(Looper.java:305)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.HandlerThread.run(HandlerThread.java:67)
然后各个继承于
implements Transitions.TransitionHandler 的对象都会调用到startAnimation 走各个业务动画逻辑

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Android 14 transtion 动画流程