20190929のAndroidに関する記事は5件です。

[Android]常にフルスクリーンにしておきたい時のTIPS

目的

  • ナビゲーションバーが邪魔で基本常に非表示にしておきたい

方法

以下の処理を実装する。

MainActivity.kt
override fun onStart() {
     super.onStart()
     hideSystemUI()    
}

fun hideSystemUI() {
     window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            or View.SYSTEM_UI_FLAG_FULLSCREEN
            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
}

override fun onWindowFocusChanged(hasFocus: Boolean) {
    super.onWindowFocusChanged(hasFocus)
    if (hasFocus) hideSystemUI()
}

View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY

「外部からスワイプしないとナビゲーションバーが出てこない上に、出てきたナビゲーションは半透明になる」というモードを指す。
なお、ナビゲーションバーは普通がいいという場合はSYSTEM_UI_FLAG_IMMERSIVEを使う。

View.SYSTEM_UI_FLAG_FULLSCREEN

ステータスバーを非表示にする。

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION

ナビゲーションバーを非表示にする

View.SYSTEM_UI_FLAG_LAYOUT_STABLE

ナビゲーションバーが非表示になった時にレイアウトが崩れないようにする。

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

ステータスバーが非表示になった時にレイアウトが崩れないようにする。

onWindowFocusChangedでhideSystemUIする理由

これがないとDialogを表示するタイミングで再度ナビゲーションバーが表示されてしまう。

それでもDialogFragment表示時にナビゲーションが表示されてしまう場合

私は表示されしまったので以下の実装を行い対処した。
このためにBaseDialogFragmentができてしまったのであまり良い方法ではないかも。

BaseDialogFragment.kt
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        hideSystemUI()
    }

    // ソフトウェアキーの非表示
    private fun hideSystemUI() {
        dialog?.window?.setFlags(
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        )
        activity?.window?.decorView?.systemUiVisibility?.let {
            dialog?.window?.decorView?.setSystemUiVisibility(it)
        }
        dialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
    }

参考

全画面モードを有効にする
https://developer.android.com/training/system-ui/immersive

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

/proc/meminfoのviewerをつくった

やりたいこと

/proc/meminfoの内容を理解するために、色々実験しながら各要素の変遷が見たい。
ただ、メモリ使用状況を可視化するツールはたくさんあるがどれも抽象度が高く、
/proc/meminfoの粒度での変遷を表示するツールを見つけられなかった。

やったこと

/proc/meminfoをできるだけそのまま表示するmiviewerをつくった。
といっても/proc/meminfoを取得して積み上げグラフにしただけ。

active.png

miviewer

$ ./miviewer.py -h
usage: miviewer.py [-h] [-a] [-i INTERVAL] [-c COUNT] [--check] [-w WINDOW]
                   [-t {active,buff-cache,available,user-kernel}]

optional arguments:
  -h, --help            show this help message and exit
  -a, --adb             Get meminfo via adb.
  -i INTERVAL, --interval INTERVAL
                        The delay between updates in milli-seconds. Default is 200.
  -c COUNT, --count COUNT
                        Number of updates. Default is infinite.
  --check               Check some formulas.
  -w WINDOW, --window WINDOW
                        Shown period time in seconds. Default is 60.
  -t {active,buff-cache,available,user-kernel}, --type {active,buff-cache,available,user-kernel}
                        Graph type. Default is active.

デフォルトでは、スクリプトを実行したPCの/proc/meminfoを、200ms間隔で取得し、グラフにプロットする。
--adbオプションを指定することで、adb経由でAndroid端末の/proc/meminfoを取得することも可能。
また、/proc/meminfoの要素はそれぞれ重なりがあり、一つの積み上げグラフですべての要素を表示することはできないので、
4つの選択肢からグラフタイプを選択できるようにしている。

グラフタイプactive

デフォルト。
Activeかどうか、つまり、LRUリストに乗ってるかどうかで分類された要素を積み上げている。
冒頭のグラフはこのタイプ。
なお、凡例の要素名が@で始まるものは、それそのものが/proc/meminfoにあるわけではなく、何らかの方法で算出した値であることを示す。

active.png

グラフタイプbuff-cache

BuffersCached、つまりバッファキャッシュ(メタデータやraw I/O用のキャッシュ)とページキャッシュ(ファイル自体のページのキャッシュ)の変遷を見るとき用。

buff-cache.png

グラフタイプavailable

シンプルにMemAvailableとそれ以外を表示する。
Linux観点でSwappingが始まるまでの余力をザクッと見るとき用。

available.png

グラフタイプuser-kernel

ユーザ空間とカーネル空間のどちらで使っているかで分類してプロットする。
なんか使うことがあるかなとおもって用意したものの、デフォルトのactiveがあれば必要ない気がしないでもない。

user-kernel.png

環境

動作確認環境は、以下のとおり。

  • Ubuntu 18.04
  • Linux 5.0.0-29-generic
  • Python 3.6.8
  • matplotlib 2.1.1

とはいえあまり環境に依存する実装ではないので、
MemAvailableがある(3.14以降)Linux環境なら動くんじゃないかと。
もしかしたらadbモードならMac/Windowsでも動くかもしれない(未確認)。

おわりに

