原文:blog.fiftykg.com/

前言

通过本文,你可以 1、了解一种特别的闪屏 2、了解 android 版本彩蛋的实现原理 3、获得一个 android 各版本彩蛋的demo

特殊的闪屏

在体验 App 时发现了一款叫‘图凌’的 app,闪屏页非常特别。从下图可以看到,是一个以桌面壁纸为背景的页面。

图凌动态效果

这种闪屏效果让人眼前一亮,所以非常好奇他的实现原理。在不破解 apk 的情况下(破解失败,有腾讯乐固加固 ==),猜想了几种实现方式:

1、通过Api获取壁纸,然后设置Activity的背景
2、特殊的Activity theme
复制代码

在逐个验证猜想之前,想到了一个页面的实现与‘图凌’的闪屏非常相似,就是 Android 的版本彩蛋(设置 - 关于手机 -Android 版本点击 3 下)。而这个页面是可以找到源码的。

扒源码

打开彩蛋页面,执行以下命令,可以得知 Activity 的名字是 PlatLogoActivity。

adb shell dumpsys activity | grep "Focus"

mFocusedActivity: ActivityRecord{2829baa u0 android/com.android.internal.app.PlatLogoActivity t4844}
mFocusedStack=ActivityStack{d93bf0d stackId=1, 4 tasks} mLastFocusedStack=ActivityStack{d93bf0d stackId=1, 4 tasks}

复制代码

( 或者 adb shell dumpsys activity top)

通过在线源码平台Xref,找到PlatLogoActivity,源码就不贴了,因为重点并不在PlatLogoActivity.java,而是在AndroidManifest,theme 才是关键!也就是开始的第二个猜想。

<activity android:name="com.android.internal.app.PlatLogoActivity"
android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
android:configChanges="orientation|keyboardHidden"
android:process=":ui">
</activity>
复制代码

试一试

通过源码基本了解了实现原理,但没有跑一下 Demo 是不靠谱的。 PlatLogoActivity 的实现非常独立,没有太多依赖。所以 copy 了一下各个版本的 PlatLogoActivity 做了一个 Demo。

Github: github.com/PortgasAce/…

探究

现在我们已经知道 theme 可以方便的实现‘图凌’的闪屏效果。那么代码可以实现吗?官方有开放相应的 api 吗?

这些问题的答案可以从 theme 的实现原理入手。通过 google 或者 xref 搜索 theme 的一些关键字,最终可以找到PhoneWindow#generateLayout有这样一段解析 theme 标签的代码:

... //省略了很多标签解析
if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
requestFeature(FEATURE_SWIPE_TO_DISMISS);
}

if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
…// 省略了很多标签解析

复制代码

theme 的主要实现就是通过window#requestFeaturewindow#setFlags方法改变样式。

临摹着写了Theme.Wallpaper.NoTitleBar.Fullscreen的 java 实现,见github:PlatLogoActivityNoStyle 主要代码:

requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().setWillNotDraw(true);
getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
复制代码

到此为止,猜想 2 通过 theme 和 java 实现都是验证了。那么其他猜想是否可行呢? 答案当然是可以的啦。通过 sdk 提供的WallpaperManager可以获取桌面壁纸。

Drawable bg = WallpaperManager.getInstance(context).getDrawable();
rootView.setBackground(bg);
复制代码

以上代码就可以给 Activity 设置背景为桌面壁纸。

但是有一个问题。动态壁纸(live wallpapewr)时通过该方法获取的 drawable 不但不会动,而且是错误的图片。

其实 liveWallpaper 获取的正确姿势是通过wallpaperManager#getWallpaperInfo#loadThumbnail

  private Drawable getWallpaperDrawable() {
    Drawable wallpaperDrawable;
    PackageManager pm = getApplicationContext().getPackageManager();
    WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
    if (wallpaperManager.getWallpaperInfo() != null) {
      /*
       * Wallpaper info is not equal to null, that is if the live wallpaper
       * is set, then get the drawable image from the package for the
       * live wallpaper
       */
      wallpaperDrawable = wallpaperManager
          .getWallpaperInfo().loadThumbnail(pm);
    } else {
      /*
       * Else, if static wallpapers are set, then directly get the
       * wallpaper image
       */
      wallpaperDrawable = wallpaperManager.getDrawable();
    }
    return wallpaperDrawable;
  }
复制代码

但是问题还是没有完全解决,背景不会动!每次调用 loadThumbnail 返回的图片都是一样的,因此猜想 1 只使用于静态壁纸。

以上。

巨人的肩膀

Andriod 中 Style/Theme 原理以及 Activity 界面文件选取过程浅析:blog.csdn.net/qinjuning/a…

  • Android

    开放手机联盟(一个由 30 多家科技公司和手机公司组成的团体)已开发出 Android,Android 是第一个完整、开放、免费的手机平台。

    293 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...