2015年4月30日木曜日

CheckBoxの再利用

CheckBoxの再利用

CheckBoxを作成&使用して、その後、そのオブジェクトを再利用したい場合があるかもしれない。
2回目の使用時にも、setCheckedメソッドを使ってチェックを付けるのである。

このsetCheckedメソッドであるが、setOnCheckedChangeListenerメソッドを実行してしまった後で、setCheckedメソッドを実行すると、onCheckedChangedメソッドが呼ばれてしまう。
2回目の使用時に、そうなってしまった場合、不都合が生じる場合が有る。

Windowsにおいても、似た仕掛けがあるが、Windowsの場合には、onCheckedChangedメソッドに「端末利用者がチェックを施したのか」「プログラムでチェックを施したのか」がわかる引数が付いている。
Androidの場合には、そういう引数は無い。

このため、setCheckedメソッドを実行する直前に、setOnCheckedChangeListener(null)を実行させれば良い。setCheckedメソッドを実行させた後で、setOnCheckedChangeListenerを再設定し直せば良い。

2015年4月19日日曜日

無料版の構築エラー

無料版の構築エラー

1個のプロジェクトで、無料版と有料版を構築している。
無料版のデバッグをしようとして、実行をさせようとするが、「無料版の実行形式ファイルがありません」という趣旨のエラーが出る。
そうすると、普通は、無料版関係について、あれこれイジリ回しますよね。

この場合、たぶん、有料版の実行形式ファイルが存在しないのである。このため、有料版の実行形式ファイルを、Build>Clean Projectコマンドを使って作れば良い。

そうすれば、無料版のデバッグができる。むむむ!

開発環境:Android Studio

2015年4月13日月曜日

AndroidLintIconMissingDensityFolder

AndroidLintIconMissingDensityFolder

Android Studio>Analyze>Inspect Code...

下記のエラーが出ることが有る。
AndroidLintIconMissingDensityFolder
Missing density folder
Icons will look best if a custom version is provided for ...

解決方法
主モジュール及び副モジュール(ライブラリ)の両方のresフォルダーに下記7個のフォルダーをダミーで設ければ良い。
drawable
mipmap-hdpi
mipmap-ldpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi

drawable-*系のフォルダーは削除しても良い。
ライブラリ側のresフォルダーにもダミーで設けるってことが肝要ですね。
画像ファイルは入れておかなくても良い。
これに伴い、主モジュールのAndroidManifest.xmlのアイコンに関して次のように書き換えます。
android:icon="@mipmap/ic_launcher"

ちなみに、「mipmap」では無く「drawable」で置き換えた場合、別途、「アイコンのサイズが異なります」という趣旨のエラーが発生します。

2015年4月11日土曜日

if statement can be simplified

if statement can be simplified

私は下記のコードを好んで使っておった。

        String s = "aaa";
        if(s==null
        || s.equals("bbb")) return false;//ここに否定形を列挙していく。
        else return true;//生き残ったのが真実

お気に入りの書き方だった。
すると、Analyze>Inspect Code...において、if statement can be simplifiedという注意を受けた。
これをどうすれば単純化できるのかね。
解答は次のとおりです。

        String s = "aaa";
        return s!=null && s.equals("bbb");

パズルみたいですな。
死なせるべき否定形を列挙していくのではなく、生き残らせるべきものを条件制約していく、ということですな。

ダメなことを列挙すれば無限にあるが、真実は1個しかない。真実を見つめて進みましょう。それが前向きであり、最適です。って、人生哲学がJavaのコーディングから導かれるんだね。

(参考)

Android Plugin for Gradle

Android Plugin for Gradle

「Android Plugin for Gradle」と「Build System」とは、別名ではあるものの同じものを指しているのですね。何も知らない者から見ると、別名で表現されると、ややこしいですね。

Android Plugin for Gradle Release Notes...このページに有る、「Android Plugin for Gradle, Revision *.*.* (* *)」を見て、最新のRevisionを確認します。