なにかお気づきの点やご要望などありましたらぜひご指摘ください。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android】ダークテーマの対応方法

はじめに

Android 10から本格サポートされたダークテーマ(ダークモード)のアプリ側の対応方法について説明します。

res/values/styles.xml

まず初めに、通常のテーマカスタマイズでも利用するstyles.xmlを更新し、ダークモードON/OFF時に切り替えたいカラーを定義しておきます。

<resources>
    <style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:colorBackground">@color/colorBackground</item>
        <item name="android:textColor">@color/textColor</item>
        <item name="android:textColorPrimary">@color/textColorPrimary</item>
        <item name="android:textColorSecondary">@color/textColorSecondary</item>
    </style>
</resources>

colors.xmlの作成

システム設定でダークモード有効時に参照されるカラー定義をres/values-night/colors.xmlに、通常時のカラーをres/values/colors.xmlにそれぞれ記載しておきます。

例) res/values-night/colors.xml

<resources>
    <color name="colorPrimary">#212121</color>
    <color name="colorPrimaryDark">#212121</color>
    <color name="colorAccent">#80cbc4</color>
    <color name="colorTransparent">#00000000</color>
    <color name="textColor">#FFFFFF</color>
    <color name="textColorPrimary">#FFFFFF</color>
    <color name="textColorSecondary">#808080</color>
    <color name="colorBackground">#313131</color>
    <color name="colorCardBackground">@color/colorPrimary</color>
    <color name="colorBackgroundBottomAppBar">#353535</color>
</resources>

ここまで対応すれば、システム設定に連動して、コードは一切書かなくても表示が切り替わります。

アプリ内の設定で動的に切り替えたい場合

AppCompatDelegate.setDefaultNightModeを利用します。

常にダークテーマで表示

AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_YES);

常にダークテーマOFF(通常表示)

AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_NO);

システム設定に連動する(特に指定しない場合はこちらがデフォルトです)

AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Class.getSimpleName()の罠

学び

Android開発において、SimpleNameは使うべきではなさそう。

背景

SimpleNameを使った実装で予期せぬ動作を経験しました。

全く違うクラス名にも関わらず、同一のSimpleNameになっていたのです。
例えば、下記のコードが true になるのです。

if (MainFragment.simpleName == SubFragment.simpleName) {
    // "MainFragment" と "SubFragment" の比較になることを期待したので、
    // falseを期待しているのに、trueになる場合がある
}

ちなみに、私の環境ではdebugビルドでは false になるのに、
releaseビルドでは true になりました。

勘のいい人はわかったかもしれませんね。

何が起きたのか

難読化。ProGuardの仕業。
上記の例では、MainFragmentSubFragment が別のパッケージだった場合に、
難読化されて同一のクラス名に置き換わる可能性があります。

初期設定のProGuardの設定では、
パッケージ内のクラス名はアルファベット順に置き換わります。

例えば、下記の二つのクラスは、このように変換されます。
com.yoshinori.sandbox.main.MainFragmentb.b.a.a.a
com.yoshinori.sandbox.sub.SubFragmentb.b.a.b.a

このように変換された時の SimpleName は、両方とも a です。
元々のクラス名は全然違うのに、難読化後は同一のクラス名として処理されてしまうのです。
当たり前のようで、気付きにくいミスです。

どうやって対応すれば良いのか

SimpleName ではなくて Name を使用する。

name は、パッケージ名 + クラス名です。
難読化前なら com.yoshinori.sandbox.main.MainFragment となります。
これであれば、難読化後であっても、同一になることはありません。

if (MainFragment.name == SubFragment.name) {
    // 常にfalseになる
}

終わりに

もし SimpleName を使用している場合、本当に問題ないか確認してみてください。
基本的に普段の実装時にはProGuardは無効にしていると思います。

ですので、リリース直前で気づくことになったり、
最悪の場合は不具合に気付かずストアリリースされちゃいます。
怖いですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows/Macでapkを動かす

Androidのアプリの画面をWindowsやMacで見たいという場合、apk自体をエミュレーターで動かしてしまう方法と、apkが動いているAndroidの画面をミラーリングする方法があります。

apk自体をエミュレーターで動かす方法

BlueStacksのインストール

BlueStacksをインストールします。Windows/iOS両方対応しています。
https://www.bluestacks.com/ja/index.html

起動すると、こうなります。

image.png

縦画面にしたい場合は、右上のボタンでサイドバーを開き、一番下の切り替えボタンを押します。

image.png

apkのインストール

分かりにくいですが、インストールアプリメニューからインストールします。

image.png

apkが動いているAndroidの画面をミラーリングする方法

ミラーリングする方法はいろいろありますが、USB接続するだけでお手軽にミラーリングする方法です。

VysorというChrome拡張を入れます。
https://chrome.google.com/webstore/detail/vysor/gidgenkbbabolejbgbpnhbimgjbffefm?hl=ja

Android側は、USBデバッグを有効にする必要があります。
その状態でVysorを起動し、USBでつなぐと、Vysorの画面にAndroid側の画面が表示されます。
Android側にはVysorアプリがインストールされます。
Windows側の画面からAndroidの画面をマウスで操作することもできます。

一定時間操作がないと広告が表示されます。戻るボタンで消せます。

おしまい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む