2014年12月20日土曜日

Android Studioで開発効率をアップしてくれるPlugins

Android Layout ID Converter

レイアウトxmlファイルからandroid:idを抽出して、findViewByIdを楽々コピペしてくれるPluginです。
詳しくは作成者さまの動画をご覧ください。



Android Parcelable code generator

データクラスを簡単にParcelable化してくれるPluginです。
https://github.com/mcharmas/android-parcelable-intellij-plugin/

※随時、更新予定

Android StudioでVolleyを使用するための設定方法

Volleyについて

Volleyは簡単に素早くネットワーク処理を実装することができるHTTPライブラリです。次のような利点があります。

  • ネットワークリクエストの自動スケジューリング
  • 多重同時ネットワーク通信
  • メモリを使用したリクエストのキャッシュ機能
  • リクエストの優先順位をサポート
  • キャンセルリクエストAPI
  • ネットワークから非同期にデータのフェッチを必要とするUIに正確に行う
  • デバッグ機能

[*1] Transmitting Network Data Using Volley: http://developer.android.com/training/volley/index.html

Volleyのセットアップ

VolleyライブラリはAOSPのframeworks/volleyに公開されています。現時点では、このリポジトリからソースをダウンロードして、Android Studioのワークスペースに組み込みます。

1
git submodule add https://android.googlesource.com/platform/frameworks/volley modules/volley

git submoduleコマンドにより、プロジェクトのサブモジュールとしてmodules/volleyに格納します。以後、volleyサブプロジェクトを更新する場合は次のコマンドを実行します。

1
git submodule update

setting.gradleにVolleyライブラリを追加

1
2
include ':app'
+include ':modules:volley'

アプリケーションのbuild.gradleのdependeciesにVolleyライブラリを追加

1
2
3
4
5
6
dependencies {
     compile 'com.android.support:support-v4:19.1.0'
     androidTestCompile 'com.android.support:support-v4:19.1.0'
     androidTestCompile 'com.android.support:support-v4:19.1.0'
+    compile project(':modules:volley')
 }

上記の設定を終えたら、Sync Project with Gradle Filesを実行してビルドを行います。

Android Studioのプロジェクトをgit cloneした際、git submoduleの更新も忘れない

Android Studioのプロジェクトをgit cloneした際、以下のエラーが出力され困ったときのメモです。
1
Error: Configuration with name 'default' not found

原因はVolleyライブラリをgit submoduleで使用していて、submoduleの設定を忘れてしまいがちなのでメモとして残します。

Android Studioのプロジェクトをgit cloneした後、git submoduleを再設定します。
1
2
git submodule init
git submodule update

submoduleを再設定することでエラーは解消されました。

2014年11月23日日曜日

Android 5.0(マテリアルデザイン) ActionBarの背景色をカスタマイズする

査読必須サイト

I/O 2014 アプリに学ぶマテリアルデザイン
Customize the Color Palette
Google本家のスタイルガイド


各パーツと要素の指定


以下、各パーツと要素名です。style.xmlにて各要素の色を指定します。


AppCompat使用時の指定

次はStatsuBarとActionBarの背景色を指定するサンプルです。styles.xmlに記載しました。

1
2
3
4
5
6
7
8
9
10
11
<resources>
 
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
 
        <!-- your app branding color for the app bar -->
        <item name="colorPrimary">@color/primary</item>
        <!-- darker variant for the status bar and contextual app bars -->
        <item name="colorPrimaryDark">@color/primary_dark</item>
    </style>
 
</resources>

AppCompatを使用時は「name="android:colorPrimary"」でないことに注意してください。


サンプル画面

次のようにcolor.xmlに定義を追加してみました。
色はGoogle本家のスタイルガイド
から適用しました。

1
2
3
4
5
6
7
<resources>
 
    <!-- Material -->
    <color name="primary">#4caf50</color>
    <color name="primary_dark">#388e3c</color>
 
</resources>



StatsuBarとActionBarの背景色がマテリアルデザインっぽくなりました。

Android Studioのコードフォーマッタを設定する

チーム開発を行う場合、フォーマッタは重要です。
メンバー全員のフォーマッタを統一しないとソース管理で痛い目にあいます。

AOSPのCodeStyleを使用する

AOSPにAndroid用のCodeStyleがアップされています。
こちらからDLしましょう。
https://android.googlesource.com/platform/development/+/master/ide/intellij/codestyles/

AndroidStyle.xmlを以下のディレクトリに格納します。
(Windowsの場合)
C:\Users\[USER_NAME]\.AndroidStudioBeta\config\codestyles

