TextInputLayoutのpassword visibility toggleを試してみた

Android support library 24.2.0からTextInputLayoutに追加されたpassword visibility toggleを試してみた。

試したサンプルコードはGithubにあげてあります。

github.com

password visibility toggleってなんぞ??

簡単に説明するとパスワード入力する際に、入力している内容をtoggleで表示・非表示と切り替えるやーつーですね(雑だな...

Material Designのドキュメントに詳しく書いてあるので、それを見れば「あーこれかー」となるはず。

Text fields - Components - Material design guidelines

んで、今までこれと似たようなものを実装したことがある人ならわかるだろうけど、今まで独自の方法で実装するしかなかったわけだ。

その実装がsupport library 24.2.0からTextInputLayoutに導入されたってこと。うれしいです☺

さようなら、独自実装...😇

TextInputLayoutでどのようにpassword visibility toggleを使うか

基本はすごく簡単です。

以下のような感じでTextInputLayoutの子ViewのEditTextにandroid:inputType="textPassword"を指定するだけで、デフォルトのpassword visibility toggleが出てきます。

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="textPassword"
        android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>

こんな感じで動きます!簡単ですね!!

f:id:operando:20160923215819g:plain

もしpassword visibility toggleを出したくなければ、TextInputLayoutにapp:passwordToggleEnabled="false"を追加すると出なくまります。

inputTypeのxxxPasswordすべて試してみた

以下のような感じでinputTypeのxxxPasswordすべて試してみます。(長いのでlayout_widthとlayout_height省いてます

<android.support.design.widget.TextInputLayout ... >

    <EditText
        android:hint="textPassword"
        android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout ... >

    <EditText
        android:hint="numberPassword"
        android:inputType="numberPassword" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout ... >

    <EditText
        android:hint="textVisiblePassword"
        android:inputType="textVisiblePassword" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout ... >

    <EditText
        android:hint="textWebPassword"
        android:inputType="textWebPassword" />
</android.support.design.widget.TextInputLayout>

hintに出ている値が各EditTextのinputTypeに設定されています。

f:id:operando:20160923220303g:plain

android:inputType="textVisiblePassword"を設定しているものはpassword visibility toggleが出てないですね。当たり前かー。

passwordToggleDrawableでアイコンを変更する

デフォルトの目のアイコンはpasswordToggleDrawable属性で変えられます。

サンプルコードではVectorのドロイド君にアイコンを変更してます(デフォルトの目のアイコンもVectorです

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:passwordToggleDrawable="@drawable/ic_android_black_24dp">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="passwordToggleDrawable"
        android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>

変更すると以下の感じでアイコンが変わります。

f:id:operando:20160923222102g:plain

XMLの属性だけじゃなくてメソッドもちゃんとありますよ

今回のサンプルコードでは全てXMLの属性で指定してますが、ちゃんと属性とマッチしてるメソッドも用意されてます。

詳しくはTextInputLayoutのドキュメントを見てみてください。

developer.android.com

今回は使用しませんでしたが属性も他にpasswordToggleTintpasswordToggleTintModeがあります。

自身のアプリのデザインに合わせてカスタマイズすると良さそうですね。

まとめ

デフォルトのデザインでいいのならTextInputLayoutでpassword visibility toggleを試すのはすごく簡単だったなー

support libraryでこういうのが増えてくれるのは独自で実装する部分が減るのでとても助かりますねー

ANDROID IDがどのように生成されているかざっくり調べた

悪名高い??ANDROID IDがどのように生成されているのか気になったのでざっくり調べた。

悪名高いと言われる闇の話は置いておいて....とりあえず生成方法だけざっくり調べた。

どのような手順で生成されるのか?という疑問はバージョンによって実装が異なるっぽかったので調べない。

ANDROID IDとは

ドキュメント見てもらえばわかるけどざっくり以下のようなもの。

  • ランダムに生成される64ビットの数値を16進数文字列にしたもの
  • 端末の最初の設定時に生成される。その後、ファクトリーリセットするまではその時に生成された値が常に取得できる
  • ファクトリーリセットすることで値は再生成される
  • 4.2以上でmultiple usersが導入され、ユーザごとにANDROID IDが生成される

developer.android.com

ANDROID IDは以下のような感じで簡単に取得できる。

String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

ANDROID IDを使用する際の気をつけていること

ざっくり以下かなー他にもなにかあれば教えてほしいかなー

  • 「ランダムに生成される64ビットの数値を16進数文字列にしたもの」なので文字数は固定ではない
  • どんなアプリでも同じ値がAPIを通して取得できる
  • ファクトリーリセットすることで値が変わる
  • 同じANDROID IDを持った端末が存在する可能性がある
  • multiple users環境ではユーザごとにANDROID IDが生成されるため、ANDROID IDは端末に1つではない

ANDROID IDがどのように生成されているのか

とりあえずAndroid Nのコードから見てみる。

ANDROID IDを生成しているのはSettingsProvider.javaensureSecureSettingAndroidIdSetLockedメソッドだね。

全体の処理は以下のような感じ。詳しくは見ないけどドキュメントどおりmultiple usersの想定もされてる実装になってる。

private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
    Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);

    if (!value.isNull()) {
        return;
    }

    final int userId = getUserIdFromKey(secureSettings.mKey);

    final UserInfo user;
    final long identity = Binder.clearCallingIdentity();
    try {
        user = mUserManager.getUserInfo(userId);
    } finally {
        Binder.restoreCallingIdentity(identity);
    }
    if (user == null) {
        // Can happen due to races when deleting users - treat as benign.
        return;
    }

    String androidId = Long.toHexString(new SecureRandom().nextLong());
    secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
            SettingsState.SYSTEM_PACKAGE_NAME);

    Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
            + "] for user " + userId);

    // Write a drop box entry if it's a restricted profile
    if (user.isRestricted()) {
        DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
                Context.DROPBOX_SERVICE);
        if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
            dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
                    + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
        }
    }
}

