ラベル ICS の投稿を表示しています。 すべての投稿を表示
ラベル ICS の投稿を表示しています。 すべての投稿を表示

2012年8月15日水曜日

何気なく使っているFramework 第7回 スクリーンショット


今回から確認OSバージョンをAndroid OS 4.0.1_r1に変更しました。


確認OSバージョン

Android OS 4.0.1_r1 ICS

スクリーンショット


ICSから端末単体でスクリーンショットが撮れるようになりました。
とりあえず、frameworks内の確認!!


スクリーンショットが実行されるまでの流れ


  1. Native層のInputDispatcherからinterceptKeyBeforeQueueingをコール
  2. 一旦、Java層にコールバック
  3. InputManagerを経てPhoneWindowManager#interceptKeyBeforeQueueing

    1. interceptKeyBeforeQueueing
    2. interceptScreenshotChord()
    3. mScreenshotChordLongPress#run
    4. takeScreenshot()
  4. SystemUIに新たに追加されたService、TakeScreenshotService

    1. run()
  5. GlobalScreenshot#takeScreenshot
  6. Surface.screenshotをコールし画面イメージのBitmap取得
  7. アニメーションして保存


確認しておいた方がいいソース

\frameworks\base\services\input
- InputDispatcher.cpp
- InputManager.cpp
\frameworks\base\policy\src\com\android\internal\policy\impl
- PhoneWindowManager.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\screenshot
- GlobalScreenshot.java
- TakeScreenshotService.java


簡易クラス図


f:id:baroqueworksdev:20111204004218p:image:w640

何気なく使っているFrameworks 第9回 CPU使用状況を表示/ addView


CPU使用状況を表示

ICSから開発者向けオプションに「CPU使用状況を表示」が追加されました。

f:id:baroqueworksdev:20120124001631p:image:w360


Settingsで設定すると

以下の処理順でサービス:LoadAverageServiceが起動します。
このサービス内でProcessから取得した値をオーバーレイ表示を行っています。

値が何を意味するのかはProcessStats.javaをみればわかります。
ついでに、Viewの追加→WindowManagerServiceまでの流れも要チェックです。

特にViewRoot.javaがViewRootImpl.javaへ変わり、中身もそれなりに修正されています。

DevelopmentSettings#onPreferenceTreeClick
- writeCpuUsageOptions()
- startService "com.android.systemui.LoadAverageService" of SysttemUI.
- LoadAverageService#onCreate()
- new LoadView extends ProcessStats
- new Stats
- WindowManager#addView() with Overlay layer of SECURE_SYSTEM_OVERLAY_LAYER
- WindowManagerImpl#addView
- ViewRootImpl#setView
- IWindowSession#add
- Session#add
- WindowManagerService#addWindow


確認しておいた方がいいソース

\packages\apps\Settings\src\com\android\settings
  • DevelopmentSettings.java

\frameworks\base\packages\SystemUI\src\com\android\systemui
  • LoadAverageService.java

\frameworks\base\core\java\com\android\internal\os
  • ProcessStats.java

\frameworks\base\core\java\android\view
  • ViewRootImpl.java

\frameworks\base\services\java\com\android\server\wm
  • WindowManagerService.java

\frameworks\base\policy\src\com\android\internal\policy\impl
  • PhoneWindowManager.java


簡易クラス図

f:id:baroqueworksdev:20120124002429p:image:w640

PhoneモードとTabletモードの切り分け


Android 4.x(Ice Cream Sandwich)はPhoneとTablet、両方のOSとして使用されます。
では、どこでPhone/Tabletの切り分けはどこで行っているか確認します。

Phone/Tabletの切り分け

起動処理中、以下の処理でFrameworks内のDisplaySizeを初期化します。
ServerThread#run()
- WindowManagerService#displayReady
- PhoneWindowManagerService#setInitialDisplaySize


PhoneWindowManagerService#setInitialDisplaySizeのそれらしき処理があります。

// Determine whether the status bar can hide based on the size
// of the screen.  We assume sizes > 600dp are tablets where we
// will use the system bar.
int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / DisplayMetrics.DENSITY_DEVICE;
mStatusBarCanHide = shortSizeDp < 600;


ソースは
 スクリーンのswWidth * DisplayMetrics.DENSITY_DEFAULT
 DisplayMetrics.DENSITY_DEVICE が600未満かどうか
