【Android】画像が押されたときの背景を簡単につける
ImageButtonを使えば簡単にできたので自分用にメモ。
<ImageButton android:id="@+id/ib_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/your_imgae" android:background="?android:selectableItemBackground" android:contentDescription="@string/your_image_desc" />
参考
Jenkinsのビルドの説明を自動的に設定する
Jenkinsのビルドでパラメータをつけてビルドするときに何のパラメータでビルドしたかいちいち確認するのが面倒なので自動化した。
まずパラメータに必要なビルドオプション(build_option)とビルドの説明(description)を入力できるようにする。
そしてパイプラインの最初でビルドの説明変更のAPIを叩く。
sh 'curl -s http://[YOUR_JENKINS_IP]:[YOUR_JENKINS_PORT]/job/[YOUR_JOB_NAME]/${BUILD_NUMBER}/configSubmit -X POST --data-urlencode "json={\'displayName\':\'#${BUILD_NUMBER}\', \'description\':\'${build_option}\\n${description}\'}"'
あとはビルド時に何のビルドかの説明を入力すれば・・・
自動的に説明欄に設定される。
参考
pycryptoのインストールがCentOS7.3 minimalで失敗する問題の対処
環境
[root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core)
結論
調査
デフォルトで入れようとすると以下ログでこける。Cコンパイラがないとのことなのでgccを入れる
[root@localhost ~]# pip install pycrypto ... configure: error: in `/tmp/pip-build-EJivFC/pycrypto': configure: error: no acceptable C compiler found in $PATH See `config.log' for more details ... Command "/usr/bin/python2 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-EJivFC/pycrypto/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().re place('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-WsN8Es-record/install-record.txt --single-version-externally-managed --compil e" failed with error code 1 in /tmp/pip-build-EJivFC/pycrypto/
[root@localhost ~]# yum install gcc
もう1回実行するとPython.hがないと言われる。調べた結果これはpython-develがないためとのことなので入れて解決。
... gcc -pthread -fno-strict-aliasing -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.7 -c src/MD2.c -o build/temp.linux-x86_64-2.7/src/MD2.o src/MD2.c:31:20: fatal error: Python.h: No such file or directory #include "Python.h" ^ compilation terminated. error: command 'gcc' failed with exit status 1 ---------------------------------------- Command "/usr/bin/python2 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-2l6kpU/pycrypto/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-7LFD3X-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-2l6kpU/pycrypto/
[root@localhost ~]# yum install python-devel
Android通知のバージョンごとのUIの違い
自分用にメモ。以下のコードを実行したときのAndroid OSバージョンごとのUIを調べた。
Intent intent = new Intent(context, MainActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); Notification notification = new NotificationCompat.Builder(context) .setAutoCancel(true) // Delete notification when user taps .setContentTitle("Test") .setTicker("ticker") // Message when notification shows for ~4.4 .setContentInfo("content info") .setContentText("content text") .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)) .setContentIntent(pi) .build(); NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); manager.notify(ID, notification);
- Android 4.4までは通知が表示されるときにTickerの文字が表示される。5.0以上では設定しても無視される。
- Android 5.0からはSmall IconがBig iconの右下に表示される。
- Android 7.0からはContent Infoが表示されない。
Notification | Ticker | |
---|---|---|
4.1 | ||
4.2 | ||
4.3 | ||
4.4 | ||
5.0 | ||
5.1 | ||
6.0 | ||
7.0 |
CircleCIでAndroid SDKとGradleをキャッシュする
CircleCIで普通にビルドしていると毎回Android SDKとGradleのダウンロードが行われてビルド時間が長くなってくる。CircleCIにはデフォルトのキャッシュ以外にも自分でキャッシュの設定ができるので、Android SDKとGradleをキャッシュすることでビルドを短くできる。~/.gradleはデフォルトでキャッシュされるようになっているようなので設定は不要。
dependencies: override: ... cache_directories: - /usr/local/android-sdk-linux/tools - /usr/local/android-sdk-linux/platforms/android-25 - /usr/local/android-sdk-linux/platforms/android-23 - /usr/local/android-sdk-linux/platforms/android-16 - /usr/local/android-sdk-linux/build-tools/25.0.2
キャッシュを使うかダウンロードするかの判定
tools, platforms/android-xxにはsource.propertiesというファイルがある。これにバージョンがPkg.Revision=25.2.5のように書かれているので、この値を見ることでキャッシュを使うかダウンロードするかを決める。build-toolsとGradleはフォルダがあるかどうかで判定する。
dependencies: override: - if ! $(grep -q "Pkg.Revision=25.2.5" $ANDROID_HOME/tools/source.properties); then echo y | android update sdk --no-ui --all --filter "tools"; fi - if [ ! -e $ANDROID_HOME/build-tools/25.0.2 ]; then echo y | android update sdk --no-ui --all --filter "build-tools-25.0.2"; fi - if ! $(grep -q "Pkg.Revision=3" $ANDROID_HOME/platforms/android-25/source.properties); then echo y | android update sdk --no-ui --all --filter "android-25"; fi - if ! $(grep -q "Pkg.Revision=3" $ANDROID_HOME/platforms/android-23/source.properties); then echo y | android update sdk --no-ui --all --filter "android-23"; fi - if ! $(grep -q "Pkg.Revision=5" $ANDROID_HOME/platforms/android-16/source.properties); then echo y | android update sdk --no-ui --all --filter "android-16"; fi - if [ ! -e ~/.gradle/wrapper/dists/gradle-3.5-all ]; then ./gradlew init; fi cache_directories: - /usr/local/android-sdk-linux/tools - /usr/local/android-sdk-linux/platforms/android-25 - /usr/local/android-sdk-linux/platforms/android-23 - /usr/local/android-sdk-linux/platforms/android-16 - /usr/local/android-sdk-linux/build-tools/25.0.2
注意点として先にAndroid SDKのアップデートをしないとGradleの初期化中にAndroid SDKの使用許諾が取れていなくて失敗する。
circle.yml
machine: java: version: openjdk8 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - if ! $(grep -q "Pkg.Revision=25.2.5" $ANDROID_HOME/tools/source.properties); then echo y | android update sdk --no-ui --all --filter "tools"; fi - if [ ! -e $ANDROID_HOME/build-tools/25.0.2 ]; then echo y | android update sdk --no-ui --all --filter "build-tools-25.0.2"; fi - if ! $(grep -q "Pkg.Revision=3" $ANDROID_HOME/platforms/android-25/source.properties); then echo y | android update sdk --no-ui --all --filter "android-25"; fi - if ! $(grep -q "Pkg.Revision=3" $ANDROID_HOME/platforms/android-23/source.properties); then echo y | android update sdk --no-ui --all --filter "android-23"; fi - if ! $(grep -q "Pkg.Revision=5" $ANDROID_HOME/platforms/android-16/source.properties); then echo y | android update sdk --no-ui --all --filter "android-16"; fi - if [ ! -e ~/.gradle/wrapper/dists/gradle-3.5-all ]; then ./gradlew init; fi cache_directories: - /usr/local/android-sdk-linux/tools - /usr/local/android-sdk-linux/platforms/android-25 - /usr/local/android-sdk-linux/platforms/android-23 - /usr/local/android-sdk-linux/platforms/android-16 - /usr/local/android-sdk-linux/build-tools/25.0.2 test: override: - ./gradlew assembleDebug - cp -r ~/$CIRCLE_PROJECT_REPONAME/app/build/outputs/apk/* $CIRCLE_ARTIFACTS # unit test - ./gradlew testDebugUnitTest - cp -r ~/$CIRCLE_PROJECT_REPONAME/app/build/test-results/testDebugUnitTest/* $CIRCLE_TEST_REPORTS deployment: master: branch: master commands: - ./gradlew assembleRelease
参考
https://circleci.com/docs/1.0/how-cache-works/https://discuss.circleci.com/t/installing-android-build-tools-23-0-2/924/6
Python3でSlackのステータスを変える
最近Slackにステータスの機能が実装された。ミーティング中や帰宅済みなど名前の横を見ればステータスがわかるようになって非常に便利になった。 https://get.slack.help/hc/ja/articles/201864558-Slack-%E3%81%AE%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B APIが公開されていてトークンがあればSlackの外から変更できる。 https://api.slack.com/methods/users.profile.set トークンの取得はこちらから https://api.slack.com/custom-integrations/legacy-tokens 以下はPython3でのコードになります。
環境
- python 3.6.0
- requests 2.13.0
コード
import requests import json import sys arguments = sys.argv text = arguments[1] emoji = arguments[2] url = "https://slack.com/api/users.profile.set" params = { "token": "your_token", "profile": json.dumps( { "status_text": text, "status_emoji": emoji } ) } headers = {"Content-Type": "application/json"} r = requests.get(url, params=params, headers=headers) print(r.url) print(r.text)
実行
python3 change_slack_status.py "In meeting" ":spiral_calendar_pad:"
【Android】jacocoでコードカバレッジを取る
追記
Kotlin対応
最近UTを書くようになってきたのでカバレッジを取ってみました。Gradleにjacocoのプラグインがあるのでそれを使います。
build.gradleはDroidkaigi2017のbuild.gradleを参考にしました。
apply 'jacoco' apply plugin: 'com.android.application' android { // Settings for Android... } jacoco { toolVersion = "0.7.7.201606060606" } // A list of directories which should be included in coverage report def coverageSourceDirs = ['src/main/java'] // A list of files which should be excluded from coverage report since they are generated and/or framework code def coverageExcludeFiles = ['**/R.class', '**/R$*.class', '**/com/android/**/*.*', '**/BuildConfig.class', '**/*Activity*.class', '**/*Fragment*.class', '**/*Receiver.class', '**/*Manifest*.class', '**/*Application*.class'] task jacocoTestReport(type: JacocoReport, dependsOn: ['testUiTestDebugUnitTest']) { group = "Reporting" description = "Generate Jacoco coverage reports after running tests." reports { xml.enabled true html.enabled true csv.enabled false xml.destination "${buildDir}/reports/jacoco/jacocoTestReport.xml" html.destination "${buildDir}/reports/jacoco/html" classDirectories = files( fileTree( dir: "${buildDir}/intermediates/classes/uiTest/debug", exclude: coverageExcludeFiles)) } sourceDirectories = files(coverageSourceDirs) executionData = files "${buildDir}/jacoco/testUiTestDebugUnitTest.exec" doLast { println "jacoco xml report has been generated to file://${buildDir}/reports/jacoco/jacocoTestReport.xml" println "jacoco html report has been generated to file://${reports.html.destination}/index.html" } } dependencies { // For dependencies... }
まずapply 'jacoco'でプラグインを適用します。そしてjacocoプラグインのバージョンを指定します。
jacoco {
toolVersion = "0.7.7.201606060606"
}
バージョンの一覧はここにあります。
次にコードカバレッジのレポートを作るタスクを作ります。 jacocoプラグインにはJacocoReportというレポートを作成するタスクがあります。jacocoの解析対象はバイトコードのため、UTのタスク(test(ProductFlavor)DebugUnitTest)と同時に実行させる必要があるので依存させます。私の場合はuiTestというProductFlavorでUTを実行しているので依存させるタスク名はtestUiTestDebugUnitTestになります。タスク名がわからなかったら./gradlew tasksで調べます。
task jacocoTestReport(type: JacocoReport, dependsOn: ['testUiTestDebugUnitTest']) {
}
あとはJacocoReportのページを参考に設定します。私の場合はActivityやFragment等のクラスはカバレッジに含めないようにしました。先ほど書いたようにjacocoの解析対象はバイトコードのため、reports.classDirectoriesにはビルド後のパスを設定します。executionDataのパスは"${buildDir}/jacoco/test(ProductFlavor)DebugUnitTest.exec"となるようです。
// A list of directories which should be included in coverage report def coverageSourceDirs = ['src/main/java'] // A list of files which should be excluded from coverage report since they are generated and/or framework code def coverageExcludeFiles = ['**/R.class', '**/R$*.class', '**/com/android/**/*.*', '**/BuildConfig.class', '**/*Activity*.class', '**/*Fragment*.class', '**/*Receiver.class', '**/*Manifest*.class', '**/*Application*.class'] task jacocoTestReport(type: JacocoReport, dependsOn: ['testUiTestDebugUnitTest']) { group = "Reporting" description = "Generate Jacoco coverage reports after running tests." reports { xml.enabled true html.enabled true csv.enabled false xml.destination "${buildDir}/reports/jacoco/jacocoTestReport.xml" html.destination "${buildDir}/reports/jacoco/html" classDirectories = files( fileTree( dir: "${buildDir}/intermediates/classes/uiTest/debug", exclude: coverageExcludeFiles)) } sourceDirectories = files(coverageSourceDirs) executionData = files "${buildDir}/jacoco/testUiTestDebugUnitTest.exec" }
結果は↓のような感じ
これでjacocoによるコードカバレッジが取れるようになりました。 次はCircleCIとCodecovを連携させてコードカバレッジをGitHubのREADMEに表示する方法について書きたいと思います。