Android StudioのメニューでFile>Project Structure...を選択します。
Project Structure画面の「Project」をクリックします。
右側に「Android Plugin Version」欄があるので、そこに、上記Revisionを書き込みます。
このやり方では無く、ルートに存在するbuild.gradleファイル内に次のように書いても良いです。
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.3'
    }
}
むむむ!ここでは「tools」って用語を使ってますな。普通は術語を統一するんじゃないのか。

上記はAndroid Studioにおいて、Gradleを使いこなす道具の設定ですね。
次に、Gradleのバージョンの設定も行います。

Gradleのサイトに最新のがあるようです。詳細を観ようとすると、セキュリティの
関係で閲覧できないという趣旨の画面が出ます。残念ですね。
Android Studioにおいては、次のメッセージが出てアプリの作成が拒否られます。
Error:No subject alternative DNS name matching services.gradle.org found.

止むを得ないので、最新のバージョンであるgradle-2.3-all.zipをダウンロードして任意のフォルダーに展開します。
File->Settings...で「Settings...」画面を表示させます。
「Gradle」の「Use default Gradle wrapper(recommended)」では無く、「Use local gradle distribution」にチェックをしまして、先ほど展開したフォルダーを設定します。
また、File>Project Structure...>Project Structure画面>「Project」>Gradle version欄を「2.3」にする。
recommendedされている方式は、ネットに情報を取りに行くようですね。

2015年4月13日現在、2.3にすると、gradleファイル内の項目に下線が引かれてしまう等の異常が発生します。2.2.1にすると問題はありません。

ちなみに私は下記の趣旨のエラー群で苦しんでいました。
Error Gradle DSL method not found compileOptions()
The project may be using a version of Gradle that does not contain the method.
Open Gradle wrapper file The build file may be missing a Gradle plugin.
Apply Gradle plugin
dependencies cannot be applied to groovy lang Closure

Googleにおける解説記事よりも、stackoverflowの記事の分量の方が多いような気がするのは、果たして私だけだろうか。
Gradleの道は険しいですね。みなさん、がんばってください。

(参考)
Android Tools Project Site
Gradle Plugin User Guide
Gradle Distributions
Error:(1, 0) Plugin with id 'com.android.application' not found
buildTypes cannot be applied to groovy.lang.Closure
Getting error “Gradle version 1.10 is required. Current version is 1.12.” when executing “gradle wrapper”?
Gradle sync error in Android studio when importing project

2015年4月10日金曜日

image varies significantly

image varies significantly
The image *.png varies significantly in its density-independent (dip) size across the various density versions
多分、EclipseからAndroid Studioにプロジェクトを移植した場合、上記の文言がinspection resultとして表示されるかもしれない。
放置しても問題は無いようである。
解決方法としては、Android Studioにおいて、空のプロジェクトを新規に生成して、そこにあるresourceのdrawableフォルダーにあるファイル関係を参考にしながら、自分のアプリのプロジェクトを構築すれば良い。例えば、mipmap-hdpiという名前のフォルダーを作成して、そこに画像ファイルを入れれば良い。
AndroidManifest.xml内の、アイコンを使用しているフォルダー名も書き換えることになる。

(参考)
Image varies significantly in its density-independent (dip) size

2015年4月9日木曜日

恐怖のPower Save Mode

恐怖のPower Save Mode

Android Studioのエディタにおいて、赤色のエラーが表示されなくなった。原因不明で、アンインストールを2回行い、Settings...を何度も見直し、問題解決を試みたが解決しなかった。

原因はFile->Power Save Modeであった。これにチェックしていると、赤色のエラーが表示されなくなる。

Android Studioはコマンド数が多すぎる。Power Save Modeは削除して欲しい。

2015年4月7日火曜日

Calendar.AM_PM

Calendar.AM_PM

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
if(cal.get(Calendar.AM_PM)==Calendar.AM){
    rgAMPM.check(R.id.Radio_NumericPad_AM);
}
else{
    rgAMPM.check(R.id.Radio_NumericPad_PM);
}

2015年4月5日日曜日

IabHelper#queryInventoryAsync()