(Macの場合)
~/Library/Preferences/AndroidStudio/codestyles
Android StudioのFile->Settingsから設定を行います。



Eclipse Code Formatterを使用する

Eclipseと共存で開発をする場合、フォーマッタを統一しましょう。(ソース管理上のトラブルを防ぐため)
Pluginsから「Eclipse Code Formatter」をインストールします。




File - Settings - Eclipse Code Formatterを開いて設定を行います。




2014年7月27日日曜日

ViewFlipperの自動フリップのフリップタイミングをハンドリングする

ViewFlipperの自動フリップで、フリップタイミングをハンドリングする方法です。
ViewFlipperクラスは、フリップタイミングを直接ハンドリングするリスナーが用意されていません。
そのため、VewFlipper#getInAnimation()でインアニメーションを制御するAnimationクラスを取得し、このクラスにリスナーをセットします。


プログラムはこんな感じ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 
    View view = inflater.inflate(R.layout.fragment_flashing_card, null);
    mVewFlipper = (ViewFlipper) view.findViewById(R.id.viewFlipper1);
 
    mVewFlipper.setAutoStart(true);
    mVewFlipper.setInAnimation(getActivity(), android.R.anim.slide_in_left);
    mVewFlipper.getInAnimation().setAnimationListener(this);
    mVewFlipper.setFlipInterval(2000);
 
    return view;
}
 
@Override
public void onAnimationEnd(Animation animation) {
}
 
@Override
public void onAnimationRepeat(Animation animation) {
}
 
@Override
public void onAnimationStart(Animation animation) {
}

2014年7月3日木曜日

AOSPのl-preview branchをビルド

AOSPにてl-previewのbranchができたので、さっそくビルドしてみました。
注意点としては、次の1点のみ。
 ・OpenJDK 1.7がMUST (oracle-JDK1.7だとビルド開始できず)


Corei7、メモリ10G、VM環境でビルド時間はこんな感じです。Kitkatよりも時間がかかりました。

real 83m16.785s
user 504m10.589s
sys 56m52.913s


参考までに。

2014年3月30日日曜日

SwipeRefreshLayoutを使ってSwipe更新を実装する

Layoutの作成

レイアウトはandroid.support.v4.widget.SwipeRefreshLayoutを使用します。
コンテンツはSwipeRefreshLayoutの子Viewとして記述します。

1
2
3
4
5
6
7
8
9
10
11
12
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_refresh_widget"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
     
    <!-- some full screen pullable view that will be the offsetable content -->
 
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/content"/>
</android.support.v4.widget.SwipeRefreshLayout>


Swipeによる更新

Swipeによる更新は次のように行います。
1. 更新開始タイミングをハンドルするために、setOnRefreshListenerメソッドにリスナーをセット
2. onRefresh()で更新開始をハンドリング
3. 更新処理が終わったら、setRefreshing(false)をコールする


1
2
3
4
5
6
7
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.sample_swipe_refresh_widget);
 mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget);
 mSwipeRefreshLayout.setOnRefreshListener(this);
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void onRefresh() {
 refresh();
}
 
private void refresh() {
 Message msg = mHander.obtainMessage(0, this);
 mHander.sendMessageDelayed(msg, 1000);
}
 
private static Handler mHander = new Handler() {
 @Override
 public void handleMessage(Message msg) {
  SwipeRefreshLayoutActivity activity = (SwipeRefreshLayoutActivity) msg.obj;
  activity.mSwipeRefreshLayout.setRefreshing(false);
 }
};

2014年3月3日月曜日

GeoFenceの解除

GeoFenceの解除は次のような手順で行います。

1. LocationClientクラスのconnectメソッドをコールして、Location Serviceに接続
2. 接続完了後、removeGeofencesメソッドをコールして、GeoFenceを解除
3. 解除結果はOnRemoveGeofencesResultListenerリスナーで受け取る

removeGeofencesメソッドは2種類あり、GeoFenceのIDを指定(リクエストID)するメソッドとPendingIntentを指定するメソッドがあります。

1
2
3
4
5
public void removeGeofences(List<String> geofenceRequestIds,
                            LocationClient.OnRemoveGeofencesResultListener listener)
 
public void removeGeofences(PendingIntent pendingIntent,
                            LocationClient.OnRemoveGeofencesResultListener listener)


