// LetterboxUiController.java voidupdateLetterboxSurface(WindowState winHint){ final WindowState w = mActivityRecord.findMainWindow(); if (w != winHint && winHint != null && w != null) { return; } // 对界面四周需要显示的 Layer 进行位置计算 layoutLetterbox(winHint); if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) { // 对 Surface 执行创建、参数设置等操作 mLetterbox.applySurfaceChanges(mActivityRecord.getSyncTransaction()); } }
voidlayoutLetterbox(WindowState winHint){ final WindowState w = mActivityRecord.findMainWindow(); if (w == null || winHint != null && w != winHint) { return; } updateRoundedCorners(w); updateWallpaperForLetterbox(w); // 是否进入 Letterbox 模式的关键判断 if (shouldShowLetterboxUi(w)) { if (mLetterbox == null) { // 把具体逻辑委托给 Letterbox mLetterbox = new Letterbox(() -> mActivityRecord.makeChildSurface(null), mActivityRecord.mWmService.mTransactionFactory, mLetterboxConfiguration::isLetterboxActivityCornersRounded, this::getLetterboxBackgroundColor, this::hasWallpaperBackgroudForLetterbox, this::getLetterboxWallpaperBlurRadius, this::getLetterboxWallpaperDarkScrimAlpha); mLetterbox.attachInput(w); } mActivityRecord.getPosition(mTmpPoint); // Get the bounds of the "space-to-fill". The transformed bounds have the highest // priority because the activity is launched in a rotated environment. In multi-window // mode, the task-level represents this. In fullscreen-mode, the task container does // (since the orientation letterbox is also applied to the task). final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds(); final Rect spaceToFill = transformedBounds != null ? transformedBounds : mActivityRecord.inMultiWindowMode() ? mActivityRecord.getRootTask().getBounds() : mActivityRecord.getRootTask().getParent().getBounds(); // 位置计算 mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint); } elseif (mLetterbox != null) { mLetterbox.hide(); } }
<declare-styleablename="View"> <!-- <p>Whether or not the force dark feature is allowed to be applied to this View. <p>Setting this to false will disable the auto-dark feature on this View draws including any descendants. <p>Setting this to true will allow this view to be automatically made dark, however a value of 'true' will not override any 'false' value in its parent chain nor will it prevent any 'false' in any of its children. --> <attrname="forceDarkAllowed"format="boolean" /> </declare-styleable>
<declare-styleablename="Theme"> <!-- <p>Whether or not the force dark feature is allowed to be applied to this theme. <p>Setting this to false will disable the auto-dark feature on everything this theme is applied to along with anything drawn by any children of views using this theme. <p>Setting this to true will allow this view to be automatically made dark, however a value of 'true' will not override any 'false' value in its parent chain nor will it prevent any 'false' in any of its children. --> <attrname="forceDarkAllowed"format="boolean" /> </declare-styleable>
// 关键代码,设置是否强制夜间模式 if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) { // TODO: Don't require regenerating all display lists to apply this setting invalidateWorld(mView); } }
template <typename Fn, typename... Args> inlinevoid DisplayListData::map(const Fn fns[], Args... args) const { auto end = fBytes.get() + fUsed; // 遍历当前的绘制的 op for (constuint8_t* ptr = fBytes.get(); ptr < end;) { auto op = (const Op*)ptr; auto type = op->type; auto skip = op->skip; // 根据 type 找到对应的 fn,根据调用关系,我们知道 fns 数组对应 color_transform_fns,这个数组其实是一个函数指针数组,下面看看定义 if (auto fn = fns[type]) { // We replace no-op functions with nullptrs // 执行 fn(op, args...); // to avoid the overhead of a pointless call. } ptr += skip; } }
template <typename Fn, typename... Args> inlinevoid DisplayListData::map(const Fn fns[], Args... args) const { auto end = fBytes.get() + fUsed; for (constuint8_t* ptr = fBytes.get(); ptr < end;) { auto op = (const Op*)ptr; auto type = op->type; auto skip = op->skip; if (auto fn = fns[type]) { // We replace no-op functions with nullptrs // 对 op 的 paint 进行颜色变换或叠加 colorfilter fn(op, args...); // to avoid the overhead of a pointless call. } ptr += skip; } }
if (info.fColorCount <= 10) { switch (type) { case SkShader::kLinear_GradientType: for (int i = 0; i < info.fColorCount; i++) { // 对 shader 中的颜色进行颜色变换 info.fColors[i] = transformColor(transform, info.fColors[i]); } paint.setShader(SkGradientShader::MakeLinear(info.fPoint, info.fColors, info.fColorOffsets, info.fColorCount, info.fTileMode, info.fGradientFlags, nullptr)); break; default:break; }
} }
if (paint.getColorFilter()) { SkBlendMode mode; SkColor color; // TODO: LRU this or something to avoid spamming new color mode filters if (paint.getColorFilter()->asColorMode(&color, &mode)) { // 对 colorfilter 中的颜色进行颜色变换 color = transformColor(transform, color); paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); } } }
// 创建依赖D D d = new D(); // 创建依赖C C c = new C(); // 创建依赖B B b = new B(c, d); // 创建依赖A A a = new A(b); // 创建PersonService的依赖:personDao PersonDao personDao = new PersonDaoImpl(a); // 通过构造方法注入依赖 mService = new PersonService(personDao); } }
publicclassHomePresenterImpimplementsHomePresenter{ publicHomePresenterImp(){ } @Override public Observable<List<User>> loadUsers(){ //Return user list observable } }
然后在 Module 中,提供实例化的 provide 方法:
1 2 3 4 5 6 7
@Module publicclassHomeModule{ @Provides public HomePresenter providesHomePresenter(){ returnnew HomePresenterImp(); } }
/** * 原始对象的方法被调用的时候,Robolectric会根据方法签名查找对应的Shadow方法并调用 */ @Implementation public String getName(){ return"Hello, I ma shadow of RobolectricBean: " + realBean.name; }