TextInputLayoutのpassword visibility toggleを試してみた
Android support library 24.2.0からTextInputLayoutに追加されたpassword visibility toggleを試してみた。
試したサンプルコードはGithubにあげてあります。
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>
こんな感じで動きます!簡単ですね!!
もし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に設定されています。
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>
変更すると以下の感じでアイコンが変わります。
XMLの属性だけじゃなくてメソッドもちゃんとありますよ
今回のサンプルコードでは全てXMLの属性で指定してますが、ちゃんと属性とマッチしてるメソッドも用意されてます。
詳しくはTextInputLayoutのドキュメントを見てみてください。
今回は使用しませんでしたが属性も他にpasswordToggleTint
やpasswordToggleTintMode
があります。
自身のアプリのデザインに合わせてカスタマイズすると良さそうですね。
まとめ
デフォルトのデザインでいいのならTextInputLayoutでpassword visibility toggleを試すのはすごく簡単だったなー
support libraryでこういうのが増えてくれるのは独自で実装する部分が減るのでとても助かりますねー
ANDROID IDがどのように生成されているかざっくり調べた
悪名高い??ANDROID IDがどのように生成されているのか気になったのでざっくり調べた。
悪名高いと言われる闇の話は置いておいて....とりあえず生成方法だけざっくり調べた。
どのような手順で生成されるのか?という疑問はバージョンによって実装が異なるっぽかったので調べない。
ANDROID IDとは
ドキュメント見てもらえばわかるけどざっくり以下のようなもの。
- ランダムに生成される64ビットの数値を16進数文字列にしたもの
- 端末の最初の設定時に生成される。その後、ファクトリーリセットするまではその時に生成された値が常に取得できる
- ファクトリーリセットすることで値は再生成される
- 4.2以上でmultiple usersが導入され、ユーザごとにANDROID IDが生成される
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.java
のensureSecureSettingAndroidIdSetLocked
メソッドだね。
全体の処理は以下のような感じ。詳しくは見ないけどドキュメントどおり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"); } } }
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.toHexString
でANDROID 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(); } }
ちなみに、コードは割愛しますが2.3.7の実装はだいたい4.0.1と同じ。もちろんSecureRandom.nextLong
+ Long.toHexString
でANDROID IDが生成されてる。
その他のバージョンもざっくり見たけど、SecureRandom.nextLong
+ Long.toHexString
でANDROID 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。
どのようにAPKのサイズを小さくしたか
コードはGithub上に公開してある。読むほどの価値はない...🐱
具体的にAPKサイズのチューニングを行ったPull Requestは以下の2つ。
不要なリソースファイルを削除する
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%」というのがデフォルトの設定みたい。最適化しても品質は落ちさないというのは当たり前か。
んじゃ、その下にある「非可逆圧縮」の動作に変えて再度アプリアイコンを最適化してみた。
画像のサイズは小さくなるが、画像の品質が落ちるので適材適所ではあるが、ここは心を鬼にしてAPKのサイズを小さくすることに優先するぞ!
ぐぬぬ...🐱よ... ちょっと品質落ちるけどごめんなー!!という気持ち...
その結果、Release APKのサイズが21KBになった!!
最適化前のVersion 1のRelease APKのサイズが 34KBだったので、 34 - 21 = 13KBの削減だ。
最高だ🐱!!
21KBになったVersion 2のAPKをリリース
最高のアップデートだ🐱
まとめ
アプリの性質によってはリリースを限界まで削減できる。
コードをいじったり、削除したりで限界がきたら画像をImageOptim等で最適化してみるといい。
🐱最高!!
Androidについて語る! shinobu.apk #3 を10/5 (水)に開催します! #shinobuapk
はい、タイトルどおりshinobu.apk #3を開催するんですよ!!やたー(/・ω・)/やたー(/・ω・)/やたー(/・ω・)/
shinobu.apk #3のイベントページになります!
開催日は 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アプリを開発している人に聞きたい開発事情、個人アプリ開発に思うこと」をメインテーマにディスカッションしました。
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
ぱないのー pic.twitter.com/AyprkxN547
— shinobu.apk (@operandoOS) 2016年9月19日
ぱないのー🍩 pic.twitter.com/KLxEcCFjQi
— shinobu.apk (@operandoOS) 2016年9月4日
ぱないのー pic.twitter.com/VCQdA7r1xT
— shinobu.apk (@operandoOS) 2016年8月13日
ぱないのー pic.twitter.com/hnC120jKSk
— shinobu.apk (@operandoOS) 2016年7月29日
ぱないのー pic.twitter.com/zR4G7eco6w
— shinobu.apk (@operandoOS) 2016年7月3日
ぱないのー pic.twitter.com/rUkaXbpAOk
— shinobu.apk (@operandoOS) 2016年6月25日
ぱないのー pic.twitter.com/HnyYLxyG9I
— shinobu.apk (@operandoOS) 2016年6月18日
ぱないのー pic.twitter.com/CNgHL3ZkOL
— shinobu.apk (@operandoOS) 2016年5月7日
ぱないのー pic.twitter.com/y9Zc9BBFTS
— shinobu.apk (@operandoOS) 2016年4月29日
ぱないのー pic.twitter.com/qnBfxx0MLH
— shinobu.apk (@operandoOS) 2016年4月16日
ぱないのー pic.twitter.com/djlVYX10l9
— shinobu.apk (@operandoOS) 2016年3月27日
ぱないのー pic.twitter.com/dC7aMjXAFF
— shinobu.apk (@operandoOS) 2016年3月13日
ぱないのー pic.twitter.com/Egriq9iW2K
— shinobu.apk (@operandoOS) 2016年2月28日
ぱないのー pic.twitter.com/1cS6purPxP
— shinobu.apk (@operandoOS) 2016年2月27日
ぱないのー pic.twitter.com/fqOtRPe1lL
— shinobu.apk (@operandoOS) 2016年2月7日
ぱないの! pic.twitter.com/ddaa2DhGQh
— shinobu.apk (@operandoOS) 2016年1月28日