次はGeoFenceのIDを指定(リクエストID)して解除を行うプログラムです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void onConnected(Bundle bundle) {
    super.onConnected(bundle);
 
    Bundle fragmentBundle = getArguments();
    ArrayList<GeoFenceData> list = fragmentBundle.getParcelableArrayList(GEOFENCE_DATA);
 
    List<String> idList = new ArrayList<String>();
    for (GeoFenceData data : list) {
        idList.add(data.getId());
    }
 
    getLocationClient().removeGeofences(idList, mOnRemoveGeofencesResultListener);
 
}


指定するクラスにより、OnRemoveGeofencesResultListenerリスナーの呼ばれるメソッドが異なります。

メソッド内容
onRemoveGeofencesByPendingIntentResultGeoFenceのID指定による削除用
onRemoveGeofencesByRequestIdsResultPendingIntent指定による削除用


次はonRemoveGeofencesByRequestIdsResultメソッドで結果を受け取るプログラムです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private OnRemoveGeofencesResultListener mOnRemoveGeofencesResultListener = new OnRemoveGeofencesResultListener() {
 
    @Override
    public void onRemoveGeofencesByPendingIntentResult(int statusCode,
            PendingIntent pendingIntent) {
        // TODO Auto-generated method stub
 
    }
 
    @Override
    public void onRemoveGeofencesByRequestIdsResult(int statusCode, String[] geofenceRequestIds) {
        switch (statusCode) {
            case LocationStatusCodes.SUCCESS:
                Toast.makeText(getActivity(), "LocationStatusCodes.SUCCESS", Toast.LENGTH_LONG)
                        .show();
                break;
            case LocationStatusCodes.GEOFENCE_NOT_AVAILABLE:
            case LocationStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
            case LocationStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
            case LocationStatusCodes.ERROR:
                break;
            default:
                break;
        }
        mLocationClient.disconnect();
        mOnGeoFenceRemoverInterface.onGeoFenceRemoved();
    }
 
};

2014年3月2日日曜日

GeoFenceの登録

GeoFenceの登録は次のような手順で行います。

1. LocationClientクラスのconnectメソッドをコールして、Location Serviceに接続
2. 接続完了後、addGeofencesメソッドをコールして、GeoFenceを登録
3. 登録結果をOnAddGeofencesResultListenerリスナーのonAddGeofencesResultメソッドで受け取る


GeoFenceのデータを生成する

addGeofencesメソッドの引数にセットするGeoFenceデータを生成します。データ生成はGeofence.Builderクラスを使用します。(※GeoFenceDataクラスはアプリケーション内に定義したデータクラス)

1
2
3
4
5
6
7
8
9
10
11
static public Geofence toGeofence(GeoFenceData data) {
    Builder builder = new Geofence.Builder();
 
    builder.setRequestId(data.getId());
    builder.setTransitionTypes(data.getTransition());
    builder.setCircularRegion(data.getLatitude(), data.getLongitude(),
            data.getRadius());
    builder.setExpirationDuration(data.getExpiration());
 
    return builder.build();
}

Geofence.Builderクラスには次のようなセッターがあります。

表1.1: Geofence.Builderクラスの主なセットモジュール

メソッド内容
setCircularRegionGeoFenceの領域を指定
setExpirationDuration有効期間を指定(自動的に削除されるまでの時間)、自動削除をしない場合はNEVER_EXPIREを指定
setLoiteringDelayGeoFence指定領域に入ってから留まると判定するまでの時間(ms)を指定
setNotificationResponsivenessGeoFenceから通知を受ける際の応答性
setRequestIdGeoFenceのIDを指定
setTransitionTypestransition typesの指定

表1.2: Geofence.Builderクラスの主なセットモジュール

メソッド内容
GEOFENCE_TRANSITION_DWELL GeoFence指定領域に入って留まる
GEOFENCE_TRANSITION_ENTER GeoFence指定領域に入る
GEOFENCE_TRANSITION_EXIT GeoFence指定領域から出る

GEOFENCE_TRANSITION_DWELLをセットする場合、GeoFence指定領域に入ってから留まると判定するまでの時間を、setLoiteringDelayメソッドで指定する必要があります。



GeoFenceの登録をする

LocationClientクラスのconnectメソッドをコールし、Location Service接続後、LocationClientクラスのaddGeofencesメソッドを使用してGeoFenceを登録します。