IabHelper#queryInventoryAsync(boolean, List<String>, Listener)

第一番目の引数 boolean
trueの場合、消費されたアイテム及び消費されてないアイテムの両方を取得する。
falseの場合、消費されたアイテムだけを取得する。

第二番目の引数 List<String>
取り扱っている商品群を代入する。
この値がnullの場合、取り扱っている商品のうち消費された商品だけが取得される。
この値に取り扱っている商品群を代入しておくと、その商品が消費されていない状況が、Inventory#hasDetails()等を併せ使うことにより、明確に判明する。
管理者は商品の全てを把握しているため、消費されていない商品群を把握する必要は無いが、商品を新規に登録した場合、本当に登録が完了したのかどうか確認したいものである。
売れ残っている商品を顧客に提示する目的でも使う。

第三番目の引数 QueryInventoryFinishedListener
リスナーです。

queryInventoryAsync(Listener)の場合、queryInventoryAsync(true, null, listener)として取り扱われ、消費された商品だけが取得されます。

2015年4月3日金曜日

License Verification Library (LVL) のVT

License Verification Library (LVL) のVT

ServerManagedPolicyでLVLを実装して動かしてみると、VT(Validity Timestamp、有効期間)の値(long型)がLong.MAX_VALUEになっていた。

これは、期間の定めが無く、いつまでも有効であることを意味している。
つまり、検査をするのは最初の1回だけであって、2回目以降は検査をしないということである。2回目以降は検査のためにネットへ接続はしないということであるので、インターネットへの接続を必要としないアプリであっても効果があるということである。

端末利用者にアプリをGoogle Playからダウンロードしてもらった後、ネットに接続している時に、アプリを1回起動して貰えれば検査は完了するのである。

以上がServerManagedPolicyの振る舞いであるが、常時インターネットに接続するアプリであれば、StrictPolicyを使うことを検討しても良い。もちろん、アプリを起動する度にインターネット経由で検査をするので、その分、遅くなるが。

Licensing Referenceに詳しい情報がある。
Table 1のCategoryがLicense check and result及びPolicyとして掲げられたName欄のクラスを必要に応じて適宜変更することになる。
CategoryがLibrary core, no integration neededとして掲げられたクラスは変更をする必要はない。例えば、ILicensingService.javaの冒頭には次のように書かれてある。
This file is auto-generated.  DO NOT MODIFY. Original file: aidl/ILicensingService.aidl
Table 2はGoogle Play serverが返してくる値をまとめた一覧である。基本はResponse Code欄にある値を参照すれば良い。Extras欄の意味は、「Server Response Extras」に説明が書かれている。
ExtrasはServerManagedPolicyでは実装している。
Policyとは、ServerManagedPolicy又はStrictPolicyの基底です。ServerManagedPolicyはひな形としてはGoogleが提供していますが、プログラマが適宜自己責任で改修を行い使うこととなっている、と思います。

以下は私なりの日本語訳です。

License validity period(ライセンス有効期間)

The Google Play licensing server sets a license validity period for all downloaded applications. The period expresses the interval of time over which an application's license status should be considered as unchanging and cacheable by a licensing Policy in the application.

Google Play licensing serverは、すべてのダウンロードされたアプリケーションのライセンスの有効期間を設定します。この期間は、アプリケーションでのライセンスPolicyに基づき、アプリケーションのライセンスの状態が
「不変であり」かつ「キャッシュが可能である」と考えられる時間間隔を表現しています。

The licensing server includes the validity period in its response to all license checks, appending an end-of-validity timestamp to the response as an extra under the key VT.

licensing serverは、ライセンス検査への応答の中に有効期間に関するデータを含めており、extraの「VT」というキーの中に、有効期間の最終日時のデータが有ります。

A Policy can extract the VT key value and use it to conditionally allow access to the application without rechecking the license, until the validity period expires.

Policyは、有効期間が満了するまで、ライセンスを再検査することなく、VTの値を、条件付きで、アプリケーションへのアクセスを許可するために使用することができます。

The license validity signals to a licensing Policy when it must recheck the licensing status with the licensing server.