http://tools.oesf.biz/android-7.0.0_r1.0/xref/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java#1915

ANDROID IDの生成処理は以下のような感じで実装されてる。

String androidId = Long.toHexString(new SecureRandom().nextLong());

SecureRandomでランダムなlong値を生成して、それをLong.toHexStringで16進数表現の文字列にする。

それがANDROID IDってことになるね。

ちなみにSecureRandom.nextLongの実装はRandom.nextLong)なんだけど、ドキュメントと実装見ればわかるけど、long 値の一部しか返さないっぽいんだよね。

なのでlong値の幅 -9223372036854775808~9223372036854775807の中の一部ってことだね。うーん...思ってた以上に範囲が狭い気もする...

あと、SecureRandom.nextLong生成される値によって16進数文字列にした時の文字列の長さは変わる

雑に以下のようなやつを実行してみればわかるけど、文字列の長さが16だったり、15だったり、14だったりする。

for (int i = 0; i < 100000; i++) {
    String androidId = Long.toHexString(new SecureRandom().nextLong());
    System.out.println(androidId.length());
}

これが最初の気にしておかなければいけない点で書いた「ランダムに生成される64ビットの数値を16進数文字列にしたもの」なので文字数は固定ではないってこと。

他のAndroidのバージョンではどう実装されているか

全部のバージョン見るのは面倒なので、いくつかのバージョンだけ。

4.0.1ではensureAndroidIdIsSetメソッドでANDROID IDが生成されてる。

もちろんSecureRandom.nextLong + Long.toHexStringANDROID IDが生成されてる。

てかSlog.dじゃなくて普通のLog.d使ってる...まあいいや...

private boolean ensureAndroidIdIsSet() {
    final Cursor c = query(Settings.Secure.CONTENT_URI,
            new String[] { Settings.NameValueTable.VALUE },
            Settings.NameValueTable.NAME + "=?",
            new String[] { Settings.Secure.ANDROID_ID }, null);
    try {
        final String value = c.moveToNext() ? c.getString(0) : null;
        if (value == null) {
            final SecureRandom random = new SecureRandom();
            final String newAndroidIdValue = Long.toHexString(random.nextLong());
            Log.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue + "]");
            final ContentValues values = new ContentValues();
            values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID);
            values.put(Settings.NameValueTable.VALUE, newAndroidIdValue);
            final Uri uri = insert(Settings.Secure.CONTENT_URI, values);
            if (uri == null) {
                return false;
            }
        }
        return true;
    } finally {
        c.close();
    }
}

http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java#316