1
2
3
4
5
6
7
8
9
10
11
12
public void onConnected(Bundle bundle) {
    super.onConnected(bundle);
 
    Intent intent = new Intent(getActivity(), ReceiveTransitionsIntentService.class);
    mPendingIntent = PendingIntent.getService(
            getActivity(),
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
 
    getLocationClient().addGeofences(mGeofences, mPendingIntent, mOnAddGeofencesResultListener);
}

第2引数に、GeoFence指定領域に対しトランザクションが発生した場合に発行するPendingIntentをセットします。第3引数に、登録結果を受け取るOnAddGeofencesResultListenerリスナークラスをセットします。



登録の結果を受け取る

OnAddGeofencesResultListenerリスナークラスの例です。登録結果はstatusCodeから判定できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private OnAddGeofencesResultListener mOnAddGeofencesResultListener = new OnAddGeofencesResultListener() {
 
    @Override
    public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {
        switch (statusCode) {
            case LocationStatusCodes.SUCCESS:
                break;
            case LocationStatusCodes.GEOFENCE_NOT_AVAILABLE:
            case LocationStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
            case LocationStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
            case LocationStatusCodes.ERROR:
                break;
            default:
                break;
        }
        mLocationClient.disconnect();
    }
 
};


GeoFenceの通知

LocationClientクラスのaddGeofencesメソッドをコールする際、PendingIntentをセットしました。このPendingIntentをアプリケーションで受け取ります。次はIntentServiceで受け取る例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class ReceiveTransitionsIntentService extends IntentService {
 
    public ReceiveTransitionsIntentService(String name) {
        super(name);
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
        if (LocationClient.hasError(intent)) {
 
            int errorCode = LocationClient.getErrorCode(intent);
            android.util.Log.e("ReceiveTransitionsIntentService",
                    "Location Services error: " +
                            Integer.toString(errorCode));
        } else {
            int transitionType =
                    LocationClient.getGeofenceTransition(intent);
            List<Geofence> geofences = LocationClient.getTriggeringGeofences(intent);
 
            switch (transitionType) {
                case Geofence.GEOFENCE_TRANSITION_ENTER:
                    break;
                case Geofence.GEOFENCE_TRANSITION_EXIT:
                    break;
                default:
                    break;
 
            }
 
        }
 
    }
}

2014年2月20日木曜日

位置情報取得に利用するLocationClient

位置情報を取得するにはLocationManagerが提供されていますが、GPSとWiFiの設定に依存してLocationProviderの切り替えが必要でした。Google Play services APKが提供するLocation Serviceを使用すれば、Providerを考慮することなく位置情報を取得することができます。



Permissionの設定

Location Serviceを使用すには、AndroidManifest.xmlにPermissionの記載が必要です。LocationManagerと同様に、位置情報の精度に応じてPermissionが異なります。

1
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
1
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>


LocationClientの接続

Location Serviceを使用するには、LocationClientクラスの生成が必要です。

1
2
mLocationClient = new LocationClient(this, mConnectionCallbacks,
   mOnConnectionFailedListener);

第2引数にConnectionCallbacksインターフェイス、第3引数にOnConnectionFailedListenerインターフェイスをセットします。ConnectionCallbacksインターフェイスは、LocationClientがLocation Serviceに接続 / 切断した際にコールされます。OnConnectionFailedListenerは何らかのエラーが発生した場合にコールされます。

LocationClientの接続要求はLocationClient#connectメソッドをコールします。

1
2
3
4
5
6
7
8
9
@Override
protected void onStart() {
    super.onStart();
    if (isGooglePlayServicesAvailable()) {
        if (!mLocationClient.isConnected()) {
            mLocationClient.connect();
        }
    }
}

接続に成功すると、mConnectionCallbacks#onConnectedがコールされます。



LocationRequestの生成

LocationClientの接続が成功した後に、requestLocationUpdatesメソッドをコールし位置情報の取得要求を行います。

1
2
3
4
@Override
public void onConnected(Bundle bundle) {
    mLocationClient.requestLocationUpdates(mLocationRequest, mLocationListener);
}

第1引数にLocationRequestクラスを、第2引数にLocationListenerインターフェイスをセットします。LocationRequestクラスは次のようなセットモジュールを提供します。

メソッド内容
setInterval位置情報の更新間隔をmsで指定
setPriorityプライオリティ(精度)の指定
setExpirationDuration要求の期間(動作時間を)msで指定
setFastestInterval位置情報の最速更新間隔をmsで指定
setSmallestDisplacement最小移動距離をmで指定(指定メートル移動したら更新)


位置情報の取得

位置情報はmLocationListener#onLocationChangedメソッドにてAndroid OSから受け取ります。位置情報はLocationクラスとして取得します。

1
2
3
4
5
6
7
private LocationListener mLocationListener = new LocationListener() {
 
    @Override
    public void onLocationChanged(Location location) {
    }
 
};


LocationClientの停止

位置情報の更新を停止するには、LocationClientクラスのremoveLocationUpdatesメソッドをコールしリスナーを解除します。続けて、disconnectメソッドをコールしLocation Serviceから切断します。

1
2
3
4
5
6
7
8
9
10
@Override
protected void onStop() {
    if (isGooglePlayServicesAvailable()) {
        if (mLocationClient.isConnected()) {
            mLocationClient.removeLocationUpdates(mLocationListener);
        }
        mLocationClient.disconnect();
    }
    super.onStop();
}

2014年2月19日水曜日

Google Play servicesを使う

Google Play servicesを使う準備

Google Play services APIを使うには、Android SDK ManagerでGoogle Play servicesをダウンロードします。ダウンロードすると、次のディレクトリに保存されます。<AndroidSDK>\sdk\extras\google\google_play_services\libproject\google-play-services_lib

上記のプロジェクトをEclipseにインポートします。

Google Play services APIを使用するプロジェクトにて、AndroidManifest.xmlにmeta-dataの記載を行います。

1
2
3
4
5
<application
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
</application>


Google Play servicesの存在確認

アプリケーションが動作するユーザー端末がどのような状態かわかりません。Google Play services APIを使用する前に、Google Play services APKがインストールされてるかどうかチェックしましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class UsingGooglePlayServiceSampleActivity extends FragmentActivity {
 
    private boolean isGooglePlayServicesAvailable() {
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
 
        if (ConnectionResult.SUCCESS == resultCode) {
            return true;
        } else {
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
            if (dialog != null) {
                ErrorDialogFragment errorFragment = new ErrorDialogFragment();
                errorFragment.setDialog(dialog);
                errorFragment.show(getSupportFragmentManager(), "errro_dialog");
            }
        }
 
        return false;
    }
 
    public static class ErrorDialogFragment extends DialogFragment {
 
        private Dialog mDialog;
 
        public ErrorDialogFragment() {
            super();
            mDialog = null;
        }
 
        public void setDialog(Dialog dialog) {
            mDialog = dialog;
        }
 
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            return mDialog;
        }
 
        @Override
        public void onDestroy() {
            mDialog = null;
            super.onDestroy();
        }
    }
}