と記述されています。


DisplayMetrics.javaに記述されている値はこんな感じ。
    /**
     * Standard quantized DPI for medium-density screens.
     */
    public static final int DENSITY_MEDIUM = 160;

    /**
     * The reference density used throughout the system.
     */
    public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;

    /**
     * The device's density.
     * @hide becase eventually this should be able to change while
     * running, so shouldn't be a constant.
     */
     public static final int DENSITY_DEVICE = getDeviceDensity();

     private static int getDeviceDensity() {
         // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
         // when running in the emulator, allowing for dynamic configurations.
         // The reason for this is that ro.sf.lcd_density is write-once and is
         // set by the init process when it parses build.prop before anything else.
         return SystemProperties.getInt("qemu.sf.lcd_density",
         SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
     }


crespo(Nexus s)の場合、
 swWidth = 480
 ro.sf.lcd_density=240
 shortSizeDp = 480 * 160 / 240 = 320

よって、Phoneモードとなる。


maguro(Galaxy Nexus)の場合、
 swWidth = 720
 ro.sf.lcd_density=320
 shortSizeDp = 720 * 160 / 320 = 360

よって、Phoneモードとなる。

maguro(Galaxy Nexus)でTabletモードで起動したい場合、
lcd_densityを320から160に変更すれば可能なはず。

 swWidth = 720
 ro.sf.lcd_density=160
 shortSizeDp = 720 * 160 / 160 = 720



確認しておきたいソース


\frameworks\base\policy\src\com\android\internal\policy\impl
- PhoneWindowManagerService.java

\frameworks\base\core\java\android\util
- DisplayMetrics.java

\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar
- この配下全部 StatusBar / SystemBarの切り分けなど。

プリインストールアプリの無効化



f:id:baroqueworksdev:20120215235245p:image:w360


設定のアプリ一覧からプリインストールの無効化ができます。
ただし、すべてのプリインストールが無効にできるわけではありません。


以下のソースを確認。

packages\apps\Settings\src\com\android\settings\applications
  • InstalledAppDetails.java

    private void initUninstallButtons() {
        mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
        boolean enabled = true;
        if (mUpdatedSysApp) {
            mUninstallButton.setText(R.string.app_factory_reset);
        } else {
            if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                enabled = false;
                if (SUPPORT_DISABLE_APPS) {
                    try {
                        // Try to prevent the user from bricking their phone
                        // by not allowing disabling of apps signed with the
                        // system cert and any launcher app in the system.
                        PackageInfo sys = mPm.getPackageInfo("android",
                                PackageManager.GET_SIGNATURES);
                        Intent intent = new Intent(Intent.ACTION_MAIN);
                        intent.addCategory(Intent.CATEGORY_HOME);
                        intent.setPackage(mAppEntry.info.packageName);
                        List homes = mPm.queryIntentActivities(intent, 0);
                        if ((homes != null && homes.size() > 0) ||
                                (mPackageInfo != null && mPackageInfo.signatures != null &&
                                        sys.signatures[0].equals(mPackageInfo.signatures[0]))) {
                            // Disable button for core system applications.
                            mUninstallButton.setText(R.string.disable_text);
                        } else if (mAppEntry.info.enabled) {
                            mUninstallButton.setText(R.string.disable_text);
                            enabled = true;
                        } else {
                            mUninstallButton.setText(R.string.enable_text);
                            enabled = true;
                        }
                    } catch (PackageManager.NameNotFoundException e) {
                        Log.w(TAG, "Unable to get package info", e);
                    }
                }
            } else {
                mUninstallButton.setText(R.string.uninstall_text);
            }
        }
        // If this is a device admin, it can't be uninstall or disabled.
        // We do this here so the text of the button is still set correctly.
        if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
            enabled = false;
        }
        mUninstallButton.setEnabled(enabled);
        if (enabled) {
            // Register listener
            mUninstallButton.setOnClickListener(this);
        }
    }


以下のプリインストールアプリは無効化できません。
  • マーケットからUpdateを行った
  • Intent.CATEGORY_HOMEのActivityを持っている (= Launcher Application)
  • System と同じSignature を持っている ( = System Application)


Disableを選択すると、PackegeManager#setApplicationEnabledSetting()がよばれ無効化されます。
無効化されたアプリは、アプリ一覧に表示されなくなります。