ちなみに、コードは割愛しますが2.3.7の実装はだいたい4.0.1と同じ。もちろんSecureRandom.nextLong + Long.toHexStringANDROID IDが生成されてる。

http://tools.oesf.biz/android-2.3.7_r1.0/xref/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java#322

その他のバージョンもざっくり見たけど、SecureRandom.nextLong + Long.toHexStringANDROID IDが生成されていることは変わらない。当たり前か。

まとめ

Long.toHexString(new SecureRandom().nextLong())で生成されるものがANDROID IDだねーということ

思ってたよりANDROID IDの生成処理があっさりしたもので驚きだったかなー

モヤモヤするのはドキュメントに書いてある「 ランダムに生成される64ビットの数値を16進数文字列にしたもの」というのは表面上はあっているが、内部処理の話をすると「えー」と言いたくなる気分...

気になったら調べてみるもんだなー

APKのサイズを34KBから21KBまで減らすために行ったこと🐱

EasterEgg Neko Atsume LauncherのAPKサイズを極限まで小さくすることに取り組んだ成果を適当に書いておく。

EasterEgg Neko Atsume Launcherがそもそもなんだ??って話だろうけど、以下とか読めばOK。

hack-it-iron.hatenablog.com

play.google.com

どのようにAPKのサイズを小さくしたか

コードはGithub上に公開してある。読むほどの価値はない...🐱

具体的にAPKサイズのチューニングを行ったPull Requestは以下の2つ。

github.com

github.com

不要なリソースファイルを削除する

EasterEgg Neko Atsume Launcherはアプリの性質上、ほとんどリソースを必要としない。

R.javaさえ消し去りたいくらいだ。

styles.xmlはいらないね。テーマの定義なんてAndroidManifest.xmlに直接書けばいい。さらば、styles.xml

次はstrings.xml、いらないね。アプリ名なんてAndroidManifest.xmlに直接書けばいい。さらば、strings.xml

これでres配下はアプリアイコンが配置してあるmipmapだけになった。