GooglePlayServicesUtil.isGooglePlayServicesAvailable()をコールします。APIリファレンスに記載されているResultコード一覧の値が返ってきます。エラーが発生した場合、GooglePlayServicesUtil.getErrorDialog()をコールしDialogを取得します。取得したDialogはDialogFragmentを使って、表示してください。

Dialogを通じてユーザーに発生した問題を通知します。Dialogを閉じると、onActivityResultがコールされてResultを通知します。

1
2
3
4
5
6
7
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == CONNECTION_FAILURE_RESOLUTION_REQUEST) {
        if (resultCode == Activity.RESULT_OK) {
            // retry process
        }
    }
}

2014年1月7日火曜日

KitKatのフルスクリーンモード

Immersive full-screen mode

SYSTEM_UI_FLAG_IMMERSIVE
API Level 19で追加されたSYSTEM_UI_FLAG_IMMERSIVEを使うと、NavigationBarを消した状態でタッチイベントをハンドリングできます。
画面下部をSwapすることでNavigationBar非表示を解除できます。
ただし、Action barのメニューを開いたり、オフスクリーン→オンスクリーンで解除されてしまうので制御が必要です。

http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_IMMERSIVE

SYSTEM_UI_FLAG_HIDE_NAVIGATIONと同時にセットする必要があります。
(SYSTEM_UI_FLAG_HIDE_NAVIGATIONを拡張したフラグ)

Viewに対して、フラグをセット。
1
2
3
View view = findViewById(R.id.layout);
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE
        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);


初回表示の際、次のような注意画面が表示されます。

NavigationBar非表示の画面。



SYSTEM_UI_FLAG_IMMERSIVE_STICKY
SYSTEM_UI_FLAG_IMMERSIVEとことなり、画面下部をSwapすることでNavigationBarを一時的に表示できます。
NavigationBar表示後、一定時間が経過すると、再度、非表示モードに戻ります。

http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_IMMERSIVE_STICKY

Viewに対して、フラグをセット。
1
2
3
View view = findViewById(R.id.layout);
view.setSystemUiVisibility(View. SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
NavigationBar非表示の画面。

画面下部をSwapするとNavigationBarを表示します。