ライセンス期間というものは、ライセンスPolicyがライセンスサーバーを使ってライセンス状態を再検査しなければならない時を示しています。

It is not intended to imply whether an application is actually licensed for use.

これは、アプリケーションが実際に使用が許可されているかどうかを意味するものではありません。

That is, when an application's license validity period expires, this does not mean that the application is no longer licensed for use 

それは、アプリケーションのライセンス有効期間が満了したとき、アプリケーションの使用が不許可になったことを意味しません。

rather, it indicates only that the Policy must recheck the licensing status with the server.

むしろ、それは、Policyはサーバを使ってライセンスの状態を再検査しなければならない、ということだけを示します。

It follows that, as long as the license validity period has not expired, it is acceptable for the Policy to cache the initial license status locally and return the cached license status instead of sending a new license check to the server.

つまり、ライセンスの有効期間が満了していない限り、Policyは、初期のライセンスのデータをローカルにキャッシュすること、そして(サーバにライセンスの検査を行わせるのではなく)キャッシュされたライセンスのデータを使うこと、が可能です。

The licensing server manages the validity period as a means of helping the application properly enforce licensing across the refund period offered by Google Play for paid applications. 

有料アプリケーションのために、アプリケーションが適切にライセンスを実施する手段として、ライセンスサーバーは有効期間を管理します。(acrossの意味不明)

It sets the validity period based on whether the application was purchased and, if so, how long ago. Specifically, the server sets a validity period as follows:

アプリケーションが購入されたかどうか、どのくらい前なのか、に基づいて有効期間を設定します。サーバが有効期間を設定するのは具体的には以下のとおりです。

●For a paid application, the server sets the initial license validity period so that the license response remains valid for as long as the application is refundable. A licensing Policy in the application may cache the result of the initial license check and does not need to recheck the license until the validity period has expired.

●有料アプリのために、サーバは初期のライセンスの有効期間を設定します。それにより、アプリが返金可能である限りは、ライセンスのレスポンスは有効の状態を維持し続けます。アプリケーションにおけるライセンスPolicyは、初期のライセンスチェックの結果をキャッシュすることができるし、有効期間が満了するまで、ライセンスを再検査する必要はありません。

●When an application is no longer refundable, the server sets a longer validity period — typically a number of days.

●アプリケーションがもはや払い戻しできない場合は、サーバは長い有効期間 - 通常は数日 を設定します。

●For a free application, the server sets the validity period to a very high value (long.MAX_VALUE). This ensures that, provided the Policy has cached the validity timestamp locally, it will not need to recheck the license status of the application in the future.

●無料のアプリケーションのために、サーバーは非常に高い値(Long.MAX_VALUE)を有効期間として設定します。これは、
Policyがローカルに有効期間に関するデータをキャッシュしてしまうことを保証します。今後ずっとアプリケーションのライセンスステータスを再検査する必要はありません。


2015年4月1日水曜日

License Verification Library (LVL)

License Verification Library (LVL)

App Licensing
Android LVL を使う - Securing Android LVL Applications -
Android Application Licensing
LVL (License Verification Library) を使ってみた
Google Play の Licensing サービスを使う
LVL(License Verification Library)の導入
Anti AntiLVL - AntiLVL への簡単な対抗方法について考えてみる
Android 5.0 で LVL が正常動作しない問題の対処

ServerManagedPolicyは、飛行機に乗っている時のように、オフラインで端末を使っている時でも取り扱えるような、規約を定めます。
StrictPolicyは、サーバーとのやり取りをする時だけしか動作しないような規約を定めます。オフラインでは動作しません。
どのように使うのかを、プログラマーは、適宜判断をして、LVLのソースコードを書き換えて使用します。

Licensing Overviewには、次のとおり書かれています。
Google Play considers a user to be licensed if the user is a recorded purchaser of the application.
また、Requirements and Limitationsには、次のとおり書かれています。
You can implement licensing controls for a free app, but only if you're using the service to provide APK expansion files.
LVLは有料アプリで使うのですね。