不要なリソースの削除はココらへんが限界。(mipmap-mdpiとか消してよくね?とかもあるけど、そこは消さずに残す縛り

アプリアイコンを最適化(optimize)する

不要なリソースファイルを消したところで削れるのは所詮 数十 〜 百 byteほどだ。

ということでアプリ唯一のリソースであるアプリアイコンを最適化してみよう。

使うツールは画像最適化ツールの「ImageOptim」

ImageOptim — better Save for Web

使い方が簡単なのでとても嬉しい。ファイルをDropするだけで最適化してくれて、どれくらい最適化できてのかも表示してくれる。

んで、ImageOptimにアプリアイコンをDropして最適化してみる。

アプリアイコンが 30%くらい最適化された。素晴らしい!

ImageOptimでもうひと押し最適化する

ImageOptimのメニューバーの「ツール」を開いてみると最適化の方式が選べることに気づいた。

「品質: 100%」というのがデフォルトの設定みたい。最適化しても品質は落ちさないというのは当たり前か。

f:id:operando:20160921185135p:plain

んじゃ、その下にある非可逆圧縮の動作に変えて再度アプリアイコンを最適化してみた。

f:id:operando:20160921185142p:plain

画像のサイズは小さくなるが、画像の品質が落ちるので適材適所ではあるが、ここは心を鬼にしてAPKのサイズを小さくすることに優先するぞ!

ぐぬぬ...🐱よ... ちょっと品質落ちるけどごめんなー!!という気持ち...

その結果、Release APKのサイズが21KBになった!!

最適化前のVersion 1のRelease APKのサイズが 34KBだったので、 34 - 21 = 13KBの削減だ。

最高だ🐱!!

21KBになったVersion 2のAPKをリリース

最高のアップデートだ🐱

f:id:operando:20160921190103p:plain

まとめ

アプリの性質によってはリリースを限界まで削減できる。

コードをいじったり、削除したりで限界がきたら画像をImageOptim等で最適化してみるといい。

🐱最高!!

Androidについて語る! shinobu.apk #3 を10/5 (水)に開催します! #shinobuapk

はい、タイトルどおりshinobu.apk #3を開催するんですよ!!やたー(/・ω・)/やたー(/・ω・)/やたー(/・ω・)/

shinobu.apk #3のイベントページになります!

shinobu-apk.connpass.com

開催日は 10/5 (水) 19:30からメルカリのオフィスにて行います。

興味があればぜひぜひ参加登録していただけると嬉しいです!!

そもそも shinobu.apkってなんぞ??

shinobu.apkは、Shinobu Okano(この記事書いてる本人)と愉快な仲間たちが繰り広げるファンタジーな勉強会です。

shibuya.apkという、渋谷を中心に活動するAndroidアプリ開発者コミュニティの名前をtypoしたことによって生まれたものです。

真面目に言うと、有志を募ってAndroidについてパネルディスカッションをする勉強会です。

という感じで、真面目だけどゆるふわな感じでAndroidについてパネルディスカッションする勉強会です!

shinobu.apkがどんな雰囲気のものなのかを知りたい場合は、shinobu.apk #1、#2のディスカッション内容の録音データやまとめ記事を書いていますので、こちらをご参照してください。

shinobu.apk #1ではAndroidで今起きている変化と今後のAndroidにどんなことを思っているのか、願っているのか」、#2では「個人でもAndroidアプリを開発している人に聞きたい開発事情、個人アプリ開発に思うこと」をメインテーマにディスカッションしました。

tech.mercari.com

hack-it-iron.hatenablog.com

hack-it-iron.hatenablog.com

shinobu.apk #3

shinobu.apk #3ではAndroidエンジニアが語るAndroidのいいところ、好きなところ、オススメなところ」をメインテーマにディスカッションします!

これまでのshinobu.apkと同様で、当日のパネルディスカッションの内容は録音して後日公開する予定です。

上記をメインテーマとしてshinobu.apk #3では日々Androidと戯れ、Androidをこよなく愛する??3名の方々にパネルディスカッションしていただきます!

パネリストを引き受けていただいた方々圧倒的感謝です!!

shinobu.apk #3 パネリストの紹介

@muumuumuumuu

Androidの光と闇について語るのが好きなエンジニア。

あるいはビールをこよなく愛する人妻。

Android Nの🐱アプリかわいい。

@named_arguments

Androidアプリ開発が好きな霊長類。

好きなMockitoの定数はRETURNS_DEEP_STUBS。好きなポケモンヤドン

DozeはAndroidのServiceの自由を奪うと考えている電源消費推進派。

@wakwak3125

ちょっと前まで家具屋で「いらっしゃいませ」と言うことを生業としていたエンジニア

やきとりとビールが大好きです。

NougatがOTAで降ってこないので悲しんでいます。

モデレーター

私(@operandoOS)がやらせていただきます。

メインテーマの理由

なぜshinobu.apk #3ではAndroidエンジニアが語るAndroidのいいところ、好きなところ、オススメなところ」をメインテーマにしたかといいますと...

正直毎回そうなんですが...私が話を聞きたい人を集めたというのもあります!が...

自分が知らない、または聴いていただける方々がまだ知らないAndroidの良さを語り合えたらいいなーと思うわけです。

さらに、Androidのいいところや好きなところを語り合って、パネリストも聴いていただける方々もAndroidにさらに好きになってくれたら嬉しいなーとも思うわけです!

iPhone 7?? iOS 10?? そんなことよりAndroidだろ!Android Nだろ!」みたいな意気込みでディスカッションしていきたいですね!!

Androidのいいところについて語り合うためにもAndroidエンジニアが3人集まると、辛いって話をする(笑)」みたいなことにならないようにモデレーター頑張ります 💪

まとめ

shinobu.apk #3に少しでも興味がある方はぜひぜひ当日勉強会に参加していただけると非常に嬉しいです!!

もし参加できなくても、後日公開予定のパネルディスカッションの録音を聴いたりしていただけるだけでも嬉しいです!!

shinobu.apk #3もゆるく楽しく面白いディスカッションにしたいと思います!!

また、Androidエンジニアに限らずもっと色んなエンジニアさん達とAndroidについて色んな視点からディスカッションしたいと思ってますので、「Androidに物申したい!」という方がいらっしゃいましたら、ぜひぜひ私(@operandoOS)にお声がけいただけると嬉しいです!!

2016年 ぱないー まとめ(9/19時点

ハニーチュロとエンゼルクリーム率が高い...なるほど...

画像解析に使えるかも...w