diff --git a/.gitignore b/.gitignore
index 218cb37..89aff86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,7 +24,6 @@ gen/
# Local configuration file (sdk path, etc)
local.properties
-gradle.properties
keystore.properties
### Mac
diff --git a/README.md b/README.md
index 9d41cfc..4f5655e 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,36 @@

# CoReader
One Android App support mutil program language.C C# C++ java swift go php xml json...It's useful for developer to read on the phone.
-###Add repo:
+### Add repo:
* Can download repo from github trending
* Search repo in the github
* Add repo by name and download url
* Open local file.
-###Download
+### Download
[Fir Download](http://fir.im/coreader)Scan the QRCode to install

-[Download from release](https://github.com/loopeer/code-reader/releases/tag/V1.0.1)
+[Download from release](https://github.com/loopeer/code-reader/releases/tag/v1.1.0)
Screenshot
====
-###Support multi markdown style
+### Support multi markdown style

Base on [markdownj](https://github.com/myabc/markdownj).Add many github styles.
-###Day night theme
+### Day night theme
 
 
-###Repo item swipe action(Sea [itemtouchhelper-extension](https://github.com/loopeer/itemtouchhelper-extension))
+### Repo item swipe action(Sea [itemtouchhelper-extension](https://github.com/loopeer/itemtouchhelper-extension))

-###Download repo from github trending
+### Download repo from github trending

-###Search repo in github
+### Search repo in github

-###Add repo to download
-
-
-Collaborators
-====
-[kKumaJ](https://github.com/kKumaJ)
-[yanxinit](https://github.com/yanxinit)
-[ToDou](https://github.com/ToDou)
+### Add repo to download
+
Contact:
====
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index 369a13f..0000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,51 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'android-apt'
-apply plugin: 'com.squareup.sqldelight'
-apply plugin: 'com.neenbedankt.android-apt'
-apply plugin: 'me.tatarka.retrolambda'
-
-android {
- compileSdkVersion Integer.parseInt(compile_sdk_version)
- buildToolsVersion build_tools_version
-
- defaultConfig {
- applicationId "com.loopeer.codereader"
- minSdkVersion min_sdk_version
- targetSdkVersion target_sdk_version
- versionCode Integer.parseInt(version_code)
- versionName version_name
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- targetCompatibility 1.8
- sourceCompatibility 1.8
- }
-}
-
-dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:' + support_version
- compile 'com.android.support:design:' + support_version
- compile 'com.jakewharton:butterknife:' + butterknife_version
- apt 'com.jakewharton:butterknife-compiler:' + butterknife_version
- compile 'com.squareup.retrofit2:retrofit:' + retrofit
- compile 'com.squareup.retrofit2:converter-gson:' + retrofit
- compile 'com.squareup.retrofit2:adapter-rxjava:' + retrofit
- compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
- compile 'io.reactivex:rxjava:' + rxjava
- compile 'io.reactivex:rxandroid:' + rxandroid
- compile 'com.github.bumptech.glide:glide:' + glide
- apt 'com.google.auto.value:auto-value:' + auto_value
- provided 'com.google.auto.value:auto-value:' + auto_value
- provided 'com.jakewharton.auto.value:auto-value-annotations:1.2-update1'
- compile project(':libraries:markdownj')
- compile project(':libraries:directoryandfilechooser')
- compile project(':libraries:itemtouchhelperextension')
- debugCompile 'com.facebook.stetho:stetho:1.1.0'
-}
diff --git a/app/src/androidTest/java/com/loopeer/codereader/ApplicationTest.java b/app/src/androidTest/java/com/loopeer/codereader/ApplicationTest.java
deleted file mode 100644
index 89c327a..0000000
--- a/app/src/androidTest/java/com/loopeer/codereader/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.loopeer.codereader;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/CodeReaderApplication.java b/app/src/main/java/com/loopeer/codereader/CodeReaderApplication.java
deleted file mode 100644
index a2f440b..0000000
--- a/app/src/main/java/com/loopeer/codereader/CodeReaderApplication.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.loopeer.codereader;
-
-import android.app.Application;
-import android.content.Context;
-import android.support.v7.app.AppCompatDelegate;
-
-import com.facebook.stetho.Stetho;
-import com.loopeer.codereader.utils.ThemeUtils;
-
-public class CodeReaderApplication extends Application {
- private static CodeReaderApplication mInstance;
- private static Context sAppContext;
-
- @Override
- public void onCreate() {
- super.onCreate();
- mInstance = this;
- sAppContext = getApplicationContext();
- Stetho.initialize(
- Stetho.newInitializerBuilder(this)
- .enableDumpapp(Stetho.defaultDumperPluginsProvider(this))
- .enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this))
- .build());
- AppCompatDelegate.setDefaultNightMode(ThemeUtils.getCurrentNightMode(this));
- }
-
- public static Context getAppContext() {
- return sAppContext;
- }
-
- public static CodeReaderApplication getInstance() {
- return mInstance;
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/Navigator.java b/app/src/main/java/com/loopeer/codereader/Navigator.java
deleted file mode 100644
index 35e4cb4..0000000
--- a/app/src/main/java/com/loopeer/codereader/Navigator.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.loopeer.codereader;
-
-import android.app.DownloadManager;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.text.Html;
-import android.widget.Toast;
-
-import com.loopeer.codereader.coreader.db.CoReaderDbHelper;
-import com.loopeer.codereader.model.Repo;
-import com.loopeer.codereader.sync.DownloadRepoService;
-import com.loopeer.codereader.ui.activity.AboutActivity;
-import com.loopeer.codereader.ui.activity.AddRepoActivity;
-import com.loopeer.codereader.ui.activity.CodeReadActivity;
-import com.loopeer.codereader.ui.activity.MainActivity;
-import com.loopeer.codereader.ui.activity.SearchActivity;
-import com.loopeer.codereader.ui.activity.SettingActivity;
-import com.loopeer.codereader.ui.activity.SimpleWebActivity;
-
-public class Navigator {
-
- public final static String EXTRA_REPO = "extra_repo";
- public final static String EXTRA_ID = "extra_id";
- public final static String EXTRA_DOWNLOAD_SERVICE_TYPE = "extra_download_service_type";
- public final static String EXTRA_DIRETORY_ROOT = "extra_diretory_root";
- public final static String EXTRA_DIRETORY_ROOT_NODE_INSTANCE = "extra_diretory_root_node_instance";
- public final static String EXTRA_DIRETORY_SELECTING = "extra_diretory_selecting";
- public final static String EXTRA_WEB_URL = "extra_web_url";
- public final static String EXTRA_HTML_STRING = "extra_html_string";
-
- public static void startMainActivity(Context context) {
- Intent intent = new Intent(context, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- context.startActivity(intent);
- }
-
- public static void startCodeReadActivity(Context context, Repo repo) {
- Intent intent = new Intent(context, CodeReadActivity.class);
- intent.putExtra(EXTRA_REPO, repo);
- context.startActivity(intent);
- }
-
- public static void startWebActivity(Context context, String url) {
- Intent intent = new Intent(context, SimpleWebActivity.class);
- intent.putExtra(EXTRA_WEB_URL, url);
- context.startActivity(intent);
- }
-
- public static void startAboutActivity(Context context) {
- Intent intent = new Intent(context, AboutActivity.class);
- context.startActivity(intent);
- }
-
- public static void startComposeEmail(Context context, String[] addresses, String subject, String content) {
- Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
- intent.putExtra(Intent.EXTRA_SUBJECT, subject);
- intent.putExtra(Intent.EXTRA_EMAIL, addresses);
- intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(content));
- if (intent.resolveActivity(context.getPackageManager()) != null) {
- context.startActivity(intent);
- } else {
- Toast.makeText(context, R.string.about_email_app_not_have, Toast.LENGTH_SHORT).show();
- }
- }
-
- public static void startDownloadNewRepoService(Context context, Repo repo) {
- Repo sameRepo = CoReaderDbHelper.getInstance(context).readSameRepo(repo);
- long repoId;
- if (sameRepo != null) {
- repoId = Long.parseLong(sameRepo.id);
- } else {
- repoId = CoReaderDbHelper.getInstance(context).insertRepo(repo);
- }
- repo.id = String.valueOf(repoId);
- Navigator.startDownloadRepoService(context, repo);
- }
-
- public static void startDownloadRepoService(Context context, Repo repo) {
- Intent intent = new Intent(context, DownloadRepoService.class);
- intent.putExtra(EXTRA_REPO, repo);
- intent.putExtra(EXTRA_DOWNLOAD_SERVICE_TYPE, DownloadRepoService.DOWNLOAD_REPO);
- context.startService(intent);
- }
-
- public static void startDownloadRepoService(Context context, int type) {
- Intent intent = new Intent(context, DownloadRepoService.class);
- intent.putExtra(EXTRA_DOWNLOAD_SERVICE_TYPE, type);
- context.startService(intent);
- }
-
- public static void startDownloadRepoServiceRemove(Context context, long downloadId) {
- Intent intent = new Intent(context, DownloadRepoService.class);
- intent.putExtra(EXTRA_DOWNLOAD_SERVICE_TYPE, DownloadRepoService.DOWNLOAD_REMOVE_DOWNLOAD);
- intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
- context.startService(intent);
- }
-
- public static void startSearchActivity(Context context) {
- Intent intent = new Intent(context, SearchActivity.class);
- context.startActivity(intent);
- }
-
- public static void startAddRepoActivity(Context context) {
- Intent intent = new Intent(context, AddRepoActivity.class);
- context.startActivity(intent);
- }
-
- public static void startSettingActivity(Context context) {
- Intent intent = new Intent(context, SettingActivity.class);
- context.startActivity(intent);
- }
-
- public static void startOutWebActivity(Context context, String url) {
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_VIEW);
- Uri content_url = Uri.parse(url);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setData(content_url);
- context.startActivity(intent);
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/api/ApiService.java b/app/src/main/java/com/loopeer/codereader/api/ApiService.java
deleted file mode 100644
index e1912db..0000000
--- a/app/src/main/java/com/loopeer/codereader/api/ApiService.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.loopeer.codereader.api;
-
-import android.app.Application;
-
-import com.loopeer.codereader.BuildConfig;
-import com.loopeer.codereader.CodeReaderApplication;
-
-import java.io.File;
-import java.util.MissingResourceException;
-import java.util.concurrent.TimeUnit;
-
-import okhttp3.Cache;
-import okhttp3.OkHttpClient;
-import retrofit2.Retrofit;
-import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
-import retrofit2.converter.gson.GsonConverterFactory;
-
-public class ApiService {
-
- public static final String API_URL = "https://api.github.com/";
-
- private static ApiService sInstance;
-
- private Retrofit mRetrofit;
-
- public static synchronized ApiService getInstance() {
- if (sInstance == null) {
- sInstance = new ApiService();
- }
- return sInstance;
- }
-
-
- private OkHttpClient getClient() {
- return createOkHttpClient(CodeReaderApplication.getInstance());
- }
-
- static final int DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
-
- static OkHttpClient createOkHttpClient(Application app) {
- OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
-
- if (BuildConfig.DEBUG) {
- HttpJsonLoggingInterceptor loggingInterceptor = new HttpJsonLoggingInterceptor();
- loggingInterceptor.setLevel(HttpJsonLoggingInterceptor.Level.BODY);
- httpClient.addInterceptor(loggingInterceptor);
- }
-
- httpClient.connectTimeout(1, TimeUnit.HOURS); // connect timeout
- httpClient.readTimeout(1, TimeUnit.HOURS);
- File cacheDir = new File(app.getCacheDir(), "http");
- Cache cache = new Cache(cacheDir, DISK_CACHE_SIZE);
- httpClient.cache(cache);
- return httpClient.build();
- }
-
- protected Retrofit.Builder newRestAdapterBuilder() {
- return new Retrofit.Builder();
- }
-
- protected Retrofit getRetrofit() {
- if (mRetrofit == null) {
- try {
- mRetrofit = newRestAdapterBuilder()
- .client(getClient())
- .addConverterFactory(GsonConverterFactory.create())
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .baseUrl(API_URL)
- .build();
- } catch (NullPointerException e) {
- throw new MissingResourceException("Define your endpoint in api_url string resource.", getClass().getName(), "api_url");
- }
- }
-
- return mRetrofit;
- }
-
- public static T create(Class service) {
- return getInstance().getRetrofit().create(service);
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/api/BaseListResponse.java b/app/src/main/java/com/loopeer/codereader/api/BaseListResponse.java
deleted file mode 100644
index 17fb08f..0000000
--- a/app/src/main/java/com/loopeer/codereader/api/BaseListResponse.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.loopeer.codereader.api;
-
-import com.google.gson.annotations.SerializedName;
-
-import java.util.List;
-
-public class BaseListResponse {
-
- @SerializedName("total_count")
- public int totalCount;
- @SerializedName("incomplete_results")
- public boolean incompleteResults;
- @SerializedName("items")
- public List items;
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/api/HttpJsonLoggingInterceptor.java b/app/src/main/java/com/loopeer/codereader/api/HttpJsonLoggingInterceptor.java
deleted file mode 100644
index fcf097e..0000000
--- a/app/src/main/java/com/loopeer/codereader/api/HttpJsonLoggingInterceptor.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2015 Square, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.loopeer.codereader.api;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.concurrent.TimeUnit;
-
-import okhttp3.Connection;
-import okhttp3.Headers;
-import okhttp3.Interceptor;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Protocol;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okhttp3.ResponseBody;
-import okhttp3.internal.http.HttpHeaders;
-import okhttp3.internal.platform.Platform;
-import okio.Buffer;
-import okio.BufferedSource;
-
-import static okhttp3.internal.platform.Platform.INFO;
-
-/**
- * An OkHttp interceptor which logs request and response information. Can be applied as an
- * {@linkplain OkHttpClient#interceptors() application interceptor} or as a {@linkplain
- * OkHttpClient#networkInterceptors() network interceptor}.
The format of the logs created by
- * this class should not be considered stable and may change slightly between releases. If you need
- * a stable logging format, use your own interceptor.
- */
-public final class HttpJsonLoggingInterceptor implements Interceptor {
- private static final Charset UTF8 = Charset.forName("UTF-8");
-
- public enum Level {
- /**
- * No logs.
- */
- NONE,
- /**
- * Logs request and response lines.
- *
");
- subscriber.onNext(HtmlParser.buildHtmlContent(getActivity(), sb.toString()
- , jsFile, mNode.name));
- } catch (OutOfMemoryError e) {
- subscriber.onError(e);
- } catch (FileNotFoundException e) {
- subscriber.onError(e);
- } catch (IOException e) {
- subscriber.onError(e);
- }
- subscriber.onCompleted();
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .doOnNext(o -> mWebCodeRead.loadDataWithBaseURL("file:///android_asset/"
- , o, "text/html", "UTF-8", ""))
- .doOnError(e -> mCodeContentLoader.showEmpty(e.getMessage()))
- .onErrorResumeNext(Observable.empty())
- .subscribe();
- }
-
- protected void openMdShowFile() {
- registerSubscription(
- Observable.create(new Observable.OnSubscribe() {
- @Override
- public void call(Subscriber super String> subscriber) {
- InputStream stream = null;
- try {
- stream = new FileInputStream(mNode.absolutePath);
- } catch (FileNotFoundException e) {
- subscriber.onError(e);
- }
- if (stream == null)
- return;
- final InputStream finalStream = stream;
- StringBuilder localStringBuilder = new StringBuilder();
- try {
- BufferedReader localBufferedReader = new BufferedReader(
- new InputStreamReader(finalStream, "UTF-8"));
- for (; ; ) {
- String str = localBufferedReader.readLine();
- if (str == null) {
- break;
- }
- localStringBuilder.append(str);
- localStringBuilder.append("\n");
- }
- String textString = localStringBuilder.toString();
-
- if (textString != null) {
- MarkdownProcessor m = new MarkdownProcessor(mRootNode.absolutePath);
- m.setTextColorString(ColorUtils.getColorString(getContext()
- , R.color.text_color_primary));
- m.setBackgroundColorString(ColorUtils.getColorString(getContext()
- , R.color.code_read_background_color));
- m.setCodeBlockColor(ColorUtils.getColorString(getContext()
- , R.color.code_block_color));
- m.setTableBorderColor(ColorUtils.getColorString(getContext()
- , R.color.table_block_border_color));
- String html = m.markdown(textString);
- subscriber.onNext(html);
- }
- subscriber.onCompleted();
- } catch (OutOfMemoryError e) {
- subscriber.onError(e);
- } catch (FileNotFoundException e) {
- subscriber.onError(e);
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .doOnNext(s -> mWebCodeRead.loadDataWithBaseURL("fake://", s, "text/html"
- , "UTF-8", ""))
- .doOnError(e -> mCodeContentLoader.showEmpty(e.getMessage()))
- .onErrorResumeNext(Observable.empty())
- .subscribe()
- );
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
-
- mWebCodeRead.destroy();
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- mOrientationChange = true;
- }
-
- @Override
- public void onScrollChanged(int l, int t, int oldl, int oldt) {
- if (mOrientationChange) {
- mOrientationChange = false;
- return;
- }
-
- if (scrollFinishDelaySubscription != null && !scrollFinishDelaySubscription.isUnsubscribed()) {
- scrollFinishDelaySubscription.unsubscribe();
- }
- if (t - oldt > 70) {
- if (mScrollDown)
- return;
-
- mScrollDown = true;
- } else if (t - oldt < 0) {
- if (!mScrollDown)
- return;
-
- mScrollDown = false;
- closeFullScreen();
- }
- if (mScrollDown) {
- scrollFinishDelaySubscription = Observable
- .timer(500, TimeUnit.MILLISECONDS)
- .observeOn(AndroidSchedulers.mainThread())
- .doOnNext(lo -> openFullScreen())
- .subscribe();
- registerSubscription(scrollFinishDelaySubscription);
- }
- }
-
- public void updateRootNode(DirectoryNode directoryNode) {
- mRootNode = directoryNode;
- }
-
- public ILoadHelper getCodeContentLoader() {
- return mCodeContentLoader;
- }
-
- private void openFullScreen() {
- hide();
- }
-
- private void closeFullScreen() {
- show();
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/loader/CodeFragmentContentLoader.java b/app/src/main/java/com/loopeer/codereader/ui/loader/CodeFragmentContentLoader.java
deleted file mode 100644
index 76e9fc5..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/loader/CodeFragmentContentLoader.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.loopeer.codereader.ui.loader;
-
-import android.view.View;
-import android.widget.TextView;
-import android.widget.ViewAnimator;
-
-import com.loopeer.codereader.R;
-import com.loopeer.codereader.ui.view.ProgressIndicatorView;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-
-public class CodeFragmentContentLoader implements ILoadHelper {
-
- @BindView(R.id.progress_code_fragment)
- ProgressIndicatorView mProgressIndicatorView;
- @BindView(R.id.content_animator)
- ViewAnimator mContentAnimator;
- @BindView(android.R.id.empty)
- TextView mTextEmpty;
-
- public CodeFragmentContentLoader(View contentView) {
- ButterKnife.bind(this, contentView);
- }
-
- @Override
- public void showProgress() {
- mContentAnimator.setDisplayedChild(1);
- mProgressIndicatorView.setAnimationStatus(ProgressIndicatorView.AnimStatus.START);
- }
-
- @Override
- public void showContent() {
- mContentAnimator.setDisplayedChild(0);
- mProgressIndicatorView.setAnimationStatus(ProgressIndicatorView.AnimStatus.CANCEL);
- }
-
- @Override
- public void showEmpty(String message) {
- mContentAnimator.setDisplayedChild(2);
- mTextEmpty.setText(message);
- mProgressIndicatorView.setAnimationStatus(ProgressIndicatorView.AnimStatus.CANCEL);
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/loader/ILoadHelper.java b/app/src/main/java/com/loopeer/codereader/ui/loader/ILoadHelper.java
deleted file mode 100644
index 424f086..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/loader/ILoadHelper.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.loopeer.codereader.ui.loader;
-
-public interface ILoadHelper {
-
- void showProgress();
-
- void showContent();
-
- void showEmpty(String message);
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/loader/RecyclerLoader.java b/app/src/main/java/com/loopeer/codereader/ui/loader/RecyclerLoader.java
deleted file mode 100644
index d46a6e1..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/loader/RecyclerLoader.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.loopeer.codereader.ui.loader;
-
-import android.widget.ViewAnimator;
-
-public class RecyclerLoader implements ILoadHelper {
-
- ViewAnimator mViewAnimator;
-
- public RecyclerLoader(ViewAnimator continer) {
- mViewAnimator = continer;
- }
-
- @Override
- public void showProgress() {
- mViewAnimator.setDisplayedChild(2);
- }
-
- @Override
- public void showContent() {
- mViewAnimator.setDisplayedChild(0);
- }
-
- @Override
- public void showEmpty(String message) {
- mViewAnimator.setDisplayedChild(1);
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/package.info b/app/src/main/java/com/loopeer/codereader/ui/package.info
deleted file mode 100644
index e69de29..0000000
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/AddRepoChecker.java b/app/src/main/java/com/loopeer/codereader/ui/view/AddRepoChecker.java
deleted file mode 100644
index ff5342d..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/AddRepoChecker.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.text.TextUtils;
-
-public class AddRepoChecker extends Checker {
- public String repoName;
- public String repoDownloadUrl;
-
- public AddRepoChecker(CheckObserver checkObserver) {
- super(checkObserver);
- }
-
- public void setRepoName(String repoName) {
- this.repoName = repoName;
- mCheckObserver.check(isEnable());
- }
-
- public void setRepoDownloadUrl(String repoDownloadUrl) {
- this.repoDownloadUrl = repoDownloadUrl;
- mCheckObserver.check(isEnable());
- }
-
- @Override
- public boolean isEnable() {
- return !TextUtils.isEmpty(repoName) && !TextUtils.isEmpty(repoDownloadUrl);
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/Checker.java b/app/src/main/java/com/loopeer/codereader/ui/view/Checker.java
deleted file mode 100644
index 4e40eca..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/Checker.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-public abstract class Checker {
- public interface CheckObserver{
- void check(boolean b);
- }
-
- CheckObserver mCheckObserver;
-
- public Checker(CheckObserver checkObserver) {
- mCheckObserver = checkObserver;
- }
-
- abstract boolean isEnable();
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/DirectoryNavDelegate.java b/app/src/main/java/com/loopeer/codereader/ui/view/DirectoryNavDelegate.java
deleted file mode 100644
index e3842dd..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/DirectoryNavDelegate.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.widget.Toast;
-
-import com.loopeer.codereader.model.DirectoryNode;
-import com.loopeer.codereader.ui.adapter.DirectoryAdapter;
-import com.loopeer.codereader.utils.FileCache;
-import com.loopeer.codereader.utils.FileTypeUtils;
-
-import java.io.File;
-
-import rx.Observable;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
-import rx.subscriptions.CompositeSubscription;
-
-public class DirectoryNavDelegate {
- private static final String TAG = "DirectoryNavDelegate";
-
- public interface FileClickListener {
- void doOpenFile(DirectoryNode node);
- }
-
- public interface LoadFileCallback{
- void onFileOpenStart();
- void onFileOpenEnd();
- }
-
- private RecyclerView mRecyclerView;
- private DirectoryAdapter mDirectoryAdapter;
- private Context mContext;
- private FileClickListener mFileClickListener;
- private LoadFileCallback mLoadFileCallback;
- private final CompositeSubscription mAllSubscription = new CompositeSubscription();
-
- public DirectoryNavDelegate(RecyclerView recyclerView, FileClickListener listener) {
- mRecyclerView = recyclerView;
- mContext = recyclerView.getContext();
- mFileClickListener = listener;
- mDirectoryAdapter = new DirectoryAdapter(recyclerView.getContext(), listener);
- setUpRecyclerView();
- }
-
- public void setLoadFileCallback(LoadFileCallback loadFileCallback) {
- mLoadFileCallback = loadFileCallback;
- }
-
- public void clearSubscription() {
- mAllSubscription.clear();
- }
-
- public void resumeDirectoryState(DirectoryNode node) {
- mDirectoryAdapter.setNodeRoot(node);
- }
-
- public DirectoryNode getDirectoryNodeInstance() {
- return mDirectoryAdapter.getNodeRoot();
- }
-
- private void setUpRecyclerView() {
- mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
- mRecyclerView.setAdapter(mDirectoryAdapter);
- }
-
- public void updateData(DirectoryNode directoryNode) {
- mLoadFileCallback.onFileOpenStart();
- mAllSubscription.add(
- Observable.fromCallable(() -> {
- DirectoryNode node;
- if (directoryNode.isDirectory) {
- node = FileCache.getFileDirectory(new File(directoryNode.absolutePath));
- } else {
- node = directoryNode;
- }
- return node;
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .doOnNext(mDirectoryAdapter::setNodeRoot)
- .doOnNext(this::checkOpenFirstFile)
- .doOnError(e -> Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show())
- .onErrorResumeNext(Observable.empty())
- .doOnCompleted(() -> mLoadFileCallback.onFileOpenEnd())
- .subscribe());
- }
-
- private void checkOpenFirstFile(DirectoryNode node) {
- if (node.isDirectory && node.pathNodes != null) {
- boolean haveOpen = false;
- for (DirectoryNode n : node.pathNodes) {
- if (FileTypeUtils.isMdFileType(n.name) && n.name.equalsIgnoreCase("readme.md")) {
- mFileClickListener.doOpenFile(n);
- haveOpen = true;
- }
- }
- if (!haveOpen) {
- mFileClickListener.doOpenFile(null);
- }
- } else if (!node.isDirectory) {
- mFileClickListener.doOpenFile(node);
- } else {
- mFileClickListener.doOpenFile(null);
- }
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayout.java b/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayout.java
deleted file mode 100644
index 108987a..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayout.java
+++ /dev/null
@@ -1,2339 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.KeyEventCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewGroupCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-public class DrawerLayout extends ViewGroup implements DrawerLayoutImpl {
- private static final String TAG = "DrawerLayout";
-
- @IntDef({STATE_IDLE, STATE_DRAGGING, STATE_SETTLING})
- @Retention(RetentionPolicy.SOURCE)
- private @interface State {}
-
- /**
- * Indicates that any drawers are in an idle, settled state. No animation is in progress.
- */
- public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
-
- /**
- * Indicates that a drawer is currently being dragged by the user.
- */
- public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
-
- /**
- * Indicates that a drawer is in the process of settling to a final position.
- */
- public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
-
- /** @hide */
- @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN,
- LOCK_MODE_UNDEFINED})
- @Retention(RetentionPolicy.SOURCE)
- private @interface LockMode {}
-
- /**
- * The drawer is unlocked.
- */
- public static final int LOCK_MODE_UNLOCKED = 0;
-
- /**
- * The drawer is locked closed. The user may not open it, though
- * the app may open it programmatically.
- */
- public static final int LOCK_MODE_LOCKED_CLOSED = 1;
-
- /**
- * The drawer is locked open. The user may not close it, though the app
- * may close it programmatically.
- */
- public static final int LOCK_MODE_LOCKED_OPEN = 2;
-
- /**
- * The drawer's lock state is reset to default.
- */
- public static final int LOCK_MODE_UNDEFINED = 3;
-
- /** @hide */
- @IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
- @Retention(RetentionPolicy.SOURCE)
- private @interface EdgeGravity {}
-
-
- private static final int MIN_DRAWER_MARGIN = 64; // dp
- private static final int DRAWER_ELEVATION = 10; //dp
-
- private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
-
- /**
- * Length of time to delay before peeking the drawer.
- */
- private static final int PEEK_DELAY = 160; // ms
-
- /**
- * Minimum velocity that will be detected as a fling
- */
- private static final int MIN_FLING_VELOCITY = 400; // dips per second
-
- /**
- * Experimental feature.
- */
- private static final boolean ALLOW_EDGE_LOCK = false;
-
- private static final boolean CHILDREN_DISALLOW_INTERCEPT = true;
-
- private static final float TOUCH_SLOP_SENSITIVITY = 1.f;
-
- private static final int[] LAYOUT_ATTRS = new int[] {
- android.R.attr.layout_gravity
- };
-
- /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
- private static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
-
- /** Whether the drawer shadow comes from setting elevation on the drawer. */
- private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
- Build.VERSION.SDK_INT >= 21;
-
- private final ChildAccessibilityDelegate mChildAccessibilityDelegate =
- new ChildAccessibilityDelegate();
- private float mDrawerElevation;
-
- private int mMinDrawerMargin;
-
- private int mScrimColor = DEFAULT_SCRIM_COLOR;
- private float mScrimOpacity;
- private Paint mScrimPaint = new Paint();
-
- private final ViewDragHelper mLeftDragger;
- private final ViewDragHelper mRightDragger;
- private final ViewDragCallback mLeftCallback;
- private final ViewDragCallback mRightCallback;
- private int mDrawerState;
- private boolean mInLayout;
- private boolean mFirstLayout = true;
-
- private @LockMode int mLockModeLeft = LOCK_MODE_UNDEFINED;
- private @LockMode int mLockModeRight = LOCK_MODE_UNDEFINED;
- private @LockMode int mLockModeStart = LOCK_MODE_UNDEFINED;
- private @LockMode int mLockModeEnd = LOCK_MODE_UNDEFINED;
-
- private boolean mDisallowInterceptRequested;
- private boolean mChildrenCanceledTouch;
-
- private @Nullable
- DrawerListener mListener;
- private List mListeners;
-
- private float mInitialMotionX;
- private float mInitialMotionY;
-
- private Drawable mStatusBarBackground;
- private Drawable mShadowLeftResolved;
- private Drawable mShadowRightResolved;
-
- private CharSequence mTitleLeft;
- private CharSequence mTitleRight;
-
- private Object mLastInsets;
- private boolean mDrawStatusBarBackground;
-
- /** Shadow drawables for different gravity */
- private Drawable mShadowStart = null;
- private Drawable mShadowEnd = null;
- private Drawable mShadowLeft = null;
- private Drawable mShadowRight = null;
-
- private final ArrayList mNonDrawerViews;
-
- /**
- * Listener for monitoring events about drawers.
- */
- public interface DrawerListener {
- /**
- * Called when a drawer's position changes.
- * @param drawerView The child view that was moved
- * @param slideOffset The new offset of this drawer within its range, from 0-1
- */
- public void onDrawerSlide(View drawerView, float slideOffset);
-
- /**
- * Called when a drawer has settled in a completely open state.
- * The drawer is interactive at this point.
- *
- * @param drawerView Drawer view that is now open
- */
- public void onDrawerOpened(View drawerView);
-
- /**
- * Called when a drawer has settled in a completely closed state.
- *
- * @param drawerView Drawer view that is now closed
- */
- public void onDrawerClosed(View drawerView);
-
- /**
- * Called when the drawer motion state changes. The new state will
- * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
- *
- * @param newState The new drawer motion state
- */
- public void onDrawerStateChanged(@State int newState);
- }
-
- /**
- * Stub/no-op implementations of all methods of {@link DrawerListener}.
- * Override this if you only care about a few of the available callback methods.
- */
- public static abstract class SimpleDrawerListener implements DrawerListener {
- @Override
- public void onDrawerSlide(View drawerView, float slideOffset) {
- }
-
- @Override
- public void onDrawerOpened(View drawerView) {
- }
-
- @Override
- public void onDrawerClosed(View drawerView) {
- }
-
- @Override
- public void onDrawerStateChanged(int newState) {
- }
- }
-
- interface DrawerLayoutCompatImpl {
- void configureApplyInsets(View drawerLayout);
- void dispatchChildInsets(View child, Object insets, int drawerGravity);
- void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity);
- int getTopInset(Object lastInsets);
- Drawable getDefaultStatusBarBackground(Context context);
- }
-
- static class DrawerLayoutCompatImplBase implements DrawerLayoutCompatImpl {
- public void configureApplyInsets(View drawerLayout) {
- // This space for rent
- }
-
- public void dispatchChildInsets(View child, Object insets, int drawerGravity) {
- // This space for rent
- }
-
- public void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity) {
- // This space for rent
- }
-
- public int getTopInset(Object insets) {
- return 0;
- }
-
- @Override
- public Drawable getDefaultStatusBarBackground(Context context) {
- return null;
- }
- }
-
- static class DrawerLayoutCompatImplApi21 implements DrawerLayoutCompatImpl {
- public void configureApplyInsets(View drawerLayout) {
- DrawerLayoutCompatApi21.configureApplyInsets(drawerLayout);
- }
-
- public void dispatchChildInsets(View child, Object insets, int drawerGravity) {
- DrawerLayoutCompatApi21.dispatchChildInsets(child, insets, drawerGravity);
- }
-
- public void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity) {
- DrawerLayoutCompatApi21.applyMarginInsets(lp, insets, drawerGravity);
- }
-
- public int getTopInset(Object insets) {
- return DrawerLayoutCompatApi21.getTopInset(insets);
- }
-
- @Override
- public Drawable getDefaultStatusBarBackground(Context context) {
- return DrawerLayoutCompatApi21.getDefaultStatusBarBackground(context);
- }
- }
-
- static {
- final int version = Build.VERSION.SDK_INT;
- if (version >= 21) {
- IMPL = new DrawerLayoutCompatImplApi21();
- } else {
- IMPL = new DrawerLayoutCompatImplBase();
- }
- }
-
- static final DrawerLayoutCompatImpl IMPL;
-
- public DrawerLayout(Context context) {
- this(context, null);
- }
-
- public DrawerLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
- final float density = getResources().getDisplayMetrics().density;
- mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
- final float minVel = MIN_FLING_VELOCITY * density;
-
- mLeftCallback = new ViewDragCallback(Gravity.LEFT);
- mRightCallback = new ViewDragCallback(Gravity.RIGHT);
-
- mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
- mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
- mLeftDragger.setMinVelocity(minVel);
- mLeftCallback.setDragger(mLeftDragger);
-
- mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);
- mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
- mRightDragger.setMinVelocity(minVel);
- mRightCallback.setDragger(mRightDragger);
-
- // So that we can catch the back button
- setFocusableInTouchMode(true);
-
- ViewCompat.setImportantForAccessibility(this,
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-
- ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
- ViewGroupCompat.setMotionEventSplittingEnabled(this, false);
- if (ViewCompat.getFitsSystemWindows(this)) {
- IMPL.configureApplyInsets(this);
- mStatusBarBackground = IMPL.getDefaultStatusBarBackground(context);
- }
-
- mDrawerElevation = DRAWER_ELEVATION * density;
-
- mNonDrawerViews = new ArrayList();
- }
-
- /**
- * Sets the base elevation of the drawer(s) relative to the parent, in pixels. Note that the
- * elevation change is only supported in API 21 and above.
- *
- * @param elevation The base depth position of the view, in pixels.
- */
- public void setDrawerElevation(float elevation) {
- mDrawerElevation = elevation;
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (isDrawerView(child)) {
- ViewCompat.setElevation(child, mDrawerElevation);
- }
- }
- }
-
- /**
- * The base elevation of the drawer(s) relative to the parent, in pixels. Note that the
- * elevation change is only supported in API 21 and above. For unsupported API levels, 0 will
- * be returned as the elevation.
- *
- * @return The base depth position of the view, in pixels.
- */
- public float getDrawerElevation() {
- if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
- return mDrawerElevation;
- }
- return 0f;
- }
-
- /**
- * @hide Internal use only; called to apply window insets when configured
- * with fitsSystemWindows="true"
- */
- @Override
- public void setChildInsets(Object insets, boolean draw) {
- mLastInsets = insets;
- mDrawStatusBarBackground = draw;
- setWillNotDraw(!draw && getBackground() == null);
- requestLayout();
- }
-
- /**
- * Set a simple drawable used for the left or right shadow. The drawable provided must have a
- * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
- * instead of the drawable provided.
- *
- *
Note that for better support for both left-to-right and right-to-left layout
- * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
- * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
- * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
- * auto-mirrored such that the drawable will be mirrored in RTL layout.
- *
- * @param shadowDrawable Shadow drawable to use at the edge of a drawer
- * @param gravity Which drawer the shadow should apply to
- */
- public void setDrawerShadow(Drawable shadowDrawable, @EdgeGravity int gravity) {
- /*
- * TODO Someone someday might want to set more complex drawables here.
- * They're probably nuts, but we might want to consider registering callbacks,
- * setting states, etc. properly.
- */
- if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
- // No op. Drawer shadow will come from setting an elevation on the drawer.
- return;
- }
- if ((gravity & GravityCompat.START) == GravityCompat.START) {
- mShadowStart = shadowDrawable;
- } else if ((gravity & GravityCompat.END) == GravityCompat.END) {
- mShadowEnd = shadowDrawable;
- } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
- mShadowLeft = shadowDrawable;
- } else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
- mShadowRight = shadowDrawable;
- } else {
- return;
- }
- resolveShadowDrawables();
- invalidate();
- }
-
- /**
- * Set a simple drawable used for the left or right shadow. The drawable provided must have a
- * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
- * instead of the drawable provided.
- *
- *
Note that for better support for both left-to-right and right-to-left layout
- * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
- * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
- * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
- * auto-mirrored such that the drawable will be mirrored in RTL layout.
- *
- * @param resId Resource id of a shadow drawable to use at the edge of a drawer
- * @param gravity Which drawer the shadow should apply to
- */
- public void setDrawerShadow(@DrawableRes int resId, @EdgeGravity int gravity) {
- setDrawerShadow(getResources().getDrawable(resId), gravity);
- }
-
- /**
- * Set a color to use for the scrim that obscures primary content while a drawer is open.
- *
- * @param color Color to use in 0xAARRGGBB format.
- */
- public void setScrimColor(@ColorInt int color) {
- mScrimColor = color;
- invalidate();
- }
-
- /**
- * Set a listener to be notified of drawer events. Note that this method is deprecated
- * and you should use {@link #addDrawerListener(DrawerListener)} to add a listener and
- * {@link #removeDrawerListener(DrawerListener)} to remove a registered listener.
- *
- * @param listener Listener to notify when drawer events occur
- * @deprecated Use {@link #addDrawerListener(DrawerListener)}
- * @see DrawerListener
- * @see #addDrawerListener(DrawerListener)
- * @see #removeDrawerListener(DrawerListener)
- */
- @Deprecated
- public void setDrawerListener(DrawerListener listener) {
- // The logic in this method emulates what we had before support for multiple
- // registered listeners.
- if (mListener != null) {
- removeDrawerListener(mListener);
- }
- if (listener != null) {
- addDrawerListener(listener);
- }
- // Update the deprecated field so that we can remove the passed listener the next
- // time we're called
- mListener = listener;
- }
-
- /**
- * Adds the specified listener to the list of listeners that will be notified of drawer events.
- *
- * @param listener Listener to notify when drawer events occur.
- * @see #removeDrawerListener(DrawerListener)
- */
- public void addDrawerListener(@NonNull DrawerListener listener) {
- if (listener == null) {
- return;
- }
- if (mListeners == null) {
- mListeners = new ArrayList();
- }
- mListeners.add(listener);
- }
-
- /**
- * Removes the specified listener from the list of listeners that will be notified of drawer
- * events.
- *
- * @param listener Listener to remove from being notified of drawer events
- * @see #addDrawerListener(DrawerListener)
- */
- public void removeDrawerListener(@NonNull DrawerListener listener) {
- if (listener == null) {
- return;
- }
- if (mListeners == null) {
- // This can happen if this method is called before the first call to addDrawerListener
- return;
- }
- mListeners.remove(listener);
- }
-
- /**
- * Enable or disable interaction with all drawers.
- *
- *
This allows the application to restrict the user's ability to open or close
- * any drawer within this layout. DrawerLayout will still respond to calls to
- * {@link #openDrawer(int)}, {@link #closeDrawer(int)} and friends if a drawer is locked.
- *
- *
Locking drawers open or closed will implicitly open or close
- * any drawers as appropriate.
- *
- * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
- * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
- */
- public void setDrawerLockMode(@LockMode int lockMode) {
- setDrawerLockMode(lockMode, Gravity.LEFT);
- setDrawerLockMode(lockMode, Gravity.RIGHT);
- }
-
- /**
- * Enable or disable interaction with the given drawer.
- *
- *
This allows the application to restrict the user's ability to open or close
- * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
- * {@link #closeDrawer(int)} and friends if a drawer is locked.
- *
- *
Locking a drawer open or closed will implicitly open or close
- * that drawer as appropriate.
- *
- * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
- * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
- * @param edgeGravity Gravity.LEFT, RIGHT, START or END.
- * Expresses which drawer to change the mode for.
- *
- * @see #LOCK_MODE_UNLOCKED
- * @see #LOCK_MODE_LOCKED_CLOSED
- * @see #LOCK_MODE_LOCKED_OPEN
- */
- public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) {
- final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity,
- ViewCompat.getLayoutDirection(this));
-
- switch (edgeGravity) {
- case Gravity.LEFT:
- mLockModeLeft = lockMode;
- break;
- case Gravity.RIGHT:
- mLockModeRight = lockMode;
- break;
- case GravityCompat.START:
- mLockModeStart = lockMode;
- break;
- case GravityCompat.END:
- mLockModeEnd = lockMode;
- break;
- }
-
- if (lockMode != LOCK_MODE_UNLOCKED) {
- // Cancel interaction in progress
- final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger;
- helper.cancel();
- }
- switch (lockMode) {
- case LOCK_MODE_LOCKED_OPEN:
- final View toOpen = findDrawerWithGravity(absGravity);
- if (toOpen != null) {
- openDrawer(toOpen);
- }
- break;
- case LOCK_MODE_LOCKED_CLOSED:
- final View toClose = findDrawerWithGravity(absGravity);
- if (toClose != null) {
- closeDrawer(toClose);
- }
- break;
- // default: do nothing
- }
- }
-
- /**
- * Enable or disable interaction with the given drawer.
- *
- *
This allows the application to restrict the user's ability to open or close
- * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
- * {@link #closeDrawer(int)} and friends if a drawer is locked.
- *
- *
Locking a drawer open or closed will implicitly open or close
- * that drawer as appropriate.
- *
- * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
- * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
- * @param drawerView The drawer view to change the lock mode for
- *
- * @see #LOCK_MODE_UNLOCKED
- * @see #LOCK_MODE_LOCKED_CLOSED
- * @see #LOCK_MODE_LOCKED_OPEN
- */
- public void setDrawerLockMode(@LockMode int lockMode, View drawerView) {
- if (!isDrawerView(drawerView)) {
- throw new IllegalArgumentException("View " + drawerView + " is not a " +
- "drawer with appropriate layout_gravity");
- }
- final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
- setDrawerLockMode(lockMode, gravity);
- }
-
- /**
- * Check the lock mode of the drawer with the given gravity.
- *
- * @param edgeGravity Gravity of the drawer to check
- * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
- * {@link #LOCK_MODE_LOCKED_OPEN}.
- */
- @LockMode
- public int getDrawerLockMode(@EdgeGravity int edgeGravity) {
- int layoutDirection = ViewCompat.getLayoutDirection(this);
-
- switch (edgeGravity) {
- case Gravity.LEFT:
- if (mLockModeLeft != LOCK_MODE_UNDEFINED) {
- return mLockModeLeft;
- }
- int leftLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
- mLockModeStart : mLockModeEnd;
- if (leftLockMode != LOCK_MODE_UNDEFINED) {
- return leftLockMode;
- }
- break;
- case Gravity.RIGHT:
- if (mLockModeRight != LOCK_MODE_UNDEFINED) {
- return mLockModeRight;
- }
- int rightLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
- mLockModeEnd : mLockModeStart;
- if (rightLockMode != LOCK_MODE_UNDEFINED) {
- return rightLockMode;
- }
- break;
- case GravityCompat.START:
- if (mLockModeStart != LOCK_MODE_UNDEFINED) {
- return mLockModeStart;
- }
- int startLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
- mLockModeLeft : mLockModeRight;
- if (startLockMode != LOCK_MODE_UNDEFINED) {
- return startLockMode;
- }
- break;
- case GravityCompat.END:
- if (mLockModeEnd != LOCK_MODE_UNDEFINED) {
- return mLockModeEnd;
- }
- int endLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
- mLockModeRight : mLockModeLeft;
- if (endLockMode != LOCK_MODE_UNDEFINED) {
- return endLockMode;
- }
- break;
- }
-
- return LOCK_MODE_UNLOCKED;
- }
-
- /**
- * Check the lock mode of the given drawer view.
- *
- * @param drawerView Drawer view to check lock mode
- * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
- * {@link #LOCK_MODE_LOCKED_OPEN}.
- */
- @LockMode
- public int getDrawerLockMode(View drawerView) {
- if (!isDrawerView(drawerView)) {
- throw new IllegalArgumentException("View " + drawerView + " is not a drawer");
- }
- final int drawerGravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
- return getDrawerLockMode(drawerGravity);
- }
-
- /**
- * Sets the title of the drawer with the given gravity.
- *
- * When accessibility is turned on, this is the title that will be used to
- * identify the drawer to the active accessibility service.
- *
- * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which
- * drawer to set the title for.
- * @param title The title for the drawer.
- */
- public void setDrawerTitle(@EdgeGravity int edgeGravity, CharSequence title) {
- final int absGravity = GravityCompat.getAbsoluteGravity(
- edgeGravity, ViewCompat.getLayoutDirection(this));
- if (absGravity == Gravity.LEFT) {
- mTitleLeft = title;
- } else if (absGravity == Gravity.RIGHT) {
- mTitleRight = title;
- }
- }
-
- /**
- * Returns the title of the drawer with the given gravity.
- *
- * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which
- * drawer to return the title for.
- * @return The title of the drawer, or null if none set.
- * @see #setDrawerTitle(int, CharSequence)
- */
- @Nullable
- public CharSequence getDrawerTitle(@EdgeGravity int edgeGravity) {
- final int absGravity = GravityCompat.getAbsoluteGravity(
- edgeGravity, ViewCompat.getLayoutDirection(this));
- if (absGravity == Gravity.LEFT) {
- return mTitleLeft;
- } else if (absGravity == Gravity.RIGHT) {
- return mTitleRight;
- }
- return null;
- }
-
- /**
- * Resolve the shared state of all drawers from the component ViewDragHelpers.
- * Should be called whenever a ViewDragHelper's state changes.
- */
- void updateDrawerState(int forGravity, @State int activeState, View activeDrawer) {
- final int leftState = mLeftDragger.getViewDragState();
- final int rightState = mRightDragger.getViewDragState();
-
- final int state;
- if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) {
- state = STATE_DRAGGING;
- } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) {
- state = STATE_SETTLING;
- } else {
- state = STATE_IDLE;
- }
-
- if (activeDrawer != null && activeState == STATE_IDLE) {
- final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams();
- if (lp.onScreen == 0) {
- dispatchOnDrawerClosed(activeDrawer);
- } else if (lp.onScreen == 1) {
- dispatchOnDrawerOpened(activeDrawer);
- }
- }
-
- if (state != mDrawerState) {
- mDrawerState = state;
-
- if (mListeners != null) {
- // Notify the listeners. Do that from the end of the list so that if a listener
- // removes itself as the result of being called, it won't mess up with our iteration
- int listenerCount = mListeners.size();
- for (int i = listenerCount - 1; i >= 0; i--) {
- mListeners.get(i).onDrawerStateChanged(state);
- }
- }
- }
- }
-
- void dispatchOnDrawerClosed(View drawerView) {
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
- lp.openState = 0;
-
- if (mListeners != null) {
- // Notify the listeners. Do that from the end of the list so that if a listener
- // removes itself as the result of being called, it won't mess up with our iteration
- int listenerCount = mListeners.size();
- for (int i = listenerCount - 1; i >= 0; i--) {
- mListeners.get(i).onDrawerClosed(drawerView);
- }
- }
-
- updateChildrenImportantForAccessibility(drawerView, false);
-
- // Only send WINDOW_STATE_CHANGE if the host has window focus. This
- // may change if support for multiple foreground windows (e.g. IME)
- // improves.
- if (hasWindowFocus()) {
- final View rootView = getRootView();
- if (rootView != null) {
- rootView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- }
- }
- }
- }
-
- void dispatchOnDrawerOpened(View drawerView) {
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 0) {
- lp.openState = LayoutParams.FLAG_IS_OPENED;
- if (mListeners != null) {
- // Notify the listeners. Do that from the end of the list so that if a listener
- // removes itself as the result of being called, it won't mess up with our iteration
- int listenerCount = mListeners.size();
- for (int i = listenerCount - 1; i >= 0; i--) {
- mListeners.get(i).onDrawerOpened(drawerView);
- }
- }
-
- updateChildrenImportantForAccessibility(drawerView, true);
-
- // Only send WINDOW_STATE_CHANGE if the host has window focus.
- if (hasWindowFocus()) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- }
-
- drawerView.requestFocus();
- }
- }
-
- private void updateChildrenImportantForAccessibility(View drawerView, boolean isDrawerOpen) {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (!isDrawerOpen && !isDrawerView(child)
- || isDrawerOpen && child == drawerView) {
- // Drawer is closed and this is a content view or this is an
- // open drawer view, so it should be visible.
- ViewCompat.setImportantForAccessibility(child,
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
- } else {
- ViewCompat.setImportantForAccessibility(child,
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- }
- }
- }
-
- void dispatchOnDrawerSlide(View drawerView, float slideOffset) {
- if (mListeners != null) {
- // Notify the listeners. Do that from the end of the list so that if a listener
- // removes itself as the result of being called, it won't mess up with our iteration
- int listenerCount = mListeners.size();
- for (int i = listenerCount - 1; i >= 0; i--) {
- mListeners.get(i).onDrawerSlide(drawerView, slideOffset);
- }
- }
- }
-
- void setDrawerViewOffset(View drawerView, float slideOffset) {
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if (slideOffset == lp.onScreen) {
- return;
- }
-
- lp.onScreen = slideOffset;
- dispatchOnDrawerSlide(drawerView, slideOffset);
- }
-
- float getDrawerViewOffset(View drawerView) {
- return ((LayoutParams) drawerView.getLayoutParams()).onScreen;
- }
-
- /**
- * @return the absolute gravity of the child drawerView, resolved according
- * to the current layout direction
- */
- int getDrawerViewAbsoluteGravity(View drawerView) {
- final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
- return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this));
- }
-
- boolean checkDrawerViewAbsoluteGravity(View drawerView, int checkFor) {
- final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
- return (absGravity & checkFor) == checkFor;
- }
-
- View findOpenDrawer() {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
- if ((childLp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
- return child;
- }
- }
- return null;
- }
-
- void moveDrawerToOffset(View drawerView, float slideOffset) {
- final float oldOffset = getDrawerViewOffset(drawerView);
- final int width = drawerView.getWidth();
- final int oldPos = (int) (width * oldOffset);
- final int newPos = (int) (width * slideOffset);
- final int dx = newPos - oldPos;
-
- drawerView.offsetLeftAndRight(
- checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT) ? dx : -dx);
- setDrawerViewOffset(drawerView, slideOffset);
- }
-
- /**
- * @param gravity the gravity of the child to return. If specified as a
- * relative value, it will be resolved according to the current
- * layout direction.
- * @return the drawer with the specified gravity
- */
- View findDrawerWithGravity(int gravity) {
- final int absHorizGravity = GravityCompat.getAbsoluteGravity(
- gravity, ViewCompat.getLayoutDirection(this)) & Gravity.HORIZONTAL_GRAVITY_MASK;
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- final int childAbsGravity = getDrawerViewAbsoluteGravity(child);
- if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizGravity) {
- return child;
- }
- }
- return null;
- }
-
- /**
- * Simple gravity to string - only supports LEFT and RIGHT for debugging output.
- *
- * @param gravity Absolute gravity value
- * @return LEFT or RIGHT as appropriate, or a hex string
- */
- static String gravityToString(@EdgeGravity int gravity) {
- if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
- return "LEFT";
- }
- if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
- return "RIGHT";
- }
- return Integer.toHexString(gravity);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mFirstLayout = true;
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mFirstLayout = true;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
- if (isInEditMode()) {
- // Don't crash the layout editor. Consume all of the space if specified
- // or pick a magic number from thin air otherwise.
- // TODO Better communication with tools of this bogus state.
- // It will crash on a real device.
- if (widthMode == MeasureSpec.AT_MOST) {
- widthMode = MeasureSpec.EXACTLY;
- } else if (widthMode == MeasureSpec.UNSPECIFIED) {
- widthMode = MeasureSpec.EXACTLY;
- widthSize = 300;
- }
- if (heightMode == MeasureSpec.AT_MOST) {
- heightMode = MeasureSpec.EXACTLY;
- }
- else if (heightMode == MeasureSpec.UNSPECIFIED) {
- heightMode = MeasureSpec.EXACTLY;
- heightSize = 300;
- }
- } else {
- throw new IllegalArgumentException(
- "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
- }
- }
-
- setMeasuredDimension(widthSize, heightSize);
-
- final boolean applyInsets = mLastInsets != null && ViewCompat.getFitsSystemWindows(this);
- final int layoutDirection = ViewCompat.getLayoutDirection(this);
-
- // Only one drawer is permitted along each vertical edge (left / right). These two booleans
- // are tracking the presence of the edge drawers.
- boolean hasDrawerOnLeftEdge = false;
- boolean hasDrawerOnRightEdge = false;
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
-
- if (child.getVisibility() == GONE) {
- continue;
- }
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (applyInsets) {
- final int cgrav = GravityCompat.getAbsoluteGravity(lp.gravity, layoutDirection);
- if (ViewCompat.getFitsSystemWindows(child)) {
- IMPL.dispatchChildInsets(child, mLastInsets, cgrav);
- } else {
- IMPL.applyMarginInsets(lp, mLastInsets, cgrav);
- }
- }
-
- if (isContentView(child)) {
- // Content views get measured at exactly the layout's size.
- final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
- widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
- final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
- heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
- child.measure(contentWidthSpec, contentHeightSpec);
- } else if (isDrawerView(child)) {
- if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
- if (ViewCompat.getElevation(child) != mDrawerElevation) {
- ViewCompat.setElevation(child, mDrawerElevation);
- }
- }
- final @EdgeGravity int childGravity =
- getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
- // Note that the isDrawerView check guarantees that childGravity here is either
- // LEFT or RIGHT
- boolean isLeftEdgeDrawer = (childGravity == Gravity.LEFT);
- if ((isLeftEdgeDrawer && hasDrawerOnLeftEdge) ||
- (!isLeftEdgeDrawer && hasDrawerOnRightEdge)) {
- throw new IllegalStateException("Child drawer has absolute gravity " +
- gravityToString(childGravity) + " but this " + TAG + " already has a " +
- "drawer view along that edge");
- }
- if (isLeftEdgeDrawer) {
- hasDrawerOnLeftEdge = true;
- } else {
- hasDrawerOnRightEdge = true;
- }
- final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
- mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
- lp.width);
- final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
- lp.topMargin + lp.bottomMargin,
- lp.height);
- child.measure(drawerWidthSpec, drawerHeightSpec);
- } else {
- throw new IllegalStateException("Child " + child + " at index " + i +
- " does not have a valid layout_gravity - must be Gravity.LEFT, " +
- "Gravity.RIGHT or Gravity.NO_GRAVITY");
- }
- }
- }
-
- private void resolveShadowDrawables() {
- if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
- return;
- }
- mShadowLeftResolved = resolveLeftShadow();
- mShadowRightResolved = resolveRightShadow();
- }
-
- private Drawable resolveLeftShadow() {
- int layoutDirection = ViewCompat.getLayoutDirection(this);
- // Prefer shadows defined with start/end gravity over left and right.
- if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
- if (mShadowStart != null) {
- // Correct drawable layout direction, if needed.
- mirror(mShadowStart, layoutDirection);
- return mShadowStart;
- }
- } else {
- if (mShadowEnd != null) {
- // Correct drawable layout direction, if needed.
- mirror(mShadowEnd, layoutDirection);
- return mShadowEnd;
- }
- }
- return mShadowLeft;
- }
-
- private Drawable resolveRightShadow() {
- int layoutDirection = ViewCompat.getLayoutDirection(this);
- if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
- if (mShadowEnd != null) {
- // Correct drawable layout direction, if needed.
- mirror(mShadowEnd, layoutDirection);
- return mShadowEnd;
- }
- } else {
- if (mShadowStart != null) {
- // Correct drawable layout direction, if needed.
- mirror(mShadowStart, layoutDirection);
- return mShadowStart;
- }
- }
- return mShadowRight;
- }
-
- /**
- * Change the layout direction of the given drawable.
- * Return true if auto-mirror is supported and drawable's layout direction can be changed.
- * Otherwise, return false.
- */
- private boolean mirror(Drawable drawable, int layoutDirection) {
- if (drawable == null || !DrawableCompat.isAutoMirrored(drawable)) {
- return false;
- }
-
- DrawableCompat.setLayoutDirection(drawable, layoutDirection);
- return true;
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mInLayout = true;
- final int width = r - l;
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
-
- if (child.getVisibility() == GONE) {
- continue;
- }
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (isContentView(child)) {
- child.layout(lp.leftMargin, lp.topMargin,
- lp.leftMargin + child.getMeasuredWidth(),
- lp.topMargin + child.getMeasuredHeight());
- } else { // Drawer, if it wasn't onMeasure would have thrown an exception.
- final int childWidth = child.getMeasuredWidth();
- final int childHeight = child.getMeasuredHeight();
- int childLeft;
-
- final float newOffset;
- if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
- childLeft = -childWidth + (int) (childWidth * lp.onScreen);
- newOffset = (float) (childWidth + childLeft) / childWidth;
- } else { // Right; onMeasure checked for us.
- childLeft = width - (int) (childWidth * lp.onScreen);
- newOffset = (float) (width - childLeft) / childWidth;
- }
-
- final boolean changeOffset = newOffset != lp.onScreen;
-
- final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (vgrav) {
- default:
- case Gravity.TOP: {
- child.layout(childLeft, lp.topMargin, childLeft + childWidth,
- lp.topMargin + childHeight);
- break;
- }
-
- case Gravity.BOTTOM: {
- final int height = b - t;
- child.layout(childLeft,
- height - lp.bottomMargin - child.getMeasuredHeight(),
- childLeft + childWidth,
- height - lp.bottomMargin);
- break;
- }
-
- case Gravity.CENTER_VERTICAL: {
- final int height = b - t;
- int childTop = (height - childHeight) / 2;
-
- // Offset for margins. If things don't fit right because of
- // bad measurement before, oh well.
- if (childTop < lp.topMargin) {
- childTop = lp.topMargin;
- } else if (childTop + childHeight > height - lp.bottomMargin) {
- childTop = height - lp.bottomMargin - childHeight;
- }
- child.layout(childLeft, childTop, childLeft + childWidth,
- childTop + childHeight);
- break;
- }
- }
-
- if (changeOffset) {
- setDrawerViewOffset(child, newOffset);
- }
-
- final int newVisibility = lp.onScreen > 0 ? VISIBLE : INVISIBLE;
- if (child.getVisibility() != newVisibility) {
- child.setVisibility(newVisibility);
- }
- }
- }
- mInLayout = false;
- mFirstLayout = false;
- }
-
- @Override
- public void requestLayout() {
- if (!mInLayout) {
- super.requestLayout();
- }
- }
-
- @Override
- public void computeScroll() {
- final int childCount = getChildCount();
- float scrimOpacity = 0;
- for (int i = 0; i < childCount; i++) {
- final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onScreen;
- scrimOpacity = Math.max(scrimOpacity, onscreen);
- }
- mScrimOpacity = scrimOpacity;
-
- // "|" used on purpose; both need to run.
- if (mLeftDragger.continueSettling(true) | mRightDragger.continueSettling(true)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }
-
- private static boolean hasOpaqueBackground(View v) {
- final Drawable bg = v.getBackground();
- if (bg != null) {
- return bg.getOpacity() == PixelFormat.OPAQUE;
- }
- return false;
- }
-
- /**
- * Set a drawable to draw in the insets area for the status bar.
- * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
- *
- * @param bg Background drawable to draw behind the status bar
- */
- public void setStatusBarBackground(Drawable bg) {
- mStatusBarBackground = bg;
- invalidate();
- }
-
- /**
- * Gets the drawable used to draw in the insets area for the status bar.
- *
- * @return The status bar background drawable, or null if none set
- */
- public Drawable getStatusBarBackgroundDrawable() {
- return mStatusBarBackground;
- }
-
- /**
- * Set a drawable to draw in the insets area for the status bar.
- * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
- *
- * @param resId Resource id of a background drawable to draw behind the status bar
- */
- public void setStatusBarBackground(int resId) {
- mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null;
- invalidate();
- }
-
- /**
- * Set a drawable to draw in the insets area for the status bar.
- * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
- *
- * @param color Color to use as a background drawable to draw behind the status bar
- * in 0xAARRGGBB format.
- */
- public void setStatusBarBackgroundColor(@ColorInt int color) {
- mStatusBarBackground = new ColorDrawable(color);
- invalidate();
- }
-
- public void onRtlPropertiesChanged(int layoutDirection) {
- resolveShadowDrawables();
- }
-
- @Override
- public void onDraw(Canvas c) {
- super.onDraw(c);
- if (mDrawStatusBarBackground && mStatusBarBackground != null) {
- final int inset = IMPL.getTopInset(mLastInsets);
- if (inset > 0) {
- mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
- mStatusBarBackground.draw(c);
- }
- }
- }
-
- @Override
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- final int height = getHeight();
- final boolean drawingContent = isContentView(child);
- int clipLeft = 0, clipRight = getWidth();
-
- final int restoreCount = canvas.save();
- if (drawingContent) {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View v = getChildAt(i);
- if (v == child || v.getVisibility() != VISIBLE ||
- !hasOpaqueBackground(v) || !isDrawerView(v) ||
- v.getHeight() < height) {
- continue;
- }
-
- if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
- final int vright = v.getRight();
- if (vright > clipLeft) clipLeft = vright;
- } else {
- final int vleft = v.getLeft();
- if (vleft < clipRight) clipRight = vleft;
- }
- }
- canvas.clipRect(clipLeft, 0, clipRight, getHeight());
- }
- final boolean result = super.drawChild(canvas, child, drawingTime);
- canvas.restoreToCount(restoreCount);
-
- if (mScrimOpacity > 0 && drawingContent) {
- final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
- final int imag = (int) (baseAlpha * mScrimOpacity);
- final int color = imag << 24 | (mScrimColor & 0xffffff);
- mScrimPaint.setColor(color);
-
- canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint);
- } else if (mShadowLeftResolved != null
- && checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
- final int shadowWidth = mShadowLeftResolved.getIntrinsicWidth();
- final int childRight = child.getRight();
- final int drawerPeekDistance = mLeftDragger.getEdgeSize();
- final float alpha =
- Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f));
- mShadowLeftResolved.setBounds(childRight, child.getTop(),
- childRight + shadowWidth, child.getBottom());
- mShadowLeftResolved.setAlpha((int) (0xff * alpha));
- mShadowLeftResolved.draw(canvas);
- } else if (mShadowRightResolved != null
- && checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) {
- final int shadowWidth = mShadowRightResolved.getIntrinsicWidth();
- final int childLeft = child.getLeft();
- final int showing = getWidth() - childLeft;
- final int drawerPeekDistance = mRightDragger.getEdgeSize();
- final float alpha =
- Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f));
- mShadowRightResolved.setBounds(childLeft - shadowWidth, child.getTop(),
- childLeft, child.getBottom());
- mShadowRightResolved.setAlpha((int) (0xff * alpha));
- mShadowRightResolved.draw(canvas);
- }
- return result;
- }
-
- boolean isContentView(View child) {
- return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
- }
-
- boolean isDrawerView(View child) {
- final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
- final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
- ViewCompat.getLayoutDirection(child));
- if ((absGravity & Gravity.LEFT) != 0) {
- // This child is a left-edge drawer
- return true;
- }
- if ((absGravity & Gravity.RIGHT) != 0) {
- // This child is a right-edge drawer
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- final int action = MotionEventCompat.getActionMasked(ev);
-
- // "|" used deliberately here; both methods should be invoked.
- final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) |
- mRightDragger.shouldInterceptTouchEvent(ev);
-
- boolean interceptForTap = false;
-
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- mInitialMotionX = x;
- mInitialMotionY = y;
- if (mScrimOpacity > 0) {
- final View child = mLeftDragger.findTopChildUnder((int) x, (int) y);
- if (child != null && isContentView(child)) {
- interceptForTap = true;
- }
- }
- mDisallowInterceptRequested = false;
- mChildrenCanceledTouch = false;
- break;
- }
-
- case MotionEvent.ACTION_MOVE: {
- // If we cross the touch slop, don't perform the delayed peek for an edge touch.
- if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
- mLeftCallback.removeCallbacks();
- mRightCallback.removeCallbacks();
- }
- break;
- }
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP: {
- closeDrawers(true);
- mDisallowInterceptRequested = false;
- mChildrenCanceledTouch = false;
- }
- }
-
- return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- mLeftDragger.processTouchEvent(ev);
- mRightDragger.processTouchEvent(ev);
-
- final int action = ev.getAction();
- boolean wantTouchEvents = true;
-
- switch (action & MotionEventCompat.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- mInitialMotionX = x;
- mInitialMotionY = y;
- mDisallowInterceptRequested = false;
- mChildrenCanceledTouch = false;
- break;
- }
-
- case MotionEvent.ACTION_UP: {
- final float x = ev.getX();
- final float y = ev.getY();
- boolean peekingOnly = true;
- final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y);
- if (touchedView != null && isContentView(touchedView)) {
- final float dx = x - mInitialMotionX;
- final float dy = y - mInitialMotionY;
- final int slop = mLeftDragger.getTouchSlop();
- if (dx * dx + dy * dy < slop * slop) {
- // Taps close a dimmed open drawer but only if it isn't locked open.
- final View openDrawer = findOpenDrawer();
- if (openDrawer != null) {
- peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN;
- }
- }
- }
- closeDrawers(peekingOnly);
- mDisallowInterceptRequested = false;
- break;
- }
-
- case MotionEvent.ACTION_CANCEL: {
- closeDrawers(true);
- mDisallowInterceptRequested = false;
- mChildrenCanceledTouch = false;
- break;
- }
- }
-
- return wantTouchEvents;
- }
-
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- if (CHILDREN_DISALLOW_INTERCEPT ||
- (!mLeftDragger.isEdgeTouched(ViewDragHelper.EDGE_LEFT) &&
- !mRightDragger.isEdgeTouched(ViewDragHelper.EDGE_RIGHT))) {
- // If we have an edge touch we want to skip this and track it for later instead.
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
- mDisallowInterceptRequested = disallowIntercept;
- if (disallowIntercept) {
- closeDrawers(true);
- }
- }
-
- /**
- * Close all currently open drawer views by animating them out of view.
- */
- public void closeDrawers() {
- closeDrawers(false);
- }
-
- void closeDrawers(boolean peekingOnly) {
- boolean needsInvalidate = false;
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) {
- continue;
- }
-
- final int childWidth = child.getWidth();
-
- if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
- needsInvalidate |= mLeftDragger.smoothSlideViewTo(child,
- -childWidth, child.getTop());
- } else {
- needsInvalidate |= mRightDragger.smoothSlideViewTo(child,
- getWidth(), child.getTop());
- }
-
- lp.isPeeking = false;
- }
-
- mLeftCallback.removeCallbacks();
- mRightCallback.removeCallbacks();
-
- if (needsInvalidate) {
- invalidate();
- }
- }
-
- /**
- * Open the specified drawer view by animating it into view.
- *
- * @param drawerView Drawer view to open
- */
- public void openDrawer(View drawerView) {
- openDrawer(drawerView, true);
- }
-
- /**
- * Open the specified drawer view.
- *
- * @param drawerView Drawer view to open
- * @param animate Whether opening of the drawer should be animated.
- */
- public void openDrawer(View drawerView, boolean animate) {
- if (!isDrawerView(drawerView)) {
- throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
- }
-
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if (mFirstLayout) {
- lp.onScreen = 1.f;
- lp.openState = LayoutParams.FLAG_IS_OPENED;
-
- updateChildrenImportantForAccessibility(drawerView, true);
- } else if (animate) {
- lp.openState |= LayoutParams.FLAG_IS_OPENING;
-
- if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
- mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
- } else {
- mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
- drawerView.getTop());
- }
- } else {
- moveDrawerToOffset(drawerView, 1.f);
- updateDrawerState(lp.gravity, STATE_IDLE, drawerView);
- drawerView.setVisibility(VISIBLE);
- }
- invalidate();
- }
-
- /**
- * Open the specified drawer by animating it out of view.
- *
- * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
- * GravityCompat.START or GravityCompat.END may also be used.
- */
- public void openDrawer(@EdgeGravity int gravity) {
- openDrawer(gravity, true);
- }
-
- /**
- * Open the specified drawer.
- *
- * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
- * GravityCompat.START or GravityCompat.END may also be used.
- * @param animate Whether opening of the drawer should be animated.
- */
- public void openDrawer(@EdgeGravity int gravity, boolean animate) {
- final View drawerView = findDrawerWithGravity(gravity);
- if (drawerView == null) {
- throw new IllegalArgumentException("No drawer view found with gravity " +
- gravityToString(gravity));
- }
- openDrawer(drawerView, animate);
- }
-
- /**
- * Close the specified drawer view by animating it into view.
- *
- * @param drawerView Drawer view to close
- */
- public void closeDrawer(View drawerView) {
- closeDrawer(drawerView, true);
- }
-
- /**
- * Close the specified drawer view.
- *
- * @param drawerView Drawer view to close
- * @param animate Whether closing of the drawer should be animated.
- */
- public void closeDrawer(View drawerView, boolean animate) {
- if (!isDrawerView(drawerView)) {
- throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
- }
-
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if (mFirstLayout) {
- lp.onScreen = 0.f;
- lp.openState = 0;
- } else if (animate) {
- lp.openState |= LayoutParams.FLAG_IS_CLOSING;
-
- if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
- mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(),
- drawerView.getTop());
- } else {
- mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop());
- }
- } else {
- moveDrawerToOffset(drawerView, 0.f);
- updateDrawerState(lp.gravity, STATE_IDLE, drawerView);
- drawerView.setVisibility(INVISIBLE);
- }
- invalidate();
- }
-
- /**
- * Close the specified drawer by animating it out of view.
- *
- * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
- * GravityCompat.START or GravityCompat.END may also be used.
- */
- public void closeDrawer(@EdgeGravity int gravity) {
- closeDrawer(gravity, true);
- }
-
- /**
- * Close the specified drawer.
- *
- * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
- * GravityCompat.START or GravityCompat.END may also be used.
- * @param animate Whether closing of the drawer should be animated.
- */
- public void closeDrawer(@EdgeGravity int gravity, boolean animate) {
- final View drawerView = findDrawerWithGravity(gravity);
- if (drawerView == null) {
- throw new IllegalArgumentException("No drawer view found with gravity " +
- gravityToString(gravity));
- }
- closeDrawer(drawerView, animate);
- }
-
- /**
- * Check if the given drawer view is currently in an open state.
- * To be considered "open" the drawer must have settled into its fully
- * visible state. To check for partial visibility use
- * {@link #isDrawerVisible(android.view.View)}.
- *
- * @param drawer Drawer view to check
- * @return true if the given drawer view is in an open state
- * @see #isDrawerVisible(android.view.View)
- */
- public boolean isDrawerOpen(View drawer) {
- if (!isDrawerView(drawer)) {
- throw new IllegalArgumentException("View " + drawer + " is not a drawer");
- }
- LayoutParams drawerLp = (LayoutParams) drawer.getLayoutParams();
- return (drawerLp.openState & LayoutParams.FLAG_IS_OPENED) == 1;
- }
-
- /**
- * Check if the given drawer view is currently in an open state.
- * To be considered "open" the drawer must have settled into its fully
- * visible state. If there is no drawer with the given gravity this method
- * will return false.
- *
- * @param drawerGravity Gravity of the drawer to check
- * @return true if the given drawer view is in an open state
- */
- public boolean isDrawerOpen(@EdgeGravity int drawerGravity) {
- final View drawerView = findDrawerWithGravity(drawerGravity);
- if (drawerView != null) {
- return isDrawerOpen(drawerView);
- }
- return false;
- }
-
- /**
- * Check if a given drawer view is currently visible on-screen. The drawer
- * may be only peeking onto the screen, fully extended, or anywhere inbetween.
- *
- * @param drawer Drawer view to check
- * @return true if the given drawer is visible on-screen
- * @see #isDrawerOpen(android.view.View)
- */
- public boolean isDrawerVisible(View drawer) {
- if (!isDrawerView(drawer)) {
- throw new IllegalArgumentException("View " + drawer + " is not a drawer");
- }
- return ((LayoutParams) drawer.getLayoutParams()).onScreen > 0;
- }
-
- /**
- * Check if a given drawer view is currently visible on-screen. The drawer
- * may be only peeking onto the screen, fully extended, or anywhere in between.
- * If there is no drawer with the given gravity this method will return false.
- *
- * @param drawerGravity Gravity of the drawer to check
- * @return true if the given drawer is visible on-screen
- */
- public boolean isDrawerVisible(@EdgeGravity int drawerGravity) {
- final View drawerView = findDrawerWithGravity(drawerGravity);
- if (drawerView != null) {
- return isDrawerVisible(drawerView);
- }
- return false;
- }
-
- private boolean hasPeekingDrawer() {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
- if (lp.isPeeking) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
- return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
- }
-
- @Override
- protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
- return p instanceof LayoutParams
- ? new LayoutParams((LayoutParams) p)
- : p instanceof ViewGroup.MarginLayoutParams
- ? new LayoutParams((MarginLayoutParams) p)
- : new LayoutParams(p);
- }
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- return p instanceof LayoutParams && super.checkLayoutParams(p);
- }
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new LayoutParams(getContext(), attrs);
- }
-
- @Override
- public void addFocusables(ArrayList views, int direction, int focusableMode) {
- if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
- return;
- }
-
- // Only the views in the open drawers are focusables. Add normal child views when
- // no drawers are opened.
- final int childCount = getChildCount();
- boolean isDrawerOpen = false;
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (isDrawerView(child)) {
- if (isDrawerOpen(child)) {
- isDrawerOpen = true;
- child.addFocusables(views, direction, focusableMode);
- }
- } else {
- mNonDrawerViews.add(child);
- }
- }
-
- if (!isDrawerOpen) {
- final int nonDrawerViewsCount = mNonDrawerViews.size();
- for (int i = 0; i < nonDrawerViewsCount; ++i) {
- final View child = mNonDrawerViews.get(i);
- if (child.getVisibility() == View.VISIBLE) {
- child.addFocusables(views, direction, focusableMode);
- }
- }
- }
-
- mNonDrawerViews.clear();
- }
-
- private boolean hasVisibleDrawer() {
- return findVisibleDrawer() != null;
- }
-
- private View findVisibleDrawer() {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (isDrawerView(child) && isDrawerVisible(child)) {
- return child;
- }
- }
- return null;
- }
-
- void cancelChildViewTouch() {
- // Cancel child touches
- if (!mChildrenCanceledTouch) {
- final long now = SystemClock.uptimeMillis();
- final MotionEvent cancelEvent = MotionEvent.obtain(now, now,
- MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- getChildAt(i).dispatchTouchEvent(cancelEvent);
- }
- cancelEvent.recycle();
- mChildrenCanceledTouch = true;
- }
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && hasVisibleDrawer()) {
- KeyEventCompat.startTracking(event);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- final View visibleDrawer = findVisibleDrawer();
- if (visibleDrawer != null && getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED) {
- closeDrawers();
- }
- return visibleDrawer != null;
- }
- return super.onKeyUp(keyCode, event);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- if (!(state instanceof SavedState)) {
- super.onRestoreInstanceState(state);
- return;
- }
-
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
-
- if (ss.openDrawerGravity != Gravity.NO_GRAVITY) {
- final View toOpen = findDrawerWithGravity(ss.openDrawerGravity);
- if (toOpen != null) {
- openDrawer(toOpen);
- }
- }
-
- if (ss.lockModeLeft != LOCK_MODE_UNDEFINED) {
- setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
- }
- if (ss.lockModeRight != LOCK_MODE_UNDEFINED) {
- setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
- }
- if (ss.lockModeStart != LOCK_MODE_UNDEFINED) {
- setDrawerLockMode(ss.lockModeStart, GravityCompat.START);
- }
- if (ss.lockModeEnd != LOCK_MODE_UNDEFINED) {
- setDrawerLockMode(ss.lockModeEnd, GravityCompat.END);
- }
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- final Parcelable superState = super.onSaveInstanceState();
- final SavedState ss = new SavedState(superState);
-
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- // Is the current child fully opened (that is, not closing)?
- boolean isOpenedAndNotClosing = (lp.openState == LayoutParams.FLAG_IS_OPENED);
- // Is the current child opening?
- boolean isClosedAndOpening = (lp.openState == LayoutParams.FLAG_IS_OPENING);
- if (isOpenedAndNotClosing || isClosedAndOpening) {
- // If one of the conditions above holds, save the child's gravity
- // so that we open that child during state restore.
- ss.openDrawerGravity = lp.gravity;
- break;
- }
- }
-
- ss.lockModeLeft = mLockModeLeft;
- ss.lockModeRight = mLockModeRight;
- ss.lockModeStart = mLockModeStart;
- ss.lockModeEnd = mLockModeEnd;
-
- return ss;
- }
-
- @Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
- super.addView(child, index, params);
-
- final View openDrawer = findOpenDrawer();
- if (openDrawer != null || isDrawerView(child)) {
- // A drawer is already open or the new view is a drawer, so the
- // new view should start out hidden.
- ViewCompat.setImportantForAccessibility(child,
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- } else {
- // Otherwise this is a content view and no drawer is open, so the
- // new view should start out visible.
- ViewCompat.setImportantForAccessibility(child,
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
-
- // We only need a delegate here if the framework doesn't understand
- // NO_HIDE_DESCENDANTS importance.
- if (!CAN_HIDE_DESCENDANTS) {
- ViewCompat.setAccessibilityDelegate(child, mChildAccessibilityDelegate);
- }
- }
-
- private static boolean includeChildForAccessibility(View child) {
- // If the child is not important for accessibility we make
- // sure this hides the entire subtree rooted at it as the
- // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not
- // supported on older platforms but we want to hide the entire
- // content and not opened drawers if a drawer is opened.
- return ViewCompat.getImportantForAccessibility(child)
- != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- && ViewCompat.getImportantForAccessibility(child)
- != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO;
- }
-
- /**
- * State persisted across instances
- */
- protected static class SavedState extends AbsSavedState {
- int openDrawerGravity = Gravity.NO_GRAVITY;
- @LockMode int lockModeLeft;
- @LockMode int lockModeRight;
- @LockMode int lockModeStart;
- @LockMode int lockModeEnd;
-
- public SavedState(Parcel in, ClassLoader loader) {
- super(in, loader);
- openDrawerGravity = in.readInt();
- lockModeLeft = in.readInt();
- lockModeRight = in.readInt();
- lockModeStart = in.readInt();
- lockModeEnd = in.readInt();
- }
-
- public SavedState(Parcelable superState) {
- super(superState);
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(openDrawerGravity);
- dest.writeInt(lockModeLeft);
- dest.writeInt(lockModeRight);
- dest.writeInt(lockModeStart);
- dest.writeInt(lockModeEnd);
- }
-
- public static final Creator CREATOR = ParcelableCompat.newCreator(
- new ParcelableCompatCreatorCallbacks() {
- @Override
- public SavedState createFromParcel(Parcel in, ClassLoader loader) {
- return new SavedState(in, loader);
- }
-
- @Override
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- });
- }
-
- private class ViewDragCallback extends ViewDragHelper.Callback {
- private final int mAbsGravity;
- private ViewDragHelper mDragger;
-
- private final Runnable mPeekRunnable = new Runnable() {
- @Override public void run() {
- peekDrawer();
- }
- };
-
- public ViewDragCallback(int gravity) {
- mAbsGravity = gravity;
- }
-
- public void setDragger(ViewDragHelper dragger) {
- mDragger = dragger;
- }
-
- public void removeCallbacks() {
- DrawerLayout.this.removeCallbacks(mPeekRunnable);
- }
-
- @Override
- public boolean tryCaptureView(View child, int pointerId) {
- // Only capture views where the gravity matches what we're looking for.
- // This lets us use two ViewDragHelpers, one for each side drawer.
- return isDrawerView(child) && checkDrawerViewAbsoluteGravity(child, mAbsGravity)
- && getDrawerLockMode(child) == LOCK_MODE_UNLOCKED;
- }
-
- @Override
- public void onViewDragStateChanged(int state) {
- updateDrawerState(mAbsGravity, state, mDragger.getCapturedView());
- }
-
- @Override
- public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
- float offset;
- final int childWidth = changedView.getWidth();
-
- // This reverses the positioning shown in onLayout.
- if (checkDrawerViewAbsoluteGravity(changedView, Gravity.LEFT)) {
- offset = (float) (childWidth + left) / childWidth;
- } else {
- final int width = getWidth();
- offset = (float) (width - left) / childWidth;
- }
- setDrawerViewOffset(changedView, offset);
- changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE);
- invalidate();
- }
-
- @Override
- public void onViewCaptured(View capturedChild, int activePointerId) {
- final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams();
- lp.isPeeking = false;
-
- closeOtherDrawer();
- }
-
- private void closeOtherDrawer() {
- final int otherGrav = mAbsGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT;
- final View toClose = findDrawerWithGravity(otherGrav);
- if (toClose != null) {
- closeDrawer(toClose);
- }
- }
-
- @Override
- public void onViewReleased(View releasedChild, float xvel, float yvel) {
- // Offset is how open the drawer is, therefore left/right values
- // are reversed from one another.
- final float offset = getDrawerViewOffset(releasedChild);
- final int childWidth = releasedChild.getWidth();
-
- int left;
- if (checkDrawerViewAbsoluteGravity(releasedChild, Gravity.LEFT)) {
- left = xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth;
- } else {
- final int width = getWidth();
- left = xvel < 0 || xvel == 0 && offset > 0.5f ? width - childWidth : width;
- }
-
- mDragger.settleCapturedViewAt(left, releasedChild.getTop());
- invalidate();
- }
-
- @Override
- public void onEdgeTouched(int edgeFlags, int pointerId) {
- postDelayed(mPeekRunnable, PEEK_DELAY);
- }
-
- private void peekDrawer() {
- final View toCapture;
- final int childLeft;
- final int peekDistance = mDragger.getEdgeSize();
- final boolean leftEdge = mAbsGravity == Gravity.LEFT;
- if (leftEdge) {
- toCapture = findDrawerWithGravity(Gravity.LEFT);
- childLeft = (toCapture != null ? -toCapture.getWidth() : 0) + peekDistance;
- } else {
- toCapture = findDrawerWithGravity(Gravity.RIGHT);
- childLeft = getWidth() - peekDistance;
- }
- // Only peek if it would mean making the drawer more visible and the drawer isn't locked
- if (toCapture != null && ((leftEdge && toCapture.getLeft() < childLeft) ||
- (!leftEdge && toCapture.getLeft() > childLeft)) &&
- getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
- final LayoutParams lp = (LayoutParams) toCapture.getLayoutParams();
- mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop());
- lp.isPeeking = true;
- invalidate();
-
- closeOtherDrawer();
-
- cancelChildViewTouch();
- }
- }
-
- @Override
- public boolean onEdgeLock(int edgeFlags) {
- if (ALLOW_EDGE_LOCK) {
- final View drawer = findDrawerWithGravity(mAbsGravity);
- if (drawer != null && !isDrawerOpen(drawer)) {
- closeDrawer(drawer);
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void onEdgeDragStarted(int edgeFlags, int pointerId) {
- final View toCapture;
- if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {
- toCapture = findDrawerWithGravity(Gravity.LEFT);
- } else {
- toCapture = findDrawerWithGravity(Gravity.RIGHT);
- }
-
- if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
- mDragger.captureChildView(toCapture, pointerId);
- }
- }
-
- @Override
- public int getViewHorizontalDragRange(View child) {
- return isDrawerView(child) ? child.getWidth() : 0;
- }
-
- @Override
- public int clampViewPositionHorizontal(View child, int left, int dx) {
- if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
- return Math.max(-child.getWidth(), Math.min(left, 0));
- } else {
- final int width = getWidth();
- return Math.max(width - child.getWidth(), Math.min(left, width));
- }
- }
-
- @Override
- public int clampViewPositionVertical(View child, int top, int dy) {
- return child.getTop();
- }
- }
-
- public static class LayoutParams extends ViewGroup.MarginLayoutParams {
- private static final int FLAG_IS_OPENED = 0x1;
- private static final int FLAG_IS_OPENING = 0x2;
- private static final int FLAG_IS_CLOSING = 0x4;
-
- public int gravity = Gravity.NO_GRAVITY;
- private float onScreen;
- private boolean isPeeking;
- private int openState;
-
- public LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
-
- final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
- this.gravity = a.getInt(0, Gravity.NO_GRAVITY);
- a.recycle();
- }
-
- public LayoutParams(int width, int height) {
- super(width, height);
- }
-
- public LayoutParams(int width, int height, int gravity) {
- this(width, height);
- this.gravity = gravity;
- }
-
- public LayoutParams(LayoutParams source) {
- super(source);
- this.gravity = source.gravity;
- }
-
- public LayoutParams(ViewGroup.LayoutParams source) {
- super(source);
- }
-
- public LayoutParams(ViewGroup.MarginLayoutParams source) {
- super(source);
- }
- }
-
- class AccessibilityDelegate extends AccessibilityDelegateCompat {
- private final Rect mTmpRect = new Rect();
-
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
- if (CAN_HIDE_DESCENDANTS) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- } else {
- // Obtain a node for the host, then manually generate the list
- // of children to only include non-obscured views.
- final AccessibilityNodeInfoCompat superNode =
- AccessibilityNodeInfoCompat.obtain(info);
- super.onInitializeAccessibilityNodeInfo(host, superNode);
-
- info.setSource(host);
- final ViewParent parent = ViewCompat.getParentForAccessibility(host);
- if (parent instanceof View) {
- info.setParent((View) parent);
- }
- copyNodeInfoNoChildren(info, superNode);
- superNode.recycle();
-
- addChildrenForAccessibility(info, (ViewGroup) host);
- }
-
- info.setClassName(DrawerLayout.class.getName());
-
- // This view reports itself as focusable so that it can intercept
- // the back button, but we should prevent this view from reporting
- // itself as focusable to accessibility services.
- info.setFocusable(false);
- info.setFocused(false);
- info.removeAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_FOCUS);
- info.removeAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLEAR_FOCUS);
- }
-
- @Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(host, event);
-
- event.setClassName(DrawerLayout.class.getName());
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- // Special case to handle window state change events. As far as
- // accessibility services are concerned, state changes from
- // DrawerLayout invalidate the entire contents of the screen (like
- // an Activity or Dialog) and they should announce the title of the
- // new content.
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- final List eventText = event.getText();
- final View visibleDrawer = findVisibleDrawer();
- if (visibleDrawer != null) {
- final int edgeGravity = getDrawerViewAbsoluteGravity(visibleDrawer);
- final CharSequence title = getDrawerTitle(edgeGravity);
- if (title != null) {
- eventText.add(title);
- }
- }
-
- return true;
- }
-
- return super.dispatchPopulateAccessibilityEvent(host, event);
- }
-
- @Override
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- if (CAN_HIDE_DESCENDANTS || includeChildForAccessibility(child)) {
- return super.onRequestSendAccessibilityEvent(host, child, event);
- }
- return false;
- }
-
- private void addChildrenForAccessibility(AccessibilityNodeInfoCompat info, ViewGroup v) {
- final int childCount = v.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = v.getChildAt(i);
- if (includeChildForAccessibility(child)) {
- info.addChild(child);
- }
- }
- }
-
- /**
- * This should really be in AccessibilityNodeInfoCompat, but there unfortunately
- * seem to be a few elements that are not easily cloneable using the underlying API.
- * Leave it private here as it's not general-purpose useful.
- */
- private void copyNodeInfoNoChildren(AccessibilityNodeInfoCompat dest,
- AccessibilityNodeInfoCompat src) {
- final Rect rect = mTmpRect;
-
- src.getBoundsInParent(rect);
- dest.setBoundsInParent(rect);
-
- src.getBoundsInScreen(rect);
- dest.setBoundsInScreen(rect);
-
- dest.setVisibleToUser(src.isVisibleToUser());
- dest.setPackageName(src.getPackageName());
- dest.setClassName(src.getClassName());
- dest.setContentDescription(src.getContentDescription());
-
- dest.setEnabled(src.isEnabled());
- dest.setClickable(src.isClickable());
- dest.setFocusable(src.isFocusable());
- dest.setFocused(src.isFocused());
- dest.setAccessibilityFocused(src.isAccessibilityFocused());
- dest.setSelected(src.isSelected());
- dest.setLongClickable(src.isLongClickable());
-
- dest.addAction(src.getActions());
- }
- }
-
- final class ChildAccessibilityDelegate extends AccessibilityDelegateCompat {
- @Override
- public void onInitializeAccessibilityNodeInfo(View child,
- AccessibilityNodeInfoCompat info) {
- super.onInitializeAccessibilityNodeInfo(child, info);
-
- if (!includeChildForAccessibility(child)) {
- // If we are ignoring the sub-tree rooted at the child,
- // break the connection to the rest of the node tree.
- // For details refer to includeChildForAccessibility.
- info.setParent(null);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayoutCompatApi21.java b/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayoutCompatApi21.java
deleted file mode 100644
index 109dd14..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayoutCompatApi21.java
+++ /dev/null
@@ -1,75 +0,0 @@
-
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-
-class DrawerLayoutCompatApi21 {
-
- private static final int[] THEME_ATTRS = {
- android.R.attr.colorPrimaryDark
- };
-
- public static void configureApplyInsets(View drawerLayout) {
- if (drawerLayout instanceof DrawerLayoutImpl) {
- drawerLayout.setOnApplyWindowInsetsListener(new InsetsListener());
- drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- }
- }
-
- public static void dispatchChildInsets(View child, Object insets, int gravity) {
- WindowInsets wi = (WindowInsets) insets;
- if (gravity == Gravity.LEFT) {
- wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(),
- wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom());
- } else if (gravity == Gravity.RIGHT) {
- wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(),
- wi.getSystemWindowInsetRight(), wi.getSystemWindowInsetBottom());
- }
- child.dispatchApplyWindowInsets(wi);
- }
-
- public static void applyMarginInsets(ViewGroup.MarginLayoutParams lp, Object insets,
- int gravity) {
- WindowInsets wi = (WindowInsets) insets;
- if (gravity == Gravity.LEFT) {
- wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(),
- wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom());
- } else if (gravity == Gravity.RIGHT) {
- wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(),
- wi.getSystemWindowInsetRight(), wi.getSystemWindowInsetBottom());
- }
- lp.leftMargin = wi.getSystemWindowInsetLeft();
- lp.topMargin = wi.getSystemWindowInsetTop();
- lp.rightMargin = wi.getSystemWindowInsetRight();
- lp.bottomMargin = wi.getSystemWindowInsetBottom();
- }
-
- public static int getTopInset(Object insets) {
- return insets != null ? ((WindowInsets) insets).getSystemWindowInsetTop() : 0;
- }
-
- public static Drawable getDefaultStatusBarBackground(Context context) {
- final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS);
- try {
- return a.getDrawable(0);
- } finally {
- a.recycle();
- }
- }
-
- static class InsetsListener implements View.OnApplyWindowInsetsListener {
- @Override
- public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- final DrawerLayoutImpl drawerLayout = (DrawerLayoutImpl) v;
- drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
- return insets.consumeSystemWindowInsets();
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayoutImpl.java b/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayoutImpl.java
deleted file mode 100644
index 6707d50..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/DrawerLayoutImpl.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-interface DrawerLayoutImpl {
- void setChildInsets(Object insets, boolean drawStatusBar);
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundProgressRelativeLayout.java b/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundProgressRelativeLayout.java
deleted file mode 100644
index a84e4ed..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundProgressRelativeLayout.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.v4.content.ContextCompat;
-import android.util.AttributeSet;
-
-import com.loopeer.codereader.R;
-
-public class ForegroundProgressRelativeLayout extends ForegroundRelativeLayout {
-
- private Paint mRemainderPaint;
- private Paint mProgressPaint;
-
- private float mProgressCurrent;
- private float mProgressPre;
- private float mProgressShow;
- private boolean mIsUnzip;
- private int mRemainderColor;
- private static int sProgressTextPadding;
- private static int sUnzipTextPadding;
-
- public ForegroundProgressRelativeLayout(Context context) {
- super(context);
- }
-
- public ForegroundProgressRelativeLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ForegroundProgressRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ForegroundProgressRelativeLayout,
- defStyle, 0);
- mRemainderColor = a.getColor(R.styleable.ForegroundProgressRelativeLayout_remainderColor
- , ContextCompat.getColor(getContext(), R.color.repo_download_remainder_color));
- init();
- setWillNotDraw(false);
- }
-
- private void init() {
- sProgressTextPadding = getResources().getDimensionPixelSize(R.dimen.inline_padding);
- sUnzipTextPadding = getResources().getDimensionPixelSize(R.dimen.medium_padding);
-
- mRemainderPaint = new Paint();
- mRemainderPaint.setColor(mRemainderColor);
- mRemainderPaint.setStyle(Paint.Style.FILL);
-
- mProgressPaint = new Paint();
- mProgressPaint.setAntiAlias(true);
- mProgressPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorPrimary));
- mProgressPaint.setStyle(Paint.Style.FILL);
- mProgressPaint.setTextSize(getResources().getDimension(R.dimen.text_size_xxsmall));
- }
-
- public void setProgressCurrent(float i) {
- if (mProgressCurrent != i && i != 0f) {
- mProgressPre = mProgressCurrent;
- mProgressCurrent = i;
- postProgressAnimation();
- } else if (i == 0f){
- mProgressCurrent = i;
- mProgressShow = 0;
- invalidate();
- }
- }
-
- public void setInitProgress(float i) {
- mProgressPre = i;
- mProgressCurrent = i;
- mProgressShow = i;
- invalidate();
- }
-
- private void postProgressAnimation() {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f);
- valueAnimator.addUpdateListener(valueAnimator1 -> {
- float fraction = valueAnimator1.getAnimatedFraction();
- mProgressShow = mProgressPre + fraction * (mProgressCurrent - mProgressPre);
- invalidate();
- });
- valueAnimator.setDuration(500);
- valueAnimator.start();
- }
-
- public void setUnzip(boolean b) {
- mIsUnzip = b;
- if (mProgressCurrent == 1.f) {
- invalidate();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mProgressCurrent <= 1f) {
- canvas.drawRect(getWidth() * mProgressShow, 0, getWidth(), getHeight(), mRemainderPaint);
- String content = String.format("%.0f", mProgressShow * 100) + "%";
- Rect bounds = new Rect();
- mProgressPaint.getTextBounds(content, 0, content.length(), bounds);
- if (getWidth() * (1 - mProgressShow) > bounds.width()) {
- canvas.drawText(content
- , getWidth() * mProgressShow + sProgressTextPadding
- , getHeight() - sProgressTextPadding
- , mProgressPaint);
- }
- }
-
- if (mProgressCurrent == 1f && mIsUnzip) {
- String content = getResources().getString(R.string.repo_download_isunzip);
- Rect bounds = new Rect();
- mProgressPaint.getTextBounds(content, 0, content.length(), bounds);
- canvas.drawText(content
- , getWidth() - sUnzipTextPadding - bounds.width()
- , getHeight() - sProgressTextPadding
- , mProgressPaint);
- }
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundRelativeLayout.java b/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundRelativeLayout.java
deleted file mode 100644
index c85468e..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundRelativeLayout.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.loopeer.codereader.ui.view;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.widget.RelativeLayout;
-
-import com.loopeer.codereader.R;
-
-public class ForegroundRelativeLayout extends RelativeLayout {
-
- private Drawable mForeground;
-
- private final Rect mSelfBounds = new Rect();
- private final Rect mOverlayBounds = new Rect();
-
- private int mForegroundGravity = Gravity.FILL;
-
- protected boolean mForegroundInPadding = true;
-
- boolean mForegroundBoundsChanged = false;
-
- public ForegroundRelativeLayout(Context context) {
- super(context);
- }
-
- public ForegroundRelativeLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ForegroundRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundRelativeLayout,
- defStyle, 0);
-
- mForegroundGravity = a.getInt(
- R.styleable.ForegroundRelativeLayout_android_foregroundGravity, mForegroundGravity);
-
- final Drawable d = a.getDrawable(R.styleable.ForegroundRelativeLayout_android_foreground);
- if (d != null) {
- setForeground(d);
- }
-
- mForegroundInPadding = a.getBoolean(
- R.styleable.ForegroundRelativeLayout_android_foregroundInsidePadding, true);
-
- a.recycle();
- }
-
- /**
- * Describes how the foreground is positioned.
- *
- * @return foreground gravity.
- * @see #setForegroundGravity(int)
- */
- public int getForegroundGravity() {
- return mForegroundGravity;
- }
-
- /**
- * Describes how the foreground is positioned. Defaults to START and TOP.
- *
- * @param foregroundGravity See {@link Gravity}
- * @see #getForegroundGravity()
- */
- public void setForegroundGravity(int foregroundGravity) {
- if (mForegroundGravity != foregroundGravity) {
- if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
- foregroundGravity |= Gravity.START;
- }
-
- if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
- foregroundGravity |= Gravity.TOP;
- }
-
- mForegroundGravity = foregroundGravity;
-
-
- if (mForegroundGravity == Gravity.FILL && mForeground != null) {
- Rect padding = new Rect();
- mForeground.getPadding(padding);
- }
-
- requestLayout();
- }
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return super.verifyDrawable(who) || (who == mForeground);
- }
-
- @Override
- public void jumpDrawablesToCurrentState() {
- super.jumpDrawablesToCurrentState();
- if (mForeground != null) mForeground.jumpToCurrentState();
- }
-
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- if (mForeground != null && mForeground.isStateful()) {
- mForeground.setState(getDrawableState());
- }
- }
-
- /**
- * Supply a Drawable that is to be rendered on top of all of the child
- * views in the frame layout. Any padding in the Drawable will be taken
- * into account by ensuring that the children are inset to be placed
- * inside of the padding area.
- *
- * @param drawable The Drawable to be drawn on top of the children.
- */
- public void setForeground(Drawable drawable) {
- if (mForeground != drawable) {
- if (mForeground != null) {
- mForeground.setCallback(null);
- unscheduleDrawable(mForeground);
- }
-
- mForeground = drawable;
-
- if (drawable != null) {
- setWillNotDraw(false);
- drawable.setCallback(this);
- if (drawable.isStateful()) {
- drawable.setState(getDrawableState());
- }
- if (mForegroundGravity == Gravity.FILL) {
- Rect padding = new Rect();
- drawable.getPadding(padding);
- }
- } else {
- setWillNotDraw(true);
- }
- requestLayout();
- invalidate();
- }
- }
-
- /**
- * Returns the drawable used as the foreground of this FrameLayout. The
- * foreground drawable, if non-null, is always drawn on top of the children.
- *
- * @return A Drawable or null if no foreground was set.
- */
- public Drawable getForeground() {
- return mForeground;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed)
- mForegroundBoundsChanged = changed;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mForegroundBoundsChanged = true;
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (mForeground != null) {
- final Drawable foreground = mForeground;
-
- if (mForegroundBoundsChanged) {
- mForegroundBoundsChanged = false;
- final Rect selfBounds = mSelfBounds;
- final Rect overlayBounds = mOverlayBounds;
-
- final int w = getRight() - getLeft();
- final int h = getBottom() - getTop();
-
- if (mForegroundInPadding) {
- selfBounds.set(0, 0, w, h);
- } else {
- selfBounds.set(getPaddingLeft(), getPaddingTop(),
- w - getPaddingRight(), h - getPaddingBottom());
- }
-
- Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
- foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
- foreground.setBounds(overlayBounds);
- }
-
- foreground.draw(canvas);
- }
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- @Override
- public void drawableHotspotChanged(float x, float y) {
- super.drawableHotspotChanged(x, y);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- if (mForeground != null) {
- mForeground.setHotspot(x, y);
- }
- }
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundTextView.java b/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundTextView.java
deleted file mode 100644
index 52b145e..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ForegroundTextView.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Created by YuGang Yang on April 08, 2015.
- * Copyright 2007-2015 Laputapp.com. All rights reserved.
- */
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.loopeer.codereader.R;
-
-public class ForegroundTextView extends TextView {
- private Drawable foreground;
-
- public ForegroundTextView(Context context) {
- this(context, null);
- }
-
- public ForegroundTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundTextView);
- Drawable foreground = a.getDrawable(R.styleable.ForegroundTextView_android_foreground);
- if (foreground != null) {
- setForeground(foreground);
- }
- a.recycle();
- }
-
- /**
- * Supply a drawable resource that is to be rendered on top of all of the child
- * views in the frame layout.
- *
- * @param drawableResId The drawable resource to be drawn on top of the children.
- */
- public void setForegroundResource(int drawableResId) {
- setForeground(getContext().getResources().getDrawable(drawableResId));
- }
-
- /**
- * Supply a Drawable that is to be rendered on top of all of the child
- * views in the frame layout.
- *
- * @param drawable The Drawable to be drawn on top of the children.
- */
- public void setForeground(Drawable drawable) {
- if (foreground == drawable) {
- return;
- }
- if (foreground != null) {
- foreground.setCallback(null);
- unscheduleDrawable(foreground);
- }
-
- foreground = drawable;
-
- if (drawable != null) {
- drawable.setCallback(this);
- if (drawable.isStateful()) {
- drawable.setState(getDrawableState());
- }
- }
- requestLayout();
- invalidate();
- }
-
- @Override protected boolean verifyDrawable(Drawable who) {
- return super.verifyDrawable(who) || who == foreground;
- }
-
- @Override public void jumpDrawablesToCurrentState() {
- super.jumpDrawablesToCurrentState();
- if (foreground != null) foreground.jumpToCurrentState();
- }
-
- @Override protected void drawableStateChanged() {
- super.drawableStateChanged();
- if (foreground != null && foreground.isStateful()) {
- foreground.setState(getDrawableState());
- }
- }
-
- @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (foreground != null) {
- foreground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
- invalidate();
- }
- }
-
- @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- if (foreground != null) {
- foreground.setBounds(0, 0, w, h);
- invalidate();
- }
- }
-
- @Override public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (foreground != null) {
- foreground.draw(canvas);
- }
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/NestHorizontalScrollView.java b/app/src/main/java/com/loopeer/codereader/ui/view/NestHorizontalScrollView.java
deleted file mode 100644
index 3811336..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/NestHorizontalScrollView.java
+++ /dev/null
@@ -1,1844 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.InputDeviceCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.NestedScrollingChild;
-import android.support.v4.view.NestedScrollingChildHelper;
-import android.support.v4.view.NestedScrollingParent;
-import android.support.v4.view.NestedScrollingParentHelper;
-import android.support.v4.view.VelocityTrackerCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityRecordCompat;
-import android.support.v4.widget.EdgeEffectCompat;
-import android.support.v4.widget.ScrollerCompat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.FocusFinder;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AnimationUtils;
-import android.widget.FrameLayout;
-import android.widget.ScrollView;
-
-import java.util.List;
-
-public class NestHorizontalScrollView extends FrameLayout implements NestedScrollingParent,
- NestedScrollingChild {
- static final int ANIMATED_SCROLL_GAP = 250;
-
- static final float MAX_SCROLL_FACTOR = 0.5f;
-
- private static final String TAG = "NestedScrollView";
-
- private long mLastScroll;
-
- private final Rect mTempRect = new Rect();
- private ScrollerCompat mScroller;
- private EdgeEffectCompat mEdgeGlowLeft;
- private EdgeEffectCompat mEdgeGlowRight;
-
- /**
- * Position of the last motion event.
- */
- private int mLastMotionX;
- private int mLastMotionY;
-
- /**
- * True when the layout has changed but the traversal has not come through yet.
- * Ideally the view hierarchy would keep track of this for us.
- */
- private boolean mIsLayoutDirty = true;
- private boolean mIsLaidOut = false;
-
- /**
- * The child to give focus to in the event that a child has requested focus while the
- * layout is dirty. This prevents the scroll from being wrong if the child has not been
- * laid out before requesting focus.
- */
- private View mChildToScrollTo = null;
-
- /**
- * True if the user is currently dragging this ScrollView around. This is
- * not the same as 'is being flinged', which can be checked by
- * mScroller.isFinished() (flinging begins when the user lifts his finger).
- */
- private boolean mIsBeingDragged = false;
-
- /**
- * Determines speed during touch scrolling
- */
- private VelocityTracker mVelocityTracker;
-
- /**
- * When set to true, the scroll view measure its child to make it fill the currently
- * visible area.
- */
- private boolean mFillViewport;
-
- /**
- * Whether arrow scrolling is animated.
- */
- private boolean mSmoothScrollingEnabled = true;
-
- private int mTouchSlop;
- private int mMinimumVelocity;
- private int mMaximumVelocity;
-
- /**
- * ID of the active pointer. This is used to retain consistency during
- * drags/flings if multiple pointers are used.
- */
- private int mActivePointerId = INVALID_POINTER;
-
- /**
- * Used during scrolling to retrieve the new offset within the window.
- */
- private final int[] mScrollOffset = new int[2];
- private final int[] mScrollConsumed = new int[2];
- private int mNestedXOffset;
-
- /**
- * Sentinel value for no current active pointer.
- * Used by {@link #mActivePointerId}.
- */
- private static final int INVALID_POINTER = -1;
-
- private SavedState mSavedState;
-
- private static final AccessibilityDelegate ACCESSIBILITY_DELEGATE = new AccessibilityDelegate();
-
- private static final int[] SCROLLVIEW_STYLEABLE = new int[] {
- android.R.attr.fillViewport
- };
-
- private final NestedScrollingParentHelper mParentHelper;
- private final NestedScrollingChildHelper mChildHelper;
-
- private float mHorizontalScrollFactor;
-
- public NestHorizontalScrollView(Context context) {
- this(context, null);
- }
-
- public NestHorizontalScrollView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public NestHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initScrollView();
-
- final TypedArray a = context.obtainStyledAttributes(
- attrs, SCROLLVIEW_STYLEABLE, defStyleAttr, 0);
-
- setFillViewport(a.getBoolean(0, false));
-
- a.recycle();
-
- mParentHelper = new NestedScrollingParentHelper(this);
- mChildHelper = new NestedScrollingChildHelper(this);
-
- // ...because why else would you be using this widget?
- setNestedScrollingEnabled(true);
-
- ViewCompat.setAccessibilityDelegate(this, ACCESSIBILITY_DELEGATE);
- }
-
- // NestedScrollingChild
-
- @Override
- public void setNestedScrollingEnabled(boolean enabled) {
- mChildHelper.setNestedScrollingEnabled(enabled);
- }
-
- @Override
- public boolean isNestedScrollingEnabled() {
- return mChildHelper.isNestedScrollingEnabled();
- }
-
- @Override
- public boolean startNestedScroll(int axes) {
- return mChildHelper.startNestedScroll(axes);
- }
-
- @Override
- public void stopNestedScroll() {
- mChildHelper.stopNestedScroll();
- }
-
- @Override
- public boolean hasNestedScrollingParent() {
- return mChildHelper.hasNestedScrollingParent();
- }
-
- @Override
- public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
- int dyUnconsumed, int[] offsetInWindow) {
- return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
- offsetInWindow);
- }
-
- @Override
- public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
- return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
- }
-
- @Override
- public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
- return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
- }
-
- @Override
- public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
- return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
- }
-
- // NestedScrollingParent
-
- @Override
- public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
- return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_HORIZONTAL) != 0;
- }
-
- @Override
- public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
- mParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
- startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL);
- }
-
- @Override
- public void onStopNestedScroll(View target) {
- stopNestedScroll();
- }
-
- @Override
- public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
- int dyUnconsumed) {
- final int oldScrollX = getScrollX();
- scrollBy(dxUnconsumed, 0);
- final int mxConsumed = getScrollX() - oldScrollX;
- final int mxUnconsumed = dxUnconsumed - mxConsumed;
- dispatchNestedScroll(mxConsumed, 0, mxUnconsumed, 0, null);
- }
-
- @Override
- public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
- // Do nothing
- }
-
- @Override
- public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
- if (!consumed) {
- flingWithNestedDispatch((int) velocityX);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
- // Do nothing
- return false;
- }
-
- @Override
- public int getNestedScrollAxes() {
- return mParentHelper.getNestedScrollAxes();
- }
-
- // ScrollView import
-
- public boolean shouldDelayChildPressedState() {
- return true;
- }
-
- @Override
- protected float getLeftFadingEdgeStrength() {
- if (getChildCount() == 0) {
- return 0.0f;
- }
-
- final int length = getHorizontalFadingEdgeLength();
- final int scrollX = getScrollX();
- if (scrollX < length) {
- return scrollX / (float) length;
- }
-
- return 1.0f;
- }
-
- @Override
- protected float getRightFadingEdgeStrength() {
- if (getChildCount() == 0) {
- return 0.0f;
- }
-
- final int length = getHorizontalFadingEdgeLength();
- final int rightEdge = getWidth() - getPaddingRight();
- final int span = getChildAt(0).getRight() - getScrollX() - rightEdge;
- if (span < length) {
- return span / (float) length;
- }
-
- return 1.0f;
- }
-
- /**
- * @return The maximum amount this scroll view will scroll in response to
- * an arrow event.
- */
- public int getMaxScrollAmount() {
- return (int) (MAX_SCROLL_FACTOR * getWidth());
- }
-
- private void initScrollView() {
- mScroller = ScrollerCompat.create(getContext(), null);
- setFocusable(true);
- setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
- setWillNotDraw(false);
- final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- mTouchSlop = configuration.getScaledTouchSlop();
- mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
- mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
- }
-
- @Override
- public void addView(View child) {
- if (getChildCount() > 0) {
- throw new IllegalStateException("ScrollView can host only one direct child");
- }
-
- super.addView(child);
- }
-
- @Override
- public void addView(View child, int index) {
- if (getChildCount() > 0) {
- throw new IllegalStateException("ScrollView can host only one direct child");
- }
-
- super.addView(child, index);
- }
-
- @Override
- public void addView(View child, ViewGroup.LayoutParams params) {
- if (getChildCount() > 0) {
- throw new IllegalStateException("ScrollView can host only one direct child");
- }
-
- super.addView(child, params);
- }
-
- @Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
- if (getChildCount() > 0) {
- throw new IllegalStateException("ScrollView can host only one direct child");
- }
-
- super.addView(child, index, params);
- }
-
- /**
- * @return Returns true this ScrollView can be scrolled
- */
- private boolean canScroll() {
- View child = getChildAt(0);
- if (child != null) {
- int childWidth = child.getWidth();
- return getWidth() < childWidth + getPaddingRight() + getPaddingLeft();
- }
- return false;
- }
-
- /**
- * Indicates whether this ScrollView's content is stretched to fill the viewport.
- *
- * @return True if the content fills the viewport, false otherwise.
- *
- * @attr ref android.R.styleable#ScrollView_fillViewport
- */
- public boolean isFillViewport() {
- return mFillViewport;
- }
-
- /**
- * Indicates this ScrollView whether it should stretch its content height to fill
- * the viewport or not.
- *
- * @param fillViewport True to stretch the content's height to the viewport's
- * boundaries, false otherwise.
- *
- * @attr ref android.R.styleable#ScrollView_fillViewport
- */
- public void setFillViewport(boolean fillViewport) {
- if (fillViewport != mFillViewport) {
- mFillViewport = fillViewport;
- requestLayout();
- }
- }
-
- /**
- * @return Whether arrow scrolling will animate its transition.
- */
- public boolean isSmoothScrollingEnabled() {
- return mSmoothScrollingEnabled;
- }
-
- /**
- * Set whether arrow scrolling will animate its transition.
- * @param smoothScrollingEnabled whether arrow scrolling will animate its transition
- */
- public void setSmoothScrollingEnabled(boolean smoothScrollingEnabled) {
- mSmoothScrollingEnabled = smoothScrollingEnabled;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (!mFillViewport) {
- return;
- }
-
- final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- if (heightMode == MeasureSpec.UNSPECIFIED) {
- return;
- }
-
- if (getChildCount() > 0) {
- final View child = getChildAt(0);
- int width = getMeasuredWidth();
- if (child.getMeasuredWidth() < width) {
- final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
- getPaddingTop() + getPaddingBottom(), lp.height);
- width -= getPaddingRight();
- width -= getPaddingLeft();
- int childWidthMeasureSpec =
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
-
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- }
- }
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- // Let the focused view and/or our descendants get the key first
- return super.dispatchKeyEvent(event) || executeKeyEvent(event);
- }
-
- /**
- * You can call this function yourself to have the scroll view perform
- * scrolling from a key event, just as if the event had been dispatched to
- * it by the view hierarchy.
- *
- * @param event The key event to execute.
- * @return Return true if the event was handled, else false.
- */
- public boolean executeKeyEvent(KeyEvent event) {
- mTempRect.setEmpty();
-
- if (!canScroll()) {
- if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK) {
- View currentFocused = findFocus();
- if (currentFocused == this) currentFocused = null;
- View nextFocused = FocusFinder.getInstance().findNextFocus(this,
- currentFocused, View.FOCUS_RIGHT);
- return nextFocused != null
- && nextFocused != this
- && nextFocused.requestFocus(View.FOCUS_RIGHT);
- }
- return false;
- }
-
- boolean handled = false;
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (!event.isAltPressed()) {
- handled = arrowScroll(View.FOCUS_LEFT);
- } else {
- handled = fullScroll(View.FOCUS_LEFT);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (!event.isAltPressed()) {
- handled = arrowScroll(View.FOCUS_RIGHT);
- } else {
- handled = fullScroll(View.FOCUS_RIGHT);
- }
- break;
- case KeyEvent.KEYCODE_SPACE:
- pageScroll(event.isShiftPressed() ? View.FOCUS_LEFT : View.FOCUS_RIGHT);
- break;
- }
- }
-
- return handled;
- }
-
- private boolean inChild(int x, int y) {
- if (getChildCount() > 0) {
- final int scrollX = getScrollX();
- final View child = getChildAt(0);
- return !(x < child.getLeft() - scrollX
- || x >= child.getRight() - scrollX
- || y < child.getTop()
- || y >= child.getBottom());
- }
- return false;
- }
-
- private void initOrResetVelocityTracker() {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- } else {
- mVelocityTracker.clear();
- }
- }
-
- private void initVelocityTrackerIfNotExists() {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- }
-
- private void recycleVelocityTracker() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
-
- @Override
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- if (disallowIntercept) {
- recycleVelocityTracker();
- }
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
-
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- /*
- * This method JUST determines whether we want to intercept the motion.
- * If we return true, onMotionEvent will be called and we do the actual
- * scrolling there.
- */
-
- /*
- * Shortcut the most recurring case: the user is in the dragging
- * state and he is moving his finger. We want to intercept this
- * motion.
- */
- final int action = ev.getAction();
- if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
- return true;
- }
-
- switch (action & MotionEventCompat.ACTION_MASK) {
- case MotionEvent.ACTION_MOVE: {
- /*
- * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
- * whether the user has moved far enough from his original down touch.
- */
-
- /*
- * Locally do absolute value. mLastMotionY is set to the y value
- * of the down event.
- */
- final int activePointerId = mActivePointerId;
- if (activePointerId == INVALID_POINTER) {
- // If we don't have a valid id, the touch down wasn't on content.
- break;
- }
-
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
- if (pointerIndex == -1) {
- Log.e(TAG, "Invalid pointerId=" + activePointerId
- + " in onInterceptTouchEvent");
- break;
- }
-
- final int x = (int) MotionEventCompat.getX(ev, pointerIndex);
- final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
- final int xDiff = Math.abs(x - mLastMotionX);
- final int yDiff = Math.abs(y - mLastMotionY);
- if (xDiff > mTouchSlop && xDiff > yDiff
- && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_HORIZONTAL) == 0) {
- mIsBeingDragged = true;
- mLastMotionX = x;
- mLastMotionY = y;
- initVelocityTrackerIfNotExists();
- mVelocityTracker.addMovement(ev);
- mNestedXOffset = 0;
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- } else {
- mIsBeingDragged = false;
- }
- break;
- }
-
- case MotionEvent.ACTION_DOWN: {
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
- if (!inChild(x, y)) {
- mIsBeingDragged = false;
- recycleVelocityTracker();
- break;
- }
-
- /*
- * Remember location of down touch.
- * ACTION_DOWN always refers to pointer index 0.
- */
- mLastMotionX = x;
- mLastMotionY = y;
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
-
- initOrResetVelocityTracker();
- mVelocityTracker.addMovement(ev);
- /*
- * If being flinged and user touches the screen, initiate drag;
- * otherwise don't. mScroller.isFinished should be false when
- * being flinged.
- */
- mIsBeingDragged = !mScroller.isFinished();
- startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL);
- break;
- }
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- /* Release the drag */
- mIsBeingDragged = false;
- mActivePointerId = INVALID_POINTER;
- recycleVelocityTracker();
- stopNestedScroll();
- break;
- case MotionEventCompat.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
- }
-
- /*
- * The only time we want to intercept motion events is if we are in the
- * drag mode.
- */
- return mIsBeingDragged;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- initVelocityTrackerIfNotExists();
-
- MotionEvent vtev = MotionEvent.obtain(ev);
-
- final int actionMasked = MotionEventCompat.getActionMasked(ev);
-
- if (actionMasked == MotionEvent.ACTION_DOWN) {
- mNestedXOffset = 0;
- }
- vtev.offsetLocation(mNestedXOffset, 0);
-
- switch (actionMasked) {
- case MotionEvent.ACTION_DOWN: {
- if (getChildCount() == 0) {
- return false;
- }
- if ((mIsBeingDragged = !mScroller.isFinished())) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
-
- /*
- * If being flinged and user touches, stop the fling. isFinished
- * will be false if being flinged.
- */
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
-
- // Remember where the motion event started
- mLastMotionX = (int) ev.getX();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL);
- break;
- }
- case MotionEvent.ACTION_MOVE:
- final int activePointerIndex = MotionEventCompat.findPointerIndex(ev,
- mActivePointerId);
- if (activePointerIndex == -1) {
- Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
- break;
- }
-
- final int x = (int) MotionEventCompat.getX(ev, activePointerIndex);
- int deltaX = mLastMotionX - x;
- if (dispatchNestedPreScroll(deltaX, 0, mScrollConsumed, mScrollOffset)) {
- deltaX -= mScrollConsumed[0];
- vtev.offsetLocation(mScrollOffset[0], 0);
- mNestedXOffset += mScrollOffset[0];
- }
- if (!mIsBeingDragged && Math.abs(deltaX) > mTouchSlop) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- mIsBeingDragged = true;
- if (deltaX > 0) {
- deltaX -= mTouchSlop;
- } else {
- deltaX += mTouchSlop;
- }
- }
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- mLastMotionX = x - mScrollOffset[0];
-
- final int oldX = getScrollX();
- final int range = getScrollRange();
- final int overscrollMode = ViewCompat.getOverScrollMode(this);
- boolean canOverscroll = overscrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
- (overscrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS &&
- range > 0);
-
- // Calling overScrollByCompat will call onOverScrolled, which
- // calls onScrollChanged if applicable.
- if (overScrollByCompat(deltaX, 0, getScrollX(), 0, range, 0, 0,
- 0, true) && !hasNestedScrollingParent()) {
- // Break our velocity if we hit a scroll barrier.
- mVelocityTracker.clear();
- }
-
- final int scrolledDeltaX = getScrollX() - oldX;
- final int unconsumedX = deltaX - scrolledDeltaX;
- if (dispatchNestedScroll(scrolledDeltaX, 0, unconsumedX, 0, mScrollOffset)) {
- mLastMotionX -= mScrollOffset[0];
- vtev.offsetLocation(mScrollOffset[0], 0);
- mNestedXOffset += mScrollOffset[0];
- } else if (canOverscroll) {
- ensureGlows();
- final int pulledToX = oldX + deltaX;
- if (pulledToX < 0) {
- mEdgeGlowLeft.onPull((float) deltaX / getWidth(),
- MotionEventCompat.getY(ev, activePointerIndex) / getHeight());
- if (!mEdgeGlowRight.isFinished()) {
- mEdgeGlowRight.onRelease();
- }
- } else if (pulledToX > range) {
- mEdgeGlowRight.onPull((float) deltaX / getWidth(),
- 1.f - MotionEventCompat.getY(ev, activePointerIndex)
- / getHeight());
- if (!mEdgeGlowLeft.isFinished()) {
- mEdgeGlowLeft.onRelease();
- }
- }
- if (mEdgeGlowLeft != null
- && (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished())) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mIsBeingDragged) {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(velocityTracker,
- mActivePointerId);
-
- if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
- flingWithNestedDispatch(-initialVelocity);
- }
-
- mActivePointerId = INVALID_POINTER;
- endDrag();
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- if (mIsBeingDragged && getChildCount() > 0) {
- mActivePointerId = INVALID_POINTER;
- endDrag();
- }
- break;
- case MotionEventCompat.ACTION_POINTER_DOWN: {
- final int index = MotionEventCompat.getActionIndex(ev);
- mLastMotionX = (int) MotionEventCompat.getX(ev, index);
- mActivePointerId = MotionEventCompat.getPointerId(ev, index);
- break;
- }
- case MotionEventCompat.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- mLastMotionX = (int) MotionEventCompat.getX(ev,
- MotionEventCompat.findPointerIndex(ev, mActivePointerId));
- break;
- }
-
- if (mVelocityTracker != null) {
- mVelocityTracker.addMovement(vtev);
- }
- vtev.recycle();
- return true;
- }
-
- private void onSecondaryPointerUp(MotionEvent ev) {
- final int pointerIndex = (ev.getAction() & MotionEventCompat.ACTION_POINTER_INDEX_MASK) >>
- MotionEventCompat.ACTION_POINTER_INDEX_SHIFT;
- final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
- if (pointerId == mActivePointerId) {
- // This was our active pointer going up. Choose a new
- // active pointer and adjust accordingly.
- // TODO: Make this decision more intelligent.
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = (int) MotionEventCompat.getX(ev, newPointerIndex);
- mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
- }
-
- public boolean onGenericMotionEvent(MotionEvent event) {
- if ((MotionEventCompat.getSource(event) & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) {
- switch (event.getAction()) {
- case MotionEventCompat.ACTION_SCROLL: {
- if (!mIsBeingDragged) {
- final float hscroll = MotionEventCompat.getAxisValue(event,
- MotionEventCompat.AXIS_HSCROLL);
- if (hscroll != 0) {
- final int delta = (int) (hscroll * getHorizontalScrollFactorCompat());
- final int range = getScrollRange();
- int oldScrollX = getScrollX();
- int newScrollX = oldScrollX - delta;
- if (newScrollX < 0) {
- newScrollX = 0;
- } else if (newScrollX > range) {
- newScrollX = range;
- }
- if (newScrollX != oldScrollX) {
- super.scrollTo(newScrollX, getScrollY());
- return true;
- }
- }
- }
- }
- }
- }
- return false;
- }
-
- private float getHorizontalScrollFactorCompat() {
- if (mHorizontalScrollFactor == 0) {
- TypedValue outValue = new TypedValue();
- final Context context = getContext();
- if (!context.getTheme().resolveAttribute(
- android.R.attr.listPreferredItemHeight, outValue, true)) {
- throw new IllegalStateException(
- "Expected theme to define listPreferredItemHeight.");
- }
- mHorizontalScrollFactor = outValue.getDimension(
- context.getResources().getDisplayMetrics());
- }
- return mHorizontalScrollFactor;
- }
-
- protected void onOverScrolled(int scrollX, int scrollY,
- boolean clampedX, boolean clampedY) {
- super.scrollTo(scrollX, scrollY);
- }
-
- boolean overScrollByCompat(int deltaX, int deltaY,
- int scrollX, int scrollY,
- int scrollRangeX, int scrollRangeY,
- int maxOverScrollX, int maxOverScrollY,
- boolean isTouchEvent) {
- final int overScrollMode = ViewCompat.getOverScrollMode(this);
- final boolean canScrollHorizontal =
- computeHorizontalScrollRange() > computeHorizontalScrollExtent();
- final boolean canScrollVertical =
- computeVerticalScrollRange() > computeVerticalScrollExtent();
- final boolean overScrollHorizontal = overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
- (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
- final boolean overScrollVertical = overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
- (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
-
- int newScrollX = scrollX + deltaX;
- if (!overScrollHorizontal) {
- maxOverScrollX = 0;
- }
-
- int newScrollY = scrollY + deltaY;
- if (!overScrollVertical) {
- maxOverScrollY = 0;
- }
-
- // Clamp values if at the limits and record
- final int left = -maxOverScrollX;
- final int right = maxOverScrollX + scrollRangeX;
- final int top = -maxOverScrollY;
- final int bottom = maxOverScrollY + scrollRangeY;
-
- boolean clampedX = false;
- if (newScrollX > right) {
- newScrollX = right;
- clampedX = true;
- } else if (newScrollX < left) {
- newScrollX = left;
- clampedX = true;
- }
-
- boolean clampedY = false;
- if (newScrollY > bottom) {
- newScrollY = bottom;
- clampedY = true;
- } else if (newScrollY < top) {
- newScrollY = top;
- clampedY = true;
- }
-
- onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
-
- return clampedX || clampedY;
- }
-
- private int getScrollRange() {
- int scrollRange = 0;
- if (getChildCount() > 0) {
- View child = getChildAt(0);
- scrollRange = Math.max(0,
- child.getWidth() - (getWidth() - getPaddingLeft() - getPaddingRight()));
- }
- return scrollRange;
- }
-
- /**
- *
- * Finds the next focusable component that fits in the specified bounds.
- *
- *
- * @param topFocus look for a candidate is the one at the top of the bounds
- * if topFocus is true, or at the bottom of the bounds if topFocus is
- * false
- * @param left the left offset of the bounds in which a focusable must be
- * found
- * @param right the right offset of the bounds in which a focusable must
- * be found
- * @return the next focusable component in the bounds or null if none can
- * be found
- */
- private View findFocusableViewInBounds(boolean topFocus, int left, int right) {
-
- List focusables = getFocusables(View.FOCUS_FORWARD);
- View focusCandidate = null;
-
- /*
- * A fully contained focusable is one where its top is below the bound's
- * top, and its bottom is above the bound's bottom. A partially
- * contained focusable is one where some part of it is within the
- * bounds, but it also has some part that is not within bounds. A fully contained
- * focusable is preferred to a partially contained focusable.
- */
- boolean foundFullyContainedFocusable = false;
-
- int count = focusables.size();
- for (int i = 0; i < count; i++) {
- View view = focusables.get(i);
- int viewLeft = view.getLeft();
- int viewRight = view.getRight();
-
- if (left < viewRight && viewLeft < right) {
- /*
- * the focusable is in the target area, it is a candidate for
- * focusing
- */
-
- final boolean viewIsFullyContained = (left < viewLeft) &&
- (viewRight < right);
-
- if (focusCandidate == null) {
- /* No candidate, take this one */
- focusCandidate = view;
- foundFullyContainedFocusable = viewIsFullyContained;
- } else {
- final boolean viewIsCloserToBoundary =
- (topFocus && viewLeft < focusCandidate.getLeft()) ||
- (!topFocus && viewRight > focusCandidate
- .getRight());
-
- if (foundFullyContainedFocusable) {
- if (viewIsFullyContained && viewIsCloserToBoundary) {
- /*
- * We're dealing with only fully contained views, so
- * it has to be closer to the boundary to beat our
- * candidate
- */
- focusCandidate = view;
- }
- } else {
- if (viewIsFullyContained) {
- /* Any fully contained view beats a partially contained view */
- focusCandidate = view;
- foundFullyContainedFocusable = true;
- } else if (viewIsCloserToBoundary) {
- /*
- * Partially contained view beats another partially
- * contained view if it's closer
- */
- focusCandidate = view;
- }
- }
- }
- }
- }
-
- return focusCandidate;
- }
-
- /**
- *
Handles scrolling in response to a "page up/down" shortcut press. This
- * method will scroll the view by one page up or down and give the focus
- * to the topmost/bottommost component in the new visible area. If no
- * component is a good candidate for focus, this scrollview reclaims the
- * focus.
- *
- * @param direction the scroll direction: {@link android.view.View#FOCUS_UP}
- * to go one page up or
- * {@link android.view.View#FOCUS_RIGHT} to go one page down
- * @return true if the key event is consumed by this method, false otherwise
- */
- public boolean pageScroll(int direction) {
- boolean toRight = direction == View.FOCUS_RIGHT;
- int width = getWidth();
-
- if (toRight) {
- mTempRect.left = getScrollX() + width;
- int count = getChildCount();
- if (count > 0) {
- View view = getChildAt(count - 1);
- if (mTempRect.left + width > view.getRight()) {
- mTempRect.left = view.getRight() - width;
- }
- }
- } else {
- mTempRect.left = getScrollX() - width;
- if (mTempRect.left < 0) {
- mTempRect.left = 0;
- }
- }
- mTempRect.right = mTempRect.left + width;
-
- return scrollAndFocus(direction, mTempRect.left, mTempRect.right);
- }
-
- /**
- *
Handles scrolling in response to a "home/end" shortcut press. This
- * method will scroll the view to the top or bottom and give the focus
- * to the topmost/bottommost component in the new visible area. If no
- * component is a good candidate for focus, this scrollview reclaims the
- * focus.
- *
- * @param direction the scroll direction: {@link android.view.View#FOCUS_UP}
- * to go the top of the view or
- * {@link android.view.View#FOCUS_DOWN} to go the bottom
- * @return true if the key event is consumed by this method, false otherwise
- */
- public boolean fullScroll(int direction) {
- boolean right = direction == View.FOCUS_RIGHT;
- int width = getWidth();
-
- mTempRect.left = 0;
- mTempRect.right = width;
-
- if (right) {
- int count = getChildCount();
- if (count > 0) {
- View view = getChildAt(count - 1);
- mTempRect.right = view.getRight() + getPaddingRight();
- mTempRect.left = mTempRect.right - width;
- }
- }
-
- return scrollAndFocus(direction, mTempRect.left, mTempRect.right);
- }
-
- /**
- *
Scrolls the view to make the area defined by top and
- * bottom visible. This method attempts to give the focus
- * to a component visible in this area. If no component can be focused in
- * the new visible area, the focus is reclaimed by this ScrollView.
- *
- * @param direction the scroll direction: {@link android.view.View#FOCUS_UP}
- * to go upward, {@link android.view.View#FOCUS_DOWN} to downward
- * @param left the left offset of the new area to be made visible
- * @param right the right offset of the new area to be made visible
- * @return true if the key event is consumed by this method, false otherwise
- */
- private boolean scrollAndFocus(int direction, int left, int right) {
- boolean handled = true;
-
- int width = getWidth();
- int containerLeft = getScrollX();
- int containerRight = containerLeft + width;
- boolean toLeft = direction == View.FOCUS_LEFT;
-
- View newFocused = findFocusableViewInBounds(toLeft, left, right);
- if (newFocused == null) {
- newFocused = this;
- }
-
- if (left >= containerLeft && right <= containerRight) {
- handled = false;
- } else {
- int delta = toLeft ? (left - containerLeft) : (right - containerRight);
- doScrollX(delta);
- }
-
- if (newFocused != findFocus()) newFocused.requestFocus(direction);
-
- return handled;
- }
-
- /**
- * Handle scrolling in response to an up or down arrow click.
- *
- * @param direction The direction corresponding to the arrow key that was
- * pressed
- * @return True if we consumed the event, false otherwise
- */
- public boolean arrowScroll(int direction) {
-
- View currentFocused = findFocus();
- if (currentFocused == this) currentFocused = null;
-
- View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction);
-
- final int maxJump = getMaxScrollAmount();
-
- if (nextFocused != null && isWithinDeltaOfScreen(nextFocused, maxJump, getHeight())) {
- nextFocused.getDrawingRect(mTempRect);
- offsetDescendantRectToMyCoords(nextFocused, mTempRect);
- int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
- doScrollX(scrollDelta);
- nextFocused.requestFocus(direction);
- } else {
- // no new focus
- int scrollDelta = maxJump;
-
- if (direction == View.FOCUS_LEFT && getScrollX() < scrollDelta) {
- scrollDelta = getScrollX();
- } else if (direction == View.FOCUS_RIGHT) {
- if (getChildCount() > 0) {
- int daRight = getChildAt(0).getRight();
- int screenRight = getScrollX() + getWidth() - getPaddingRight();
- if (daRight - screenRight < maxJump) {
- scrollDelta = daRight - screenRight;
- }
- }
- }
- if (scrollDelta == 0) {
- return false;
- }
- doScrollX(direction == View.FOCUS_RIGHT ? scrollDelta : -scrollDelta);
- }
-
- if (currentFocused != null && currentFocused.isFocused()
- && isOffScreen(currentFocused)) {
- // previously focused item still has focus and is off screen, give
- // it up (take it back to ourselves)
- // (also, need to temporarily force FOCUS_BEFORE_DESCENDANTS so we are
- // sure to
- // get it)
- final int descendantFocusability = getDescendantFocusability(); // save
- setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
- requestFocus();
- setDescendantFocusability(descendantFocusability); // restore
- }
- return true;
- }
-
- /**
- * @return whether the descendant of this scroll view is scrolled off
- * screen.
- */
- private boolean isOffScreen(View descendant) {
- return !isWithinDeltaOfScreen(descendant, 0, getWidth());
- }
-
- /**
- * @return whether the descendant of this scroll view is within delta
- * pixels of being on the screen.
- */
- private boolean isWithinDeltaOfScreen(View descendant, int delta, int width) {
- descendant.getDrawingRect(mTempRect);
- offsetDescendantRectToMyCoords(descendant, mTempRect);
-
- return (mTempRect.right + delta) >= getScrollX()
- && (mTempRect.left - delta) <= (getScrollX() + width);
- }
-
- /**
- * Smooth scroll by a X delta
- *
- * @param delta the number of pixels to scroll by on the X axis
- */
- private void doScrollX(int delta) {
- if (delta != 0) {
- if (mSmoothScrollingEnabled) {
- smoothScrollBy(delta, 0);
- } else {
- scrollBy(delta, 0);
- }
- }
- }
-
- /**
- * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
- *
- * @param dx the number of pixels to scroll by on the X axis
- * @param dy the number of pixels to scroll by on the Y axis
- */
- public final void smoothScrollBy(int dx, int dy) {
- if (getChildCount() == 0) {
- // Nothing to do.
- return;
- }
- long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
- if (duration > ANIMATED_SCROLL_GAP) {
- final int width = getWidth() - getPaddingLeft() - getPaddingRight();
- final int right = getChildAt(0).getWidth();
- final int maxX = Math.max(0, right - width);
- final int scrollX = getScrollX();
- dx = Math.max(0, Math.min(scrollX + dx, maxX)) - scrollX;
-
- mScroller.startScroll(scrollX, getScrollY(), dx, 0);
- ViewCompat.postInvalidateOnAnimation(this);
- } else {
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
- scrollBy(dx, dy);
- }
- mLastScroll = AnimationUtils.currentAnimationTimeMillis();
- }
-
- /**
- * Like {@link #scrollTo}, but scroll smoothly instead of immediately.
- *
- * @param x the position where to scroll on the X axis
- * @param y the position where to scroll on the Y axis
- */
- public final void smoothScrollTo(int x, int y) {
- smoothScrollBy(x - getScrollX(), y - getScrollY());
- }
-
- @Override
- protected int computeHorizontalScrollRange() {
- final int count = getChildCount();
- final int contentWidth = getWidth() - getPaddingLeft() - getPaddingRight();
- if (count == 0) {
- return contentWidth;
- }
-
- int scrollRange = getChildAt(0).getRight();
- final int scrollX = getScrollX();
- final int overscrollRight = Math.max(0, scrollRange - contentWidth);
- if (scrollX < 0) {
- scrollRange -= scrollX;
- } else if (scrollX > overscrollRight) {
- scrollRange += scrollX - overscrollRight;
- }
-
- return scrollRange;
- }
-
- @Override
- protected int computeHorizontalScrollOffset() {
- return Math.max(0, super.computeHorizontalScrollOffset());
- }
-
- @Override
- protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
- ViewGroup.LayoutParams lp = child.getLayoutParams();
-
- int childWidthMeasureSpec;
- int childHeightMeasureSpec;
-
- childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, getPaddingTop()
- + getPaddingBottom(), lp.height);
-
- childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- }
-
- @Override
- protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
- int parentHeightMeasureSpec, int heightUsed) {
- final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
-
- final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
- getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin
- + heightUsed, lp.height);
- final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
- lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
-
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- }
-
- @Override
- public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- int oldX = getScrollX();
- int oldY = getScrollY();
- int x = mScroller.getCurrX();
- int y = mScroller.getCurrY();
-
- if (oldX != x || oldY != y) {
- final int range = getScrollRange();
- final int overscrollMode = ViewCompat.getOverScrollMode(this);
- final boolean canOverscroll = overscrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
- (overscrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
-
- overScrollByCompat(x - oldX, y - oldY, oldX, oldY, range, 0,
- 0, 0, false);
-
- if (canOverscroll) {
- ensureGlows();
- if (x <= 0 && oldX > 0) {
- mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
- } else if (x >= range && oldX < range) {
- mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
- }
- }
- }
- }
- }
-
- /**
- * Scrolls the view to the given child.
- *
- * @param child the View to scroll to
- */
- private void scrollToChild(View child) {
- child.getDrawingRect(mTempRect);
-
- /* Offset from child's local coordinates to ScrollView coordinates */
- offsetDescendantRectToMyCoords(child, mTempRect);
-
- int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
-
- if (scrollDelta != 0) {
- scrollBy(scrollDelta, 0);
- }
- }
-
- /**
- * If rect is off screen, scroll just enough to get it (or at least the
- * first screen size chunk of it) on screen.
- *
- * @param rect The rectangle.
- * @param immediate True to scroll immediately without animation
- * @return true if scrolling was performed
- */
- private boolean scrollToChildRect(Rect rect, boolean immediate) {
- final int delta = computeScrollDeltaToGetChildRectOnScreen(rect);
- final boolean scroll = delta != 0;
- if (scroll) {
- if (immediate) {
- scrollBy(delta, 0);
- } else {
- smoothScrollBy(delta, 0);
- }
- }
- return scroll;
- }
-
- /**
- * Compute the amount to scroll in the Y direction in order to get
- * a rectangle completely on the screen (or, if taller than the screen,
- * at least the first screen size chunk of it).
- *
- * @param rect The rect.
- * @return The scroll delta.
- */
- protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
- if (getChildCount() == 0) return 0;
-
- int width = getWidth();
- int screenLeft = getScrollX();
- int screenRight = screenLeft + width;
-
- int fadingEdge = getHorizontalFadingEdgeLength();
-
- // leave room for top fading edge as long as rect isn't at very top
- if (rect.left > 0) {
- screenLeft += fadingEdge;
- }
-
- // leave room for bottom fading edge as long as rect isn't at very bottom
- if (rect.right < getChildAt(0).getWidth()) {
- screenRight -= fadingEdge;
- }
-
- int scrollXDelta = 0;
-
- if (rect.right > screenRight && rect.left > screenLeft) {
- // need to move down to get it in view: move down just enough so
- // that the entire rectangle is in view (or at least the first
- // screen size chunk).
-
- if (rect.width() > width) {
- // just enough to get screen size chunk on
- scrollXDelta += (rect.left - screenLeft);
- } else {
- // get entire rect at bottom of screen
- scrollXDelta += (rect.right - screenRight);
- }
-
- // make sure we aren't scrolling beyond the end of our content
- int right = getChildAt(0).getRight();
- int distanceToRight = right - screenRight;
- scrollXDelta = Math.min(scrollXDelta, distanceToRight);
-
- } else if (rect.left < screenLeft && rect.right < screenRight) {
- // need to move up to get it in view: move up just enough so that
- // entire rectangle is in view (or at least the first screen
- // size chunk of it).
-
- if (rect.width() > width) {
- // screen size chunk
- scrollXDelta -= (screenRight - rect.right);
- } else {
- // entire rect at top
- scrollXDelta -= (screenLeft - rect.left);
- }
-
- // make sure we aren't scrolling any further than the top our content
- scrollXDelta = Math.max(scrollXDelta, -getScrollX());
- }
- return scrollXDelta;
- }
-
- @Override
- public void requestChildFocus(View child, View focused) {
- if (!mIsLayoutDirty) {
- scrollToChild(focused);
- } else {
- // The child may not be laid out yet, we can't compute the scroll yet
- mChildToScrollTo = focused;
- }
- super.requestChildFocus(child, focused);
- }
-
-
- /**
- * When looking for focus in children of a scroll view, need to be a little
- * more careful not to give focus to something that is scrolled off screen.
- *
- * This is more expensive than the default {@link android.view.ViewGroup}
- * implementation, otherwise this behavior might have been made the default.
- */
- @Override
- protected boolean onRequestFocusInDescendants(int direction,
- Rect previouslyFocusedRect) {
-
- // convert from forward / backward notation to up / down / left / right
- // (ugh).
- if (direction == View.FOCUS_FORWARD) {
- direction = View.FOCUS_RIGHT;
- } else if (direction == View.FOCUS_BACKWARD) {
- direction = View.FOCUS_LEFT;
- }
-
- final View nextFocus = previouslyFocusedRect == null ?
- FocusFinder.getInstance().findNextFocus(this, null, direction) :
- FocusFinder.getInstance().findNextFocusFromRect(this,
- previouslyFocusedRect, direction);
-
- if (nextFocus == null) {
- return false;
- }
-
- if (isOffScreen(nextFocus)) {
- return false;
- }
-
- return nextFocus.requestFocus(direction, previouslyFocusedRect);
- }
-
- @Override
- public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
- boolean immediate) {
- // offset into coordinate space of this scroll view
- rectangle.offset(child.getLeft() - child.getScrollX(),
- child.getTop() - child.getScrollY());
-
- return scrollToChildRect(rectangle, immediate);
- }
-
- @Override
- public void requestLayout() {
- mIsLayoutDirty = true;
- super.requestLayout();
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mIsLayoutDirty = false;
- // Give a child focus if it needs it
- if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
- scrollToChild(mChildToScrollTo);
- }
- mChildToScrollTo = null;
-
- if (!mIsLaidOut) {
- if (mSavedState != null) {
- scrollTo(mSavedState.scrollPosition, getScrollY());
- mSavedState = null;
- } // mScrollY default value is "0"
-
- final int childWidth = (getChildCount() > 0) ? getChildAt(0).getMeasuredWidth() : 0;
- final int scrollRange = Math.max(0,
- childWidth - (r - l - getPaddingRight() - getPaddingLeft()));
-
- // Don't forget to clamp
- if (getScrollX() > scrollRange) {
- scrollTo(scrollRange, getScrollY());
- } else if (getScrollX() < 0) {
- scrollTo(0, getScrollY());
- }
- }
-
- // Calling this with the present values causes it to re-claim them
- scrollTo(getScrollX(), getScrollY());
- mIsLaidOut = true;
- }
-
- @SuppressLint("MissingSuperCall")
- @Override
- public void onAttachedToWindow() {
- mIsLaidOut = false;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
-
- View currentFocused = findFocus();
- if (null == currentFocused || this == currentFocused)
- return;
-
- // If the currently-focused view was visible on the screen when the
- // screen was at the old height, then scroll the screen to make that
- // view visible with the new screen height.
- if (isWithinDeltaOfScreen(currentFocused, 0, oldw)) {
- currentFocused.getDrawingRect(mTempRect);
- offsetDescendantRectToMyCoords(currentFocused, mTempRect);
- int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
- doScrollX(scrollDelta);
- }
- }
-
- /**
- * Return true if child is a descendant of parent, (or equal to the parent).
- */
- private static boolean isViewDescendantOf(View child, View parent) {
- if (child == parent) {
- return true;
- }
-
- final ViewParent theParent = child.getParent();
- return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
- }
-
- /**
- * Fling the scroll view
- *
- * @param velocityX The initial velocity in the X direction. Positive
- * numbers mean that the finger/cursor is moving down the screen,
- * which means we want to scroll towards the top.
- */
- public void fling(int velocityX) {
- if (getChildCount() > 0) {
- int width = getWidth() - getPaddingRight() - getPaddingLeft();
- int right = getChildAt(0).getWidth();
-
- mScroller.fling(getScrollX(), getScrollY(), velocityX, 0, 0, Math.max(0, right - width)
- , 0,
- 0, width/2, 0);
-
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }
-
- private void flingWithNestedDispatch(int velocityX) {
- final int scrollX = getScrollX();
- final boolean canFling = (scrollX > 0 || velocityX > 0) &&
- (scrollX < getScrollRange() || velocityX < 0);
- if (!dispatchNestedPreFling(velocityX, 0)) {
- dispatchNestedFling(velocityX, 0, canFling);
- if (canFling) {
- fling(velocityX);
- }
- }
- }
-
- private void endDrag() {
- mIsBeingDragged = false;
-
- recycleVelocityTracker();
- stopNestedScroll();
-
- if (mEdgeGlowLeft != null) {
- mEdgeGlowLeft.onRelease();
- mEdgeGlowRight.onRelease();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- *
This version also clamps the scrolling to the bounds of our child.
- */
- @Override
- public void scrollTo(int x, int y) {
- // we rely on the fact the View.scrollBy calls scrollTo.
- if (getChildCount() > 0) {
- View child = getChildAt(0);
- x = clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth());
- y = clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight());
- if (x != getScrollX() || y != getScrollY()) {
- super.scrollTo(x, y);
- }
- }
- }
-
- private void ensureGlows() {
- if (ViewCompat.getOverScrollMode(this) != ViewCompat.OVER_SCROLL_NEVER) {
- if (mEdgeGlowLeft == null) {
- Context context = getContext();
- mEdgeGlowLeft = new EdgeEffectCompat(context);
- mEdgeGlowRight = new EdgeEffectCompat(context);
-
- }
- } else {
- mEdgeGlowLeft = null;
- mEdgeGlowRight = null;
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- if (mEdgeGlowLeft != null) {
- final int scrollX = getScrollX();
- if (!mEdgeGlowLeft.isFinished()) {
- final int restoreCount = canvas.save();
- final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-
- canvas.translate(Math.min(0, scrollX), getPaddingTop());
- canvas.rotate(90, 0, height);
- mEdgeGlowLeft.setSize(getWidth(), height);
- if (mEdgeGlowLeft.draw(canvas)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- canvas.restoreToCount(restoreCount);
- }
- if (!mEdgeGlowRight.isFinished()) {
- final int restoreCount = canvas.save();
- final int width = getWidth();
- final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-
- canvas.translate(Math.max(getScrollRange(), scrollX) + width,
- -height + getPaddingTop());
- canvas.rotate(90, 0, height);
- mEdgeGlowRight.setSize(width, height);
- if (mEdgeGlowRight.draw(canvas)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- canvas.restoreToCount(restoreCount);
- }
- }
- }
-
- private static int clamp(int n, int my, int child) {
- if (my >= child || n < 0) {
- /* my >= child is this case:
- * |--------------- me ---------------|
- * |------ child ------|
- * or
- * |--------------- me ---------------|
- * |------ child ------|
- * or
- * |--------------- me ---------------|
- * |------ child ------|
- *
- * n < 0 is this case:
- * |------ me ------|
- * |-------- child --------|
- * |-- mScrollX --|
- */
- return 0;
- }
- if ((my+n) > child) {
- /* this case:
- * |------ me ------|
- * |------ child ------|
- * |-- mScrollX --|
- */
- return child-my;
- }
- return n;
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- mSavedState = ss;
- requestLayout();
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- SavedState ss = new SavedState(superState);
- ss.scrollPosition = getScrollX();
- return ss;
- }
-
- static class SavedState extends BaseSavedState {
- public int scrollPosition;
-
- SavedState(Parcelable superState) {
- super(superState);
- }
-
- public SavedState(Parcel source) {
- super(source);
- scrollPosition = source.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(scrollPosition);
- }
-
- @Override
- public String toString() {
- return "HorizontalScrollView.SavedState{"
- + Integer.toHexString(System.identityHashCode(this))
- + " scrollPosition=" + scrollPosition + "}";
- }
-
- public static final Parcelable.Creator CREATOR
- = new Parcelable.Creator() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- static class AccessibilityDelegate extends AccessibilityDelegateCompat {
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
- if (super.performAccessibilityAction(host, action, arguments)) {
- return true;
- }
- final NestHorizontalScrollView nsvHost = (NestHorizontalScrollView) host;
- if (!nsvHost.isEnabled()) {
- return false;
- }
- switch (action) {
- case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
- final int viewportWidth = nsvHost.getWidth() - nsvHost.getPaddingRight()
- - nsvHost.getPaddingLeft();
- final int targetScrollX = Math.min(nsvHost.getScrollX() + viewportWidth,
- nsvHost.getScrollRange());
- if (targetScrollX != nsvHost.getScrollX()) {
- nsvHost.smoothScrollTo(targetScrollX, 0);
- return true;
- }
- }
- return false;
- case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
- final int viewportWidth = nsvHost.getWidth() - nsvHost.getPaddingRight()
- - nsvHost.getPaddingLeft();
- final int targetScrollX = Math.max(nsvHost.getScrollX() - viewportWidth, 0);
- if (targetScrollX != nsvHost.getScrollX()) {
- nsvHost.smoothScrollTo(0, targetScrollX);
- return true;
- }
- }
- return false;
- }
- return false;
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- final NestHorizontalScrollView nsvHost = (NestHorizontalScrollView) host;
- info.setClassName(ScrollView.class.getName());
- if (nsvHost.isEnabled()) {
- final int scrollRange = nsvHost.getScrollRange();
- if (scrollRange > 0) {
- info.setScrollable(true);
- if (nsvHost.getScrollX() > 0) {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
- }
- if (nsvHost.getScrollX() < scrollRange) {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
- }
- }
- }
- }
-
- @Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(host, event);
- final NestHorizontalScrollView nsvHost = (NestHorizontalScrollView) host;
- event.setClassName(ScrollView.class.getName());
- final AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event);
- final boolean scrollable = nsvHost.getScrollRange() > 0;
- record.setScrollable(scrollable);
- record.setScrollX(nsvHost.getScrollX());
- record.setScrollY(nsvHost.getScrollY());
- record.setMaxScrollX(nsvHost.getScrollRange());
- record.setMaxScrollY(nsvHost.getScrollY());
- }
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/NestedScrollWebView.java b/app/src/main/java/com/loopeer/codereader/ui/view/NestedScrollWebView.java
deleted file mode 100644
index 3d888fa..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/NestedScrollWebView.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.NestedScrollingChild;
-import android.support.v4.view.NestedScrollingChildHelper;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.webkit.WebView;
-
-/*
-* https://github.com/rhlff/NestedScrollWebView
-* */
-public class NestedScrollWebView extends WebView implements NestedScrollingChild {
-
- public interface ScrollChangeListener{
- void onScrollChanged(int l, int t, int oldl, int oldt);
- }
-
- public static final String TAG = NestedScrollWebView.class.getSimpleName();
-
- private int mLastMotionY;
-
- private final int[] mScrollOffset = new int[2];
- private final int[] mScrollConsumed = new int[2];
-
- private int mNestedYOffset;
-
- private NestedScrollingChildHelper mChildHelper;
-
- private ScrollChangeListener mScrollChangeListener;
-
- public NestedScrollWebView(Context context) {
- super(context);
- init();
- }
-
- public NestedScrollWebView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public NestedScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- private void init() {
- mChildHelper = new NestedScrollingChildHelper(this);
- setNestedScrollingEnabled(true);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean result = false;
-
- MotionEvent trackedEvent = MotionEvent.obtain(event);
-
- final int action = MotionEventCompat.getActionMasked(event);
-
- if (action == MotionEvent.ACTION_DOWN) {
- mNestedYOffset = 0;
- }
-
- int y = (int) event.getY();
-
- event.offsetLocation(0, mNestedYOffset);
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mLastMotionY = y;
- startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
- result = super.onTouchEvent(event);
- break;
- case MotionEvent.ACTION_MOVE:
- int deltaY = mLastMotionY - y;
-
- if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
- deltaY -= mScrollConsumed[1];
- trackedEvent.offsetLocation(0, mScrollOffset[1]);
- mNestedYOffset += mScrollOffset[1];
- }
-
- int oldY = getScrollY();
- mLastMotionY = y - mScrollOffset[1];
- if (deltaY < 0) {
- int newScrollY = Math.max(0, oldY + deltaY);
- deltaY -= newScrollY - oldY;
- if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
- mLastMotionY -= mScrollOffset[1];
- trackedEvent.offsetLocation(0, mScrollOffset[1]);
- mNestedYOffset += mScrollOffset[1];
- }
- }
-
- trackedEvent.recycle();
- result = super.onTouchEvent(trackedEvent);
- break;
- case MotionEvent.ACTION_POINTER_DOWN:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- stopNestedScroll();
- result = super.onTouchEvent(event);
- break;
- }
- return result;
- }
-
- // NestedScrollingChild
-
- @Override
- public void setNestedScrollingEnabled(boolean enabled) {
- mChildHelper.setNestedScrollingEnabled(enabled);
- }
-
- @Override
- public boolean isNestedScrollingEnabled() {
- return mChildHelper.isNestedScrollingEnabled();
- }
-
- @Override
- public boolean startNestedScroll(int axes) {
- return mChildHelper.startNestedScroll(axes);
- }
-
- @Override
- public void stopNestedScroll() {
- mChildHelper.stopNestedScroll();
- }
-
- @Override
- public boolean hasNestedScrollingParent() {
- return mChildHelper.hasNestedScrollingParent();
- }
-
- @Override
- public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
- return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
- }
-
- @Override
- public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
- return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
- }
-
- @Override
- public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
- return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
- }
-
- @Override
- public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
- return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
- }
-
- public void setScrollChangeListener(ScrollChangeListener scrollChangeListener) {
- mScrollChangeListener = scrollChangeListener;
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- super.onScrollChanged(l, t, oldl, oldt);
- if (mScrollChangeListener != null) {
- mScrollChangeListener.onScrollChanged(l, t, oldl, oldt);
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ProgressIndicatorView.java b/app/src/main/java/com/loopeer/codereader/ui/view/ProgressIndicatorView.java
deleted file mode 100644
index 8bee473..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ProgressIndicatorView.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.support.v4.content.ContextCompat;
-import android.util.AttributeSet;
-import android.view.View;
-
-import com.loopeer.codereader.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ProgressIndicatorView extends View {
-
- float scaleFloat1, scaleFloat2, degrees;
- public static final int DEFAULT_SIZE = 45;
-
- int mIndicatorColor;
- Paint mPaint;
- private List mAnimators;
- private boolean mHasAnimation;
-
- public ProgressIndicatorView(Context context) {
- this(context, null);
- }
-
- public ProgressIndicatorView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ProgressIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
-
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- mIndicatorColor = ContextCompat.getColor(getContext(), R.color.colorPrimary);
- mPaint = new Paint();
- mPaint.setColor(mIndicatorColor);
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setAntiAlias(true);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- setAnimationStatus(AnimStatus.START);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- setAnimationStatus(AnimStatus.CANCEL);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int width = measureDimension(dp2px(DEFAULT_SIZE), widthMeasureSpec);
- int height = measureDimension(dp2px(DEFAULT_SIZE), heightMeasureSpec);
- setMeasuredDimension(width, height);
- }
-
- private int dp2px(int dpValue) {
- return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
- }
-
- private int measureDimension(int defaultSize, int measureSpec) {
- int result = defaultSize;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- if (specMode == MeasureSpec.EXACTLY) {
- result = specSize;
- } else if (specMode == MeasureSpec.AT_MOST) {
- result = Math.min(defaultSize, specSize);
- } else {
- result = defaultSize;
- }
- return result;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (!mHasAnimation) {
- mHasAnimation = true;
- initAnimation();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- float circleSpacing = 12;
- float x = getWidth() / 2;
- float y = getHeight() / 2;
-
- canvas.save();
- canvas.translate(x, y);
- canvas.scale(scaleFloat1, scaleFloat1);
- mPaint.setStyle(Paint.Style.FILL);
- canvas.drawCircle(0, 0, x / 2.5f, mPaint);
-
- canvas.restore();
-
- canvas.translate(x, y);
- canvas.scale(scaleFloat2, scaleFloat2);
- canvas.rotate(degrees);
-
- mPaint.setStrokeWidth(3);
- mPaint.setStyle(Paint.Style.STROKE);
-
- float[] startAngles = new float[]{225, 45};
- for (int i = 0; i < 2; i++) {
- RectF rectF = new RectF(-x + circleSpacing, -y + circleSpacing, x - circleSpacing, y - circleSpacing);
- canvas.drawArc(rectF, startAngles[i], 90, false, mPaint);
- }
- }
-
- public void initAnimation() {
- mAnimators = createAnimation();
- }
-
- public void setAnimationStatus(AnimStatus animStatus) {
- if (mAnimators == null) {
- return;
- }
- int count = mAnimators.size();
- for (int i = 0; i < count; i++) {
- Animator animator = mAnimators.get(i);
- boolean isRunning = animator.isRunning();
- switch (animStatus) {
- case START:
- if (!isRunning) {
- animator.start();
- }
- break;
- case END:
- if (isRunning) {
- animator.end();
- }
- break;
- case CANCEL:
- if (isRunning) {
- animator.cancel();
- }
- break;
- }
- }
- }
-
- public enum AnimStatus {
- START, END, CANCEL
- }
-
- public List createAnimation() {
- ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.3f, 1);
- scaleAnim.setDuration(1000);
- scaleAnim.setRepeatCount(-1);
- scaleAnim.addUpdateListener(animation -> {
- scaleFloat1 = (float) animation.getAnimatedValue();
- postInvalidate();
- });
- scaleAnim.start();
-
- ValueAnimator scaleAnim2 = ValueAnimator.ofFloat(1, 0.6f, 1);
- scaleAnim2.setDuration(1000);
- scaleAnim2.setRepeatCount(-1);
- scaleAnim2.addUpdateListener(animation -> {
- scaleFloat2 = (float) animation.getAnimatedValue();
- postInvalidate();
- });
- scaleAnim2.start();
-
- ValueAnimator rotateAnim = ValueAnimator.ofFloat(0, 180, 360);
- rotateAnim.setDuration(1000);
- rotateAnim.setRepeatCount(-1);
- rotateAnim.addUpdateListener(animation -> {
- degrees = (float) animation.getAnimatedValue();
- postInvalidate();
- });
- rotateAnim.start();
-
- List animators = new ArrayList<>();
- animators.add(scaleAnim);
- animators.add(scaleAnim2);
- animators.add(rotateAnim);
- return animators;
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ProgressLoading.java b/app/src/main/java/com/loopeer/codereader/ui/view/ProgressLoading.java
deleted file mode 100644
index 21af7ac..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ProgressLoading.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.Window;
-import android.widget.TextView;
-
-import com.loopeer.codereader.R;
-
-public class ProgressLoading extends Dialog {
-
- private View mProgressView;
- private TextView mMessageTextView;
-
- private Window mWindow;
-
- private CharSequence mMessage;
- private boolean mShowProgress = true;
-
- public ProgressLoading(Context context, int theme) {
- super(context, theme);
- initialize(context, theme);
- }
-
- private void initialize(Context context, int theme) {
- mWindow = getWindow();
- mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
- setContentView(R.layout.progress_loading);
- mMessageTextView = (TextView) findViewById(R.id.text_message);
- mProgressView = findViewById(R.id.progress);
- }
-
- public ProgressLoading setMessage(int resId) {
- return setMessage(getContext().getString(resId));
- }
-
- public ProgressLoading setMessage(CharSequence msg) {
- mMessage = msg;
- return this;
- }
-
- public ProgressLoading updateMessage(CharSequence msg) {
- mMessage = msg;
- show();
- return this;
- }
-
- public ProgressLoading hideMessage() {
- return updateMessage("");
- }
-
- public ProgressLoading hideProgressBar() {
- mShowProgress = false;
- show();
- return this;
- }
-
- @Override
- public void show() {
- if (mMessageTextView != null) {
- if (TextUtils.isEmpty(mMessage)) {
- mMessageTextView.setVisibility(View.GONE);
- } else {
- mMessageTextView.setVisibility(View.VISIBLE);
- mMessageTextView.setText(mMessage);
- }
- }
-
- if (mProgressView != null) {
- if (mShowProgress) {
- mProgressView.setVisibility(View.VISIBLE);
- } else {
- mProgressView.setVisibility(View.GONE);
- }
- }
- super.show();
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ProgressWebView.java b/app/src/main/java/com/loopeer/codereader/ui/view/ProgressWebView.java
deleted file mode 100644
index 84fe270..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ProgressWebView.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.support.v4.content.ContextCompat;
-import android.util.AttributeSet;
-import android.webkit.WebView;
-import android.widget.ProgressBar;
-
-import com.loopeer.codereader.R;
-
-public class ProgressWebView extends WebView {
-
- private ProgressBar mProgressBar;
-
- public ProgressWebView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mProgressBar = new ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal);
- mProgressBar.setIndeterminate(false);
- mProgressBar.setProgressDrawable(ContextCompat.getDrawable(context, R.drawable.progress_horizontal_web_view));
- mProgressBar.setIndeterminateDrawable(ContextCompat.getDrawable(context, android.R.drawable.progress_indeterminate_horizontal));
- mProgressBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 5, 0, 0));
- mProgressBar.setMinimumHeight(16);
- addView(mProgressBar);
- setWebChromeClient(new WebChromeClient());
- }
-
- public void setProgressbarGone() {
- mProgressBar.setVisibility(GONE);
- }
-
- public class WebChromeClient extends android.webkit.WebChromeClient {
- @Override
- public void onProgressChanged(WebView view, int newProgress) {
- if (newProgress == 100) {
- mProgressBar.setVisibility(GONE);
- } else {
- if (mProgressBar.getVisibility() == GONE) mProgressBar.setVisibility(VISIBLE);
- mProgressBar.setProgress(newProgress);
- }
- super.onProgressChanged(view, newProgress);
- }
-
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- LayoutParams lp = (LayoutParams) mProgressBar.getLayoutParams();
- lp.x = l;
- lp.y = t;
- mProgressBar.setLayoutParams(lp);
- super.onScrollChanged(l, t, oldl, oldt);
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ScrollAwareFABBehavior.java b/app/src/main/java/com/loopeer/codereader/ui/view/ScrollAwareFABBehavior.java
deleted file mode 100644
index dd05f60..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ScrollAwareFABBehavior.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.support.design.widget.CoordinatorLayout;
-import android.support.design.widget.FloatingActionButton;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
- public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
- super();
- }
-
- @Override
- public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
- final View directTargetChild, final View target, final int nestedScrollAxes) {
- // Ensure we react to vertical scrolling
- return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
- || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
- }
-
- @Override
- public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
- final View target, final int dxConsumed, final int dyConsumed,
- final int dxUnconsumed, final int dyUnconsumed) {
- super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
- if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
- // User scrolled down and the FAB is currently visible -> hide the FAB
- child.hide();
- } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
- // User scrolled up and the FAB is currently not visible -> show the FAB
- child.show();
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/TextWatcherImpl.java b/app/src/main/java/com/loopeer/codereader/ui/view/TextWatcherImpl.java
deleted file mode 100644
index 856dfb2..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/TextWatcherImpl.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-
-public class TextWatcherImpl implements TextWatcher {
-
- @Override
- public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
-
- }
-
- @Override
- public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
-
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
-
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ThemeChooser.java b/app/src/main/java/com/loopeer/codereader/ui/view/ThemeChooser.java
deleted file mode 100644
index a2833aa..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ThemeChooser.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.app.Activity;
-import android.content.Context;
-import android.view.View;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class ThemeChooser {
- public interface OnItemSelectListener {
- void onItemSelect(int id, String tag);
- }
- private HashMap mViewThemeTags;
- private Context mContext;
- private OnItemSelectListener mOnItemSelectListener;
-
- public ThemeChooser(Context context, OnItemSelectListener onItemSelectListener) {
- mContext = context;
- mOnItemSelectListener = onItemSelectListener;
- mViewThemeTags = new HashMap<>();
- }
-
- public void addItem(int id, String tag) {
- mViewThemeTags.put(id, tag);
- }
-
- public void onItemSelect(View view) {
- view.setSelected(true);
- mOnItemSelectListener.onItemSelect(view.getId(), mViewThemeTags.get(view.getId()));
- for (Integer i : mViewThemeTags.keySet()) {
- if (view.getId() != i) {
- ((Activity) mContext).findViewById(i).setSelected(false);
- }
- }
- }
-
- public void onItemSelectByTag(String tag) {
- for (Map.Entry entry : mViewThemeTags.entrySet()) {
- int id = entry.getKey();
- ((Activity) mContext).findViewById(id).setSelected(entry.getValue().equals(tag));
- }
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/ui/view/ViewDragHelper.java b/app/src/main/java/com/loopeer/codereader/ui/view/ViewDragHelper.java
deleted file mode 100644
index 6432fd5..0000000
--- a/app/src/main/java/com/loopeer/codereader/ui/view/ViewDragHelper.java
+++ /dev/null
@@ -1,1491 +0,0 @@
-package com.loopeer.codereader.ui.view;
-
-import android.content.Context;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.VelocityTrackerCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.ScrollerCompat;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-
-import java.util.Arrays;
-
-public class ViewDragHelper {
- private static final String TAG = "ViewDragHelper";
-
- /**
- * A null/invalid pointer ID.
- */
- public static final int INVALID_POINTER = -1;
-
- /**
- * A view is not currently being dragged or animating as a result of a fling/snap.
- */
- public static final int STATE_IDLE = 0;
-
- /**
- * A view is currently being dragged. The position is currently changing as a result
- * of user input or simulated user input.
- */
- public static final int STATE_DRAGGING = 1;
-
- /**
- * A view is currently settling into place as a result of a fling or
- * predefined non-interactive motion.
- */
- public static final int STATE_SETTLING = 2;
-
- /**
- * Edge flag indicating that the left edge should be affected.
- */
- public static final int EDGE_LEFT = 1 << 0;
-
- /**
- * Edge flag indicating that the right edge should be affected.
- */
- public static final int EDGE_RIGHT = 1 << 1;
-
- /**
- * Edge flag indicating that the top edge should be affected.
- */
- public static final int EDGE_TOP = 1 << 2;
-
- /**
- * Edge flag indicating that the bottom edge should be affected.
- */
- public static final int EDGE_BOTTOM = 1 << 3;
-
- /**
- * Edge flag set indicating all edges should be affected.
- */
- public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;
-
- /**
- * Indicates that a check should occur along the horizontal axis
- */
- public static final int DIRECTION_HORIZONTAL = 1 << 0;
-
- /**
- * Indicates that a check should occur along the vertical axis
- */
- public static final int DIRECTION_VERTICAL = 1 << 1;
-
- /**
- * Indicates that a check should occur along all axes
- */
- public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
-
- private static final int EDGE_SIZE = 20; // dp
-
- private static final int BASE_SETTLE_DURATION = 256; // ms
- private static final int MAX_SETTLE_DURATION = 600; // ms
-
- // Current drag state; idle, dragging or settling
- private int mDragState;
-
- // Distance to travel before a drag may begin
- private int mTouchSlop;
-
- // Last known position/pointer tracking
- private int mActivePointerId = INVALID_POINTER;
- private float[] mInitialMotionX;
- private float[] mInitialMotionY;
- private float[] mLastMotionX;
- private float[] mLastMotionY;
- private int[] mInitialEdgesTouched;
- private int[] mEdgeDragsInProgress;
- private int[] mEdgeDragsLocked;
- private int mPointersDown;
-
- private VelocityTracker mVelocityTracker;
- private float mMaxVelocity;
- private float mMinVelocity;
-
- private int mEdgeSize;
- private int mTrackingEdges;
-
- private ScrollerCompat mScroller;
-
- private final Callback mCallback;
-
- private View mCapturedView;
- private boolean mReleaseInProgress;
-
- private final ViewGroup mParentView;
-
- /**
- * A Callback is used as a communication channel with the ViewDragHelper back to the
- * parent view using it. on*methods are invoked on siginficant events and several
- * accessor methods are expected to provide the ViewDragHelper with more information
- * about the state of the parent view upon request. The callback also makes decisions
- * governing the range and draggability of child views.
- */
- public static abstract class Callback {
- /**
- * Called when the drag state changes. See the STATE_* constants
- * for more information.
- *
- * @param state The new drag state
- *
- * @see #STATE_IDLE
- * @see #STATE_DRAGGING
- * @see #STATE_SETTLING
- */
- public void onViewDragStateChanged(int state) {}
-
- /**
- * Called when the captured view's position changes as the result of a drag or settle.
- *
- * @param changedView View whose position changed
- * @param left New X coordinate of the left edge of the view
- * @param top New Y coordinate of the top edge of the view
- * @param dx Change in X position from the last call
- * @param dy Change in Y position from the last call
- */
- public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {}
-
- /**
- * Called when a child view is captured for dragging or settling. The ID of the pointer
- * currently dragging the captured view is supplied. If activePointerId is
- * identified as {@link #INVALID_POINTER} the capture is programmatic instead of
- * pointer-initiated.
- *
- * @param capturedChild Child view that was captured
- * @param activePointerId Pointer id tracking the child capture
- */
- public void onViewCaptured(View capturedChild, int activePointerId) {}
-
- /**
- * Called when the child view is no longer being actively dragged.
- * The fling velocity is also supplied, if relevant. The velocity values may
- * be clamped to system minimums or maximums.
- *
- *
Calling code may decide to fling or otherwise release the view to let it
- * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)}
- * or {@link #flingCapturedView(int, int, int, int)}. If the Callback invokes
- * one of these methods, the ViewDragHelper will enter {@link #STATE_SETTLING}
- * and the view capture will not fully end until it comes to a complete stop.
- * If neither of these methods is invoked before onViewReleased returns,
- * the view will stop in place and the ViewDragHelper will return to
- * {@link #STATE_IDLE}.
- *
- * @param releasedChild The captured child view now being released
- * @param xvel X velocity of the pointer as it left the screen in pixels per second.
- * @param yvel Y velocity of the pointer as it left the screen in pixels per second.
- */
- public void onViewReleased(View releasedChild, float xvel, float yvel) {}
-
- /**
- * Called when one of the subscribed edges in the parent view has been touched
- * by the user while no child view is currently captured.
- *
- * @param edgeFlags A combination of edge flags describing the edge(s) currently touched
- * @param pointerId ID of the pointer touching the described edge(s)
- * @see #EDGE_LEFT
- * @see #EDGE_TOP
- * @see #EDGE_RIGHT
- * @see #EDGE_BOTTOM
- */
- public void onEdgeTouched(int edgeFlags, int pointerId) {}
-
- /**
- * Called when the given edge may become locked. This can happen if an edge drag
- * was preliminarily rejected before beginning, but after {@link #onEdgeTouched(int, int)}
- * was called. This method should return true to lock this edge or false to leave it
- * unlocked. The default behavior is to leave edges unlocked.
- *
- * @param edgeFlags A combination of edge flags describing the edge(s) locked
- * @return true to lock the edge, false to leave it unlocked
- */
- public boolean onEdgeLock(int edgeFlags) {
- return false;
- }
-
- /**
- * Called when the user has started a deliberate drag away from one
- * of the subscribed edges in the parent view while no child view is currently captured.
- *
- * @param edgeFlags A combination of edge flags describing the edge(s) dragged
- * @param pointerId ID of the pointer touching the described edge(s)
- * @see #EDGE_LEFT
- * @see #EDGE_TOP
- * @see #EDGE_RIGHT
- * @see #EDGE_BOTTOM
- */
- public void onEdgeDragStarted(int edgeFlags, int pointerId) {}
-
- /**
- * Called to determine the Z-order of child views.
- *
- * @param index the ordered position to query for
- * @return index of the view that should be ordered at position index
- */
- public int getOrderedChildIndex(int index) {
- return index;
- }
-
- /**
- * Return the magnitude of a draggable child view's horizontal range of motion in pixels.
- * This method should return 0 for views that cannot move horizontally.
- *
- * @param child Child view to check
- * @return range of horizontal motion in pixels
- */
- public int getViewHorizontalDragRange(View child) {
- return 0;
- }
-
- /**
- * Return the magnitude of a draggable child view's vertical range of motion in pixels.
- * This method should return 0 for views that cannot move vertically.
- *
- * @param child Child view to check
- * @return range of vertical motion in pixels
- */
- public int getViewVerticalDragRange(View child) {
- return 0;
- }
-
- /**
- * Called when the user's input indicates that they want to capture the given child view
- * with the pointer indicated by pointerId. The callback should return true if the user
- * is permitted to drag the given view with the indicated pointer.
- *
- *
ViewDragHelper may call this method multiple times for the same view even if
- * the view is already captured; this indicates that a new pointer is trying to take
- * control of the view.
- *
- *
If this method returns true, a call to {@link #onViewCaptured(android.view.View, int)}
- * will follow if the capture is successful.
- *
- * @param child Child the user is attempting to capture
- * @param pointerId ID of the pointer attempting the capture
- * @return true if capture should be allowed, false otherwise
- */
- public abstract boolean tryCaptureView(View child, int pointerId);
-
- /**
- * Restrict the motion of the dragged child view along the horizontal axis.
- * The default implementation does not allow horizontal motion; the extending
- * class must override this method and provide the desired clamping.
- *
- *
- * @param child Child view being dragged
- * @param left Attempted motion along the X axis
- * @param dx Proposed change in position for left
- * @return The new clamped position for left
- */
- public int clampViewPositionHorizontal(View child, int left, int dx) {
- return 0;
- }
-
- /**
- * Restrict the motion of the dragged child view along the vertical axis.
- * The default implementation does not allow vertical motion; the extending
- * class must override this method and provide the desired clamping.
- *
- *
- * @param child Child view being dragged
- * @param top Attempted motion along the Y axis
- * @param dy Proposed change in position for top
- * @return The new clamped position for top
- */
- public int clampViewPositionVertical(View child, int top, int dy) {
- return 0;
- }
- }
-
- /**
- * Interpolator defining the animation curve for mScroller
- */
- private static final Interpolator sInterpolator = new Interpolator() {
- public float getInterpolation(float t) {
- t -= 1.0f;
- return t * t * t * t * t + 1.0f;
- }
- };
-
- private final Runnable mSetIdleRunnable = new Runnable() {
- public void run() {
- setDragState(STATE_IDLE);
- }
- };
-
- /**
- * Factory method to create a new ViewDragHelper.
- *
- * @param forParent Parent view to monitor
- * @param cb Callback to provide information and receive events
- * @return a new ViewDragHelper instance
- */
- public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
- return new ViewDragHelper(forParent.getContext(), forParent, cb);
- }
-
- /**
- * Factory method to create a new ViewDragHelper.
- *
- * @param forParent Parent view to monitor
- * @param sensitivity Multiplier for how sensitive the helper should be about detecting
- * the start of a drag. Larger values are more sensitive. 1.0f is normal.
- * @param cb Callback to provide information and receive events
- * @return a new ViewDragHelper instance
- */
- public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
- final ViewDragHelper helper = create(forParent, cb);
- helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
- return helper;
- }
-
- /**
- * Apps should use ViewDragHelper.create() to get a new instance.
- * This will allow VDH to use internal compatibility implementations for different
- * platform versions.
- *
- * @param context Context to initialize config-dependent params from
- * @param forParent Parent view to monitor
- */
- private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {
- if (forParent == null) {
- throw new IllegalArgumentException("Parent view may not be null");
- }
- if (cb == null) {
- throw new IllegalArgumentException("Callback may not be null");
- }
-
- mParentView = forParent;
- mCallback = cb;
-
- final ViewConfiguration vc = ViewConfiguration.get(context);
- final float density = context.getResources().getDisplayMetrics().density;
- mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);
-
- mTouchSlop = vc.getScaledTouchSlop();
- mMaxVelocity = vc.getScaledMaximumFlingVelocity();
- mMinVelocity = vc.getScaledMinimumFlingVelocity();
- mScroller = ScrollerCompat.create(context, sInterpolator);
- }
-
- /**
- * Set the minimum velocity that will be detected as having a magnitude greater than zero
- * in pixels per second. Callback methods accepting a velocity will be clamped appropriately.
- *
- * @param minVel Minimum velocity to detect
- */
- public void setMinVelocity(float minVel) {
- mMinVelocity = minVel;
- }
-
- /**
- * Return the currently configured minimum velocity. Any flings with a magnitude less
- * than this value in pixels per second. Callback methods accepting a velocity will receive
- * zero as a velocity value if the real detected velocity was below this threshold.
- *
- * @return the minimum velocity that will be detected
- */
- public float getMinVelocity() {
- return mMinVelocity;
- }
-
- /**
- * Retrieve the current drag state of this helper. This will return one of
- * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
- * @return The current drag state
- */
- public int getViewDragState() {
- return mDragState;
- }
-
- /**
- * Enable edge tracking for the selected edges of the parent view.
- * The callback's {@link Callback#onEdgeTouched(int, int)} and
- * {@link Callback#onEdgeDragStarted(int, int)} methods will only be invoked
- * for edges for which edge tracking has been enabled.
- *
- * @param edgeFlags Combination of edge flags describing the edges to watch
- * @see #EDGE_LEFT
- * @see #EDGE_TOP
- * @see #EDGE_RIGHT
- * @see #EDGE_BOTTOM
- */
- public void setEdgeTrackingEnabled(int edgeFlags) {
- mTrackingEdges = edgeFlags;
- }
-
- /**
- * Return the size of an edge. This is the range in pixels along the edges of this view
- * that will actively detect edge touches or drags if edge tracking is enabled.
- *
- * @return The size of an edge in pixels
- * @see #setEdgeTrackingEnabled(int)
- */
- public int getEdgeSize() {
- return mEdgeSize;
- }
-
- /**
- * Capture a specific child view for dragging within the parent. The callback will be notified
- * but {@link Callback#tryCaptureView(android.view.View, int)} will not be asked permission to
- * capture this view.
- *
- * @param childView Child view to capture
- * @param activePointerId ID of the pointer that is dragging the captured child view
- */
- public void captureChildView(View childView, int activePointerId) {
- if (childView.getParent() != mParentView) {
- throw new IllegalArgumentException("captureChildView: parameter must be a descendant " +
- "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
- }
-
- mCapturedView = childView;
- mActivePointerId = activePointerId;
- mCallback.onViewCaptured(childView, activePointerId);
- setDragState(STATE_DRAGGING);
- }
-
- /**
- * @return The currently captured view, or null if no view has been captured.
- */
- public View getCapturedView() {
- return mCapturedView;
- }
-
- /**
- * @return The ID of the pointer currently dragging the captured view,
- * or {@link #INVALID_POINTER}.
- */
- public int getActivePointerId() {
- return mActivePointerId;
- }
-
- /**
- * @return The minimum distance in pixels that the user must travel to initiate a drag
- */
- public int getTouchSlop() {
- return mTouchSlop;
- }
-
- /**
- * The result of a call to this method is equivalent to
- * {@link #processTouchEvent(android.view.MotionEvent)} receiving an ACTION_CANCEL event.
- */
- public void cancel() {
- mActivePointerId = INVALID_POINTER;
- clearMotionHistory();
-
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
-
- /**
- * {@link #cancel()}, but also abort all motion in progress and snap to the end of any
- * animation.
- */
- public void abort() {
- cancel();
- if (mDragState == STATE_SETTLING) {
- final int oldX = mScroller.getCurrX();
- final int oldY = mScroller.getCurrY();
- mScroller.abortAnimation();
- final int newX = mScroller.getCurrX();
- final int newY = mScroller.getCurrY();
- mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY);
- }
- setDragState(STATE_IDLE);
- }
-
- /**
- * Animate the view child to the given (left, top) position.
- * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
- * on each subsequent frame to continue the motion until it returns false. If this method
- * returns false there is no further work to do to complete the movement.
- *
- *
This operation does not count as a capture event, though {@link #getCapturedView()}
- * will still report the sliding view while the slide is in progress.
- *
- * @param child Child view to capture and animate
- * @param finalLeft Final left position of child
- * @param finalTop Final top position of child
- * @return true if animation should continue through {@link #continueSettling(boolean)} calls
- */
- public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {
- mCapturedView = child;
- mActivePointerId = INVALID_POINTER;
-
- boolean continueSliding = forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);
- if (!continueSliding && mDragState == STATE_IDLE && mCapturedView != null) {
- // If we're in an IDLE state to begin with and aren't moving anywhere, we
- // end up having a non-null capturedView with an IDLE dragState
- mCapturedView = null;
- }
-
- return continueSliding;
- }
-
- /**
- * Settle the captured view at the given (left, top) position.
- * The appropriate velocity from prior motion will be taken into account.
- * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
- * on each subsequent frame to continue the motion until it returns false. If this method
- * returns false there is no further work to do to complete the movement.
- *
- * @param finalLeft Settled left edge position for the captured view
- * @param finalTop Settled top edge position for the captured view
- * @return true if animation should continue through {@link #continueSettling(boolean)} calls
- */
- public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
- if (!mReleaseInProgress) {
- throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to " +
- "Callback#onViewReleased");
- }
-
- return forceSettleCapturedViewAt(finalLeft, finalTop,
- (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
- (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));
- }
-
- /**
- * Settle the captured view at the given (left, top) position.
- *
- * @param finalLeft Target left position for the captured view
- * @param finalTop Target top position for the captured view
- * @param xvel Horizontal velocity
- * @param yvel Vertical velocity
- * @return true if animation should continue through {@link #continueSettling(boolean)} calls
- */
- private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {
- final int startLeft = mCapturedView.getLeft();
- final int startTop = mCapturedView.getTop();
- final int dx = finalLeft - startLeft;
- final int dy = finalTop - startTop;
-
- if (dx == 0 && dy == 0) {
- // Nothing to do. Send callbacks, be done.
- mScroller.abortAnimation();
- setDragState(STATE_IDLE);
- return false;
- }
-
- final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);
- mScroller.startScroll(startLeft, startTop, dx, dy, duration);
-
- setDragState(STATE_SETTLING);
- return true;
- }
-
- private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {
- xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);
- yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);
- final int absDx = Math.abs(dx);
- final int absDy = Math.abs(dy);
- final int absXVel = Math.abs(xvel);
- final int absYVel = Math.abs(yvel);
- final int addedVel = absXVel + absYVel;
- final int addedDistance = absDx + absDy;
-
- final float xweight = xvel != 0 ? (float) absXVel / addedVel :
- (float) absDx / addedDistance;
- final float yweight = yvel != 0 ? (float) absYVel / addedVel :
- (float) absDy / addedDistance;
-
- int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));
- int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));
-
- return (int) (xduration * xweight + yduration * yweight);
- }
-
- private int computeAxisDuration(int delta, int velocity, int motionRange) {
- if (delta == 0) {
- return 0;
- }
-
- final int width = mParentView.getWidth();
- final int halfWidth = width / 2;
- final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);
- final float distance = halfWidth + halfWidth *
- distanceInfluenceForSnapDuration(distanceRatio);
-
- int duration;
- velocity = Math.abs(velocity);
- if (velocity > 0) {
- duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
- } else {
- final float range = (float) Math.abs(delta) / motionRange;
- duration = (int) ((range + 1) * BASE_SETTLE_DURATION);
- }
- return Math.min(duration, MAX_SETTLE_DURATION);
- }
-
- /**
- * Clamp the magnitude of value for absMin and absMax.
- * If the value is below the minimum, it will be clamped to zero.
- * If the value is above the maximum, it will be clamped to the maximum.
- *
- * @param value Value to clamp
- * @param absMin Absolute value of the minimum significant value to return
- * @param absMax Absolute value of the maximum value to return
- * @return The clamped value with the same sign as value
- */
- private int clampMag(int value, int absMin, int absMax) {
- final int absValue = Math.abs(value);
- if (absValue < absMin) return 0;
- if (absValue > absMax) return value > 0 ? absMax : -absMax;
- return value;
- }
-
- /**
- * Clamp the magnitude of value for absMin and absMax.
- * If the value is below the minimum, it will be clamped to zero.
- * If the value is above the maximum, it will be clamped to the maximum.
- *
- * @param value Value to clamp
- * @param absMin Absolute value of the minimum significant value to return
- * @param absMax Absolute value of the maximum value to return
- * @return The clamped value with the same sign as value
- */
- private float clampMag(float value, float absMin, float absMax) {
- final float absValue = Math.abs(value);
- if (absValue < absMin) return 0;
- if (absValue > absMax) return value > 0 ? absMax : -absMax;
- return value;
- }
-
- private float distanceInfluenceForSnapDuration(float f) {
- f -= 0.5f; // center the values about 0.
- f *= 0.3f * Math.PI / 2.0f;
- return (float) Math.sin(f);
- }
-
- /**
- * Settle the captured view based on standard free-moving fling behavior.
- * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame
- * to continue the motion until it returns false.
- *
- * @param minLeft Minimum X position for the view's left edge
- * @param minTop Minimum Y position for the view's top edge
- * @param maxLeft Maximum X position for the view's left edge
- * @param maxTop Maximum Y position for the view's top edge
- */
- public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {
- if (!mReleaseInProgress) {
- throw new IllegalStateException("Cannot flingCapturedView outside of a call to " +
- "Callback#onViewReleased");
- }
-
- mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),
- (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
- (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),
- minLeft, maxLeft, minTop, maxTop);
-
- setDragState(STATE_SETTLING);
- }
-
- /**
- * Move the captured settling view by the appropriate amount for the current time.
- * If continueSettling returns true, the caller should call it again
- * on the next frame to continue.
- *
- * @param deferCallbacks true if state callbacks should be deferred via posted message.
- * Set this to true if you are calling this method from
- * {@link android.view.View#computeScroll()} or similar methods
- * invoked as part of layout or drawing.
- * @return true if settle is still in progress
- */
- public boolean continueSettling(boolean deferCallbacks) {
- if (mDragState == STATE_SETTLING) {
- boolean keepGoing = mScroller.computeScrollOffset();
- final int x = mScroller.getCurrX();
- final int y = mScroller.getCurrY();
- final int dx = x - mCapturedView.getLeft();
- final int dy = y - mCapturedView.getTop();
-
- if (dx != 0) {
- ViewCompat.offsetLeftAndRight(mCapturedView, dx);
- }
- if (dy != 0) {
- ViewCompat.offsetTopAndBottom(mCapturedView, dy);
- }
-
- if (dx != 0 || dy != 0) {
- mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);
- }
-
- if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {
- // Close enough. The interpolator/scroller might think we're still moving
- // but the user sure doesn't.
- mScroller.abortAnimation();
- keepGoing = false;
- }
-
- if (!keepGoing) {
- if (deferCallbacks) {
- mParentView.post(mSetIdleRunnable);
- } else {
- setDragState(STATE_IDLE);
- }
- }
- }
-
- return mDragState == STATE_SETTLING;
- }
-
- /**
- * Like all callback events this must happen on the UI thread, but release
- * involves some extra semantics. During a release (mReleaseInProgress)
- * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)}
- * or {@link #flingCapturedView(int, int, int, int)}.
- */
- private void dispatchViewReleased(float xvel, float yvel) {
- mReleaseInProgress = true;
- mCallback.onViewReleased(mCapturedView, xvel, yvel);
- mReleaseInProgress = false;
-
- if (mDragState == STATE_DRAGGING) {
- // onViewReleased didn't call a method that would have changed this. Go idle.
- setDragState(STATE_IDLE);
- }
- }
-
- private void clearMotionHistory() {
- if (mInitialMotionX == null) {
- return;
- }
- Arrays.fill(mInitialMotionX, 0);
- Arrays.fill(mInitialMotionY, 0);
- Arrays.fill(mLastMotionX, 0);
- Arrays.fill(mLastMotionY, 0);
- Arrays.fill(mInitialEdgesTouched, 0);
- Arrays.fill(mEdgeDragsInProgress, 0);
- Arrays.fill(mEdgeDragsLocked, 0);
- mPointersDown = 0;
- }
-
- private void clearMotionHistory(int pointerId) {
- if (mInitialMotionX == null || !isPointerDown(pointerId)) {
- return;
- }
- mInitialMotionX[pointerId] = 0;
- mInitialMotionY[pointerId] = 0;
- mLastMotionX[pointerId] = 0;
- mLastMotionY[pointerId] = 0;
- mInitialEdgesTouched[pointerId] = 0;
- mEdgeDragsInProgress[pointerId] = 0;
- mEdgeDragsLocked[pointerId] = 0;
- mPointersDown &= ~(1 << pointerId);
- }
-
- private void ensureMotionHistorySizeForId(int pointerId) {
- if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) {
- float[] imx = new float[pointerId + 1];
- float[] imy = new float[pointerId + 1];
- float[] lmx = new float[pointerId + 1];
- float[] lmy = new float[pointerId + 1];
- int[] iit = new int[pointerId + 1];
- int[] edip = new int[pointerId + 1];
- int[] edl = new int[pointerId + 1];
-
- if (mInitialMotionX != null) {
- System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length);
- System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length);
- System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length);
- System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length);
- System.arraycopy(mInitialEdgesTouched, 0, iit, 0, mInitialEdgesTouched.length);
- System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length);
- System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length);
- }
-
- mInitialMotionX = imx;
- mInitialMotionY = imy;
- mLastMotionX = lmx;
- mLastMotionY = lmy;
- mInitialEdgesTouched = iit;
- mEdgeDragsInProgress = edip;
- mEdgeDragsLocked = edl;
- }
- }
-
- private void saveInitialMotion(float x, float y, int pointerId) {
- ensureMotionHistorySizeForId(pointerId);
- mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x;
- mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y;
- mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y);
- mPointersDown |= 1 << pointerId;
- }
-
- private void saveLastMotion(MotionEvent ev) {
- final int pointerCount = MotionEventCompat.getPointerCount(ev);
- for (int i = 0; i < pointerCount; i++) {
- final int pointerId = MotionEventCompat.getPointerId(ev, i);
- // If pointer is invalid then skip saving on ACTION_MOVE.
- if (!isValidPointerForActionMove(pointerId)) {
- continue;
- }
- final float x = MotionEventCompat.getX(ev, i);
- final float y = MotionEventCompat.getY(ev, i);
- mLastMotionX[pointerId] = x;
- mLastMotionY[pointerId] = y;
- }
- }
-
- /**
- * Check if the given pointer ID represents a pointer that is currently down (to the best
- * of the ViewDragHelper's knowledge).
- *
- *
The state used to report this information is populated by the methods
- * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
- * {@link #processTouchEvent(android.view.MotionEvent)}. If one of these methods has not
- * been called for all relevant MotionEvents to track, the information reported
- * by this method may be stale or incorrect.
- *
- * @param pointerId pointer ID to check; corresponds to IDs provided by MotionEvent
- * @return true if the pointer with the given ID is still down
- */
- public boolean isPointerDown(int pointerId) {
- return (mPointersDown & 1 << pointerId) != 0;
- }
-
- void setDragState(int state) {
- mParentView.removeCallbacks(mSetIdleRunnable);
- if (mDragState != state) {
- mDragState = state;
- mCallback.onViewDragStateChanged(state);
- if (mDragState == STATE_IDLE) {
- mCapturedView = null;
- }
- }
- }
-
- /**
- * Attempt to capture the view with the given pointer ID. The callback will be involved.
- * This will put us into the "dragging" state. If we've already captured this view with
- * this pointer this method will immediately return true without consulting the callback.
- *
- * @param toCapture View to capture
- * @param pointerId Pointer to capture with
- * @return true if capture was successful
- */
- boolean tryCaptureViewForDrag(View toCapture, int pointerId) {
- if (toCapture == mCapturedView && mActivePointerId == pointerId) {
- // Already done!
- return true;
- }
- if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) {
- mActivePointerId = pointerId;
- captureChildView(toCapture, pointerId);
- return true;
- }
- return false;
- }
-
- /**
- * Tests scrollability within child views of v given a delta of dx.
- *
- * @param v View to test for horizontal scrollability
- * @param checkV Whether the view v passed should itself be checked for scrollability (true),
- * or just its children (false).
- * @param dx Delta scrolled in pixels along the X axis
- * @param dy Delta scrolled in pixels along the Y axis
- * @param x X coordinate of the active touch point
- * @param y Y coordinate of the active touch point
- * @return true if child views of v can be scrolled by delta of dx.
- */
- protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) {
- if (v instanceof ViewGroup) {
- final ViewGroup group = (ViewGroup) v;
- final int scrollX = v.getScrollX();
- final int scrollY = v.getScrollY();
- final int count = group.getChildCount();
- // Count backwards - let topmost views consume scroll distance first.
- for (int i = count - 1; i >= 0; i--) {
- // TODO: Add versioned support here for transformed views.
- // This will not work for transformed views in Honeycomb+
- final View child = group.getChildAt(i);
- if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
- y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
- canScroll(child, true, dx, dy, x + scrollX - child.getLeft(),
- y + scrollY - child.getTop())) {
- return true;
- }
- }
- }
-
- return checkV && (ViewCompat.canScrollHorizontally(v, -dx) ||
- ViewCompat.canScrollVertically(v, -dy));
- }
-
- /**
- * Check if this event as provided to the parent view's onInterceptTouchEvent should
- * cause the parent to intercept the touch event stream.
- *
- * @param ev MotionEvent provided to onInterceptTouchEvent
- * @return true if the parent view should return true from onInterceptTouchEvent
- */
- public boolean shouldInterceptTouchEvent(MotionEvent ev) {
- final int action = MotionEventCompat.getActionMasked(ev);
- final int actionIndex = MotionEventCompat.getActionIndex(ev);
-
- if (action == MotionEvent.ACTION_DOWN) {
- // Reset things for a new event stream, just in case we didn't get
- // the whole previous stream.
- cancel();
- }
-
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
-
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- final int pointerId = MotionEventCompat.getPointerId(ev, 0);
- saveInitialMotion(x, y, pointerId);
-
- final View toCapture = findTopChildUnder((int) x, (int) y);
-
- // Catch a settling view if possible.
- if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
- tryCaptureViewForDrag(toCapture, pointerId);
- }
-
- final int edgesTouched = mInitialEdgesTouched[pointerId];
- if ((edgesTouched & mTrackingEdges) != 0) {
- mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
- }
- break;
- }
-
- case MotionEventCompat.ACTION_POINTER_DOWN: {
- final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
- final float x = MotionEventCompat.getX(ev, actionIndex);
- final float y = MotionEventCompat.getY(ev, actionIndex);
-
- saveInitialMotion(x, y, pointerId);
-
- // A ViewDragHelper can only manipulate one view at a time.
- if (mDragState == STATE_IDLE) {
- final int edgesTouched = mInitialEdgesTouched[pointerId];
- if ((edgesTouched & mTrackingEdges) != 0) {
- mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
- }
- } else if (mDragState == STATE_SETTLING) {
- // Catch a settling view if possible.
- final View toCapture = findTopChildUnder((int) x, (int) y);
- if (toCapture == mCapturedView) {
- tryCaptureViewForDrag(toCapture, pointerId);
- }
- }
- break;
- }
-
- case MotionEvent.ACTION_MOVE: {
- if (mInitialMotionX == null || mInitialMotionY == null) break;
-
- // First to cross a touch slop over a draggable view wins. Also report edge drags.
- final int pointerCount = MotionEventCompat.getPointerCount(ev);
- for (int i = 0; i < pointerCount; i++) {
- final int pointerId = MotionEventCompat.getPointerId(ev, i);
-
- // If pointer is invalid then skip the ACTION_MOVE.
- if (!isValidPointerForActionMove(pointerId)) continue;
-
- final float x = MotionEventCompat.getX(ev, i);
- final float y = MotionEventCompat.getY(ev, i);
- final float dx = x - mInitialMotionX[pointerId];
- final float dy = y - mInitialMotionY[pointerId];
-
- final View toCapture = findTopChildUnder((int) x, (int) y);
- final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy);
- if (pastSlop) {
- // check the callback's
- // getView[Horizontal|Vertical]DragRange methods to know
- // if you can move at all along an axis, then see if it
- // would clamp to the same value. If you can't move at
- // all in every dimension with a nonzero range, bail.
- final int oldLeft = toCapture.getLeft();
- final int targetLeft = oldLeft + (int) dx;
- final int newLeft = mCallback.clampViewPositionHorizontal(toCapture,
- targetLeft, (int) dx);
- final int oldTop = toCapture.getTop();
- final int targetTop = oldTop + (int) dy;
- final int newTop = mCallback.clampViewPositionVertical(toCapture, targetTop,
- (int) dy);
- final int horizontalDragRange = mCallback.getViewHorizontalDragRange(
- toCapture);
- final int verticalDragRange = mCallback.getViewVerticalDragRange(toCapture);
- if ((horizontalDragRange == 0 || horizontalDragRange > 0
- && newLeft == oldLeft) && (verticalDragRange == 0
- || verticalDragRange > 0 && newTop == oldTop)) {
- break;
- }
- }
- reportNewEdgeDrags(dx, dy, pointerId);
- if (mDragState == STATE_DRAGGING) {
- // Callback might have started an edge drag
- break;
- }
-
- if (pastSlop && tryCaptureViewForDrag(toCapture, pointerId)) {
- break;
- }
- }
- saveLastMotion(ev);
- break;
- }
-
- case MotionEventCompat.ACTION_POINTER_UP: {
- final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
- clearMotionHistory(pointerId);
- break;
- }
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL: {
- cancel();
- break;
- }
- }
-
- return mDragState == STATE_DRAGGING;
- }
-
- /**
- * Process a touch event received by the parent view. This method will dispatch callback events
- * as needed before returning. The parent view's onTouchEvent implementation should call this.
- *
- * @param ev The touch event received by the parent view
- */
- public void processTouchEvent(MotionEvent ev) {
- final int action = MotionEventCompat.getActionMasked(ev);
- final int actionIndex = MotionEventCompat.getActionIndex(ev);
-
- if (action == MotionEvent.ACTION_DOWN) {
- // Reset things for a new event stream, just in case we didn't get
- // the whole previous stream.
- cancel();
- }
-
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
-
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- final int pointerId = MotionEventCompat.getPointerId(ev, 0);
- final View toCapture = findTopChildUnder((int) x, (int) y);
-
- saveInitialMotion(x, y, pointerId);
-
- // Since the parent is already directly processing this touch event,
- // there is no reason to delay for a slop before dragging.
- // Start immediately if possible.
- tryCaptureViewForDrag(toCapture, pointerId);
-
- final int edgesTouched = mInitialEdgesTouched[pointerId];
- if ((edgesTouched & mTrackingEdges) != 0) {
- mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
- }
- break;
- }
-
- case MotionEventCompat.ACTION_POINTER_DOWN: {
- final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
- final float x = MotionEventCompat.getX(ev, actionIndex);
- final float y = MotionEventCompat.getY(ev, actionIndex);
-
- saveInitialMotion(x, y, pointerId);
-
- // A ViewDragHelper can only manipulate one view at a time.
- if (mDragState == STATE_IDLE) {
- // If we're idle we can do anything! Treat it like a normal down event.
-
- final View toCapture = findTopChildUnder((int) x, (int) y);
- tryCaptureViewForDrag(toCapture, pointerId);
-
- final int edgesTouched = mInitialEdgesTouched[pointerId];
- if ((edgesTouched & mTrackingEdges) != 0) {
- mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
- }
- } else if (isCapturedViewUnder((int) x, (int) y)) {
- // We're still tracking a captured view. If the same view is under this
- // point, we'll swap to controlling it with this pointer instead.
- // (This will still work if we're "catching" a settling view.)
-
- tryCaptureViewForDrag(mCapturedView, pointerId);
- }
- break;
- }
-
- case MotionEvent.ACTION_MOVE: {
- if (mDragState == STATE_DRAGGING) {
- // If pointer is invalid then skip the ACTION_MOVE.
- if (!isValidPointerForActionMove(mActivePointerId)) break;
-
- final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, index);
- final float y = MotionEventCompat.getY(ev, index);
- final int idx = (int) (x - mLastMotionX[mActivePointerId]);
- final int idy = (int) (y - mLastMotionY[mActivePointerId]);
-
- dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);
-
- saveLastMotion(ev);
- } else {
- // Check to see if any pointer is now over a draggable view.
- final int pointerCount = MotionEventCompat.getPointerCount(ev);
- for (int i = 0; i < pointerCount; i++) {
- final int pointerId = MotionEventCompat.getPointerId(ev, i);
-
- // If pointer is invalid then skip the ACTION_MOVE.
- if (!isValidPointerForActionMove(pointerId)) continue;
-
- final float x = MotionEventCompat.getX(ev, i);
- final float y = MotionEventCompat.getY(ev, i);
- final float dx = x - mInitialMotionX[pointerId];
- final float dy = y - mInitialMotionY[pointerId];
-
- reportNewEdgeDrags(dx, dy, pointerId);
- if (mDragState == STATE_DRAGGING) {
- // Callback might have started an edge drag.
- break;
- }
-
- final View toCapture = findTopChildUnder((int) x, (int) y);
- if (checkTouchSlop(toCapture, dx, dy) &&
- tryCaptureViewForDrag(toCapture, pointerId)) {
- break;
- }
- }
- saveLastMotion(ev);
- }
- break;
- }
-
- case MotionEventCompat.ACTION_POINTER_UP: {
- final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
- if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
- // Try to find another pointer that's still holding on to the captured view.
- int newActivePointer = INVALID_POINTER;
- final int pointerCount = MotionEventCompat.getPointerCount(ev);
- for (int i = 0; i < pointerCount; i++) {
- final int id = MotionEventCompat.getPointerId(ev, i);
- if (id == mActivePointerId) {
- // This one's going away, skip.
- continue;
- }
-
- final float x = MotionEventCompat.getX(ev, i);
- final float y = MotionEventCompat.getY(ev, i);
- if (findTopChildUnder((int) x, (int) y) == mCapturedView &&
- tryCaptureViewForDrag(mCapturedView, id)) {
- newActivePointer = mActivePointerId;
- break;
- }
- }
-
- if (newActivePointer == INVALID_POINTER) {
- // We didn't find another pointer still touching the view, release it.
- releaseViewForPointerUp();
- }
- }
- clearMotionHistory(pointerId);
- break;
- }
-
- case MotionEvent.ACTION_UP: {
- if (mDragState == STATE_DRAGGING) {
- releaseViewForPointerUp();
- }
- cancel();
- break;
- }
-
- case MotionEvent.ACTION_CANCEL: {
- if (mDragState == STATE_DRAGGING) {
- dispatchViewReleased(0, 0);
- }
- cancel();
- break;
- }
- }
- }
-
- private void reportNewEdgeDrags(float dx, float dy, int pointerId) {
- int dragsStarted = 0;
- if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) {
- dragsStarted |= EDGE_LEFT;
- }
- if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) {
- dragsStarted |= EDGE_TOP;
- }
- if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) {
- dragsStarted |= EDGE_RIGHT;
- }
- if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) {
- dragsStarted |= EDGE_BOTTOM;
- }
-
- if (dragsStarted != 0) {
- mEdgeDragsInProgress[pointerId] |= dragsStarted;
- mCallback.onEdgeDragStarted(dragsStarted, pointerId);
- }
- }
-
- private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) {
- final float absDelta = Math.abs(delta);
- final float absODelta = Math.abs(odelta);
-
- if ((mInitialEdgesTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0 ||
- (mEdgeDragsLocked[pointerId] & edge) == edge ||
- (mEdgeDragsInProgress[pointerId] & edge) == edge ||
- (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) {
- return false;
- }
- if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) {
- mEdgeDragsLocked[pointerId] |= edge;
- return false;
- }
- return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop;
- }
-
- /**
- * Check if we've crossed a reasonable touch slop for the given child view.
- * If the child cannot be dragged along the horizontal or vertical axis, motion
- * along that axis will not count toward the slop check.
- *
- * @param child Child to check
- * @param dx Motion since initial position along X axis
- * @param dy Motion since initial position along Y axis
- * @return true if the touch slop has been crossed
- */
- private boolean checkTouchSlop(View child, float dx, float dy) {
- if (child == null) {
- return false;
- }
- final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0;
- final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0;
- if ((dx >= 0 && ViewCompat.canScrollHorizontally(child, -1))
- || (dx <= 0 && ViewCompat.canScrollHorizontally(child, 1))) {
-
- } else {
- if (checkHorizontal && checkVertical) {
- return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
- } else if (checkHorizontal) {
- return Math.abs(dx) > mTouchSlop;
- } else if (checkVertical) {
- return Math.abs(dy) > mTouchSlop;
- }
- }
- return false;
- }
-
- /**
- * Check if any pointer tracked in the current gesture has crossed
- * the required slop threshold.
- *
- *
This depends on internal state populated by
- * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
- * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on
- * the results of this method after all currently available touch data
- * has been provided to one of these two methods.
- *
- * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL},
- * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL}
- * @return true if the slop threshold has been crossed, false otherwise
- */
- public boolean checkTouchSlop(int directions) {
- final int count = mInitialMotionX.length;
- for (int i = 0; i < count; i++) {
- if (checkTouchSlop(directions, i)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check if the specified pointer tracked in the current gesture has crossed
- * the required slop threshold.
- *
- *
This depends on internal state populated by
- * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
- * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on
- * the results of this method after all currently available touch data
- * has been provided to one of these two methods.
- *
- * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL},
- * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL}
- * @param pointerId ID of the pointer to slop check as specified by MotionEvent
- * @return true if the slop threshold has been crossed, false otherwise
- */
- public boolean checkTouchSlop(int directions, int pointerId) {
- if (!isPointerDown(pointerId)) {
- return false;
- }
-
- final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL;
- final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL;
-
- final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId];
- final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId];
-
- if (checkHorizontal && checkVertical) {
- return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
- } else if (checkHorizontal) {
- return Math.abs(dx) > mTouchSlop;
- } else if (checkVertical) {
- return Math.abs(dy) > mTouchSlop;
- }
- return false;
- }
-
- /**
- * Check if any of the edges specified were initially touched in the currently active gesture.
- * If there is no currently active gesture this method will return false.
- *
- * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT},
- * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and
- * {@link #EDGE_ALL}
- * @return true if any of the edges specified were initially touched in the current gesture
- */
- public boolean isEdgeTouched(int edges) {
- final int count = mInitialEdgesTouched.length;
- for (int i = 0; i < count; i++) {
- if (isEdgeTouched(edges, i)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check if any of the edges specified were initially touched by the pointer with
- * the specified ID. If there is no currently active gesture or if there is no pointer with
- * the given ID currently down this method will return false.
- *
- * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT},
- * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and
- * {@link #EDGE_ALL}
- * @return true if any of the edges specified were initially touched in the current gesture
- */
- public boolean isEdgeTouched(int edges, int pointerId) {
- return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0;
- }
-
- private void releaseViewForPointerUp() {
- mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
- final float xvel = clampMag(
- VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
- mMinVelocity, mMaxVelocity);
- final float yvel = clampMag(
- VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),
- mMinVelocity, mMaxVelocity);
- dispatchViewReleased(xvel, yvel);
- }
-
- private void dragTo(int left, int top, int dx, int dy) {
- int clampedX = left;
- int clampedY = top;
- final int oldLeft = mCapturedView.getLeft();
- final int oldTop = mCapturedView.getTop();
- if (dx != 0) {
- clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);
- ViewCompat.offsetLeftAndRight(mCapturedView, clampedX - oldLeft);
- }
- if (dy != 0) {
- clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);
- ViewCompat.offsetTopAndBottom(mCapturedView, clampedY - oldTop);
- }
-
- if (dx != 0 || dy != 0) {
- final int clampedDx = clampedX - oldLeft;
- final int clampedDy = clampedY - oldTop;
- mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY,
- clampedDx, clampedDy);
- }
- }
-
- /**
- * Determine if the currently captured view is under the given point in the
- * parent view's coordinate system. If there is no captured view this method
- * will return false.
- *
- * @param x X position to test in the parent's coordinate system
- * @param y Y position to test in the parent's coordinate system
- * @return true if the captured view is under the given point, false otherwise
- */
- public boolean isCapturedViewUnder(int x, int y) {
- return isViewUnder(mCapturedView, x, y);
- }
-
- /**
- * Determine if the supplied view is under the given point in the
- * parent view's coordinate system.
- *
- * @param view Child view of the parent to hit test
- * @param x X position to test in the parent's coordinate system
- * @param y Y position to test in the parent's coordinate system
- * @return true if the supplied view is under the given point, false otherwise
- */
- public boolean isViewUnder(View view, int x, int y) {
- if (view == null) {
- return false;
- }
- return x >= view.getLeft() &&
- x < view.getRight() &&
- y >= view.getTop() &&
- y < view.getBottom();
- }
-
- /**
- * Find the topmost child under the given point within the parent view's coordinate system.
- * The child order is determined using {@link Callback#getOrderedChildIndex(int)}.
- *
- * @param x X position to test in the parent's coordinate system
- * @param y Y position to test in the parent's coordinate system
- * @return The topmost child view under (x, y) or null if none found.
- */
- public View findTopChildUnder(int x, int y) {
- final int childCount = mParentView.getChildCount();
- for (int i = childCount - 1; i >= 0; i--) {
- final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));
- if (x >= child.getLeft() && x < child.getRight() &&
- y >= child.getTop() && y < child.getBottom()) {
- return child;
- }
- }
- return null;
- }
-
- private int getEdgesTouched(int x, int y) {
- int result = 0;
-
- if (x < mParentView.getLeft() + mEdgeSize) result |= EDGE_LEFT;
- if (y < mParentView.getTop() + mEdgeSize) result |= EDGE_TOP;
- if (x > mParentView.getRight() - mEdgeSize) result |= EDGE_RIGHT;
- if (y > mParentView.getBottom() - mEdgeSize) result |= EDGE_BOTTOM;
-
- return result;
- }
-
- private boolean isValidPointerForActionMove(int pointerId) {
- if (!isPointerDown(pointerId)) {
- Log.e(TAG, "Ignoring pointerId=" + pointerId + " because ACTION_DOWN was not received "
- + "for this pointer before ACTION_MOVE. It likely happened because "
- + " ViewDragHelper did not receive all the events in the event stream.");
- return false;
- }
- return true;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/utils/BrushMap.java b/app/src/main/java/com/loopeer/codereader/utils/BrushMap.java
deleted file mode 100644
index 8172d60..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/BrushMap.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class BrushMap {
- public static HashMap> mapping;
-
- static {
- new BrushMap();
- }
-
- public BrushMap() {
- if (mapping == null) {
- mapping = new HashMap();
- init();
- }
- }
-
- public static final String[] FILE_BLACKLIST = new String[]{"hprof", "apk", "jar", "so"};
-
- public static boolean isBlackFile(String name) {
- if (name != null) return Arrays.asList(FILE_BLACKLIST).contains(name.toLowerCase());
- return false;
- }
-
- public static void init() {
- List list = new ArrayList();
- list.add("actionscript3");
- list.add("as3");
- mapping.put("AS3", list);
- list = new ArrayList();
- list.add("applescript");
- list.add("scpt");
- mapping.put("AppleScript", list);
- list = new ArrayList();
- list.add("bash");
- list.add("shell");
- list.add("sh");
- list.add("rc");
- list.add("conf");
- mapping.put("Bash", list);
- list = new ArrayList();
- list.add("coldfusion");
- list.add("cfm");
- list.add("cf");
- mapping.put("ColdFusion", list);
- list = new ArrayList();
- list.add("cpp");
- list.add("c");
- list.add("cc");
- list.add("h");
- list.add("hpp");
- mapping.put("Cpp", list);
- list = new ArrayList();
- list.add("c#");
- list.add("c-sharp");
- list.add("csharp");
- list.add("cs");
- mapping.put("CSharp", list);
- list = new ArrayList();
- list.add("css");
- mapping.put("Css", list);
- list = new ArrayList();
- list.add("delphi");
- list.add("pascal");
- list.add("pas");
- list.add("simba");
- mapping.put("Delphi", list);
- list = new ArrayList();
- list.add("diff");
- list.add("patch");
- mapping.put("Diff", list);
- list = new ArrayList();
- list.add("erl");
- list.add("hrl");
- mapping.put("Erlang", list);
- list = new ArrayList();
- list.add("groovy");
- mapping.put("Groovy", list);
- list = new ArrayList();
- list.add("java");
- mapping.put("Java", list);
- list = new ArrayList();
- list.add("jfx");
- list.add("javafx");
- mapping.put("JavaFX", list);
- list = new ArrayList();
- list.add("js");
- list.add("jscript");
- list.add("javascript");
- mapping.put("JScript", list);
- list = new ArrayList();
- list.add("perl");
- list.add("pl");
- mapping.put("Perl", list);
- list = new ArrayList();
- list.add("php");
- mapping.put("Php", list);
- list = new ArrayList();
- list.add("text");
- list.add("plain");
- list.add("rst");
- list.add("txt");
- mapping.put("Plain", list);
- list = new ArrayList();
- list.add("powershell");
- list.add("ps");
- list.add("ps1");
- mapping.put("PowerShell", list);
- list = new ArrayList();
- list.add("py");
- list.add("python");
- mapping.put("Python", list);
- list = new ArrayList();
- list.add("ruby");
- list.add("rails");
- list.add("ror");
- mapping.put("Ruby", list);
- list = new ArrayList();
- list.add("sass");
- list.add("scss");
- mapping.put("Sass", list);
- list = new ArrayList();
- list.add("scala");
- mapping.put("Scala", list);
- list = new ArrayList();
- list.add("sql");
- mapping.put("Sql", list);
- list = new ArrayList();
- list.add("v");
- list.add("sv");
- mapping.put("Verilog", list);
- list = new ArrayList();
- list.add("vb");
- list.add("vbnet");
- mapping.put("Vb", list);
- list = new ArrayList();
- list.add("xml");
- list.add("xslt");
- list.add("htm");
- list.add("html");
- list.add("xhtml");
- list.add("xaml");
- list.add("iml");
- list.add("plist");
- list.add("storyboard");
- list.add("xcworkspacedata");
- list.add("xcscheme");
- mapping.put("Xml", list);
- list = new ArrayList();
- list.add("gradle");
- mapping.put("Gradle", list);
- list = new ArrayList();
- list.add("txt");
- list.add("bat");
- list.add("pbxproj");
- mapping.put("Txt", list);
- list = new ArrayList();
- list.add("pro");
- mapping.put("Pro", list);
- list = new ArrayList();
- list.add("properties");
- mapping.put("Properties", list);
- list = new ArrayList();
- list.add("json");
- mapping.put("Json", list);
- list = new ArrayList();
- list.add("swift");
- mapping.put("Swift", list);
- list = new ArrayList();
- list.add("go");
- mapping.put("Go", list);
- }
-
- public static String getJsFileForExtension(String paramString) {
- paramString = paramString.toLowerCase();
- Iterator localIterator = mapping.entrySet().iterator();
- while (localIterator.hasNext()) {
- Map.Entry localEntry = (Map.Entry) localIterator.next();
- if (((List) localEntry.getValue()).indexOf(paramString) != -1) {
- return (String) localEntry.getKey();
- }
- }
- return null;
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/ColorUtils.java b/app/src/main/java/com/loopeer/codereader/utils/ColorUtils.java
deleted file mode 100644
index 4deab59..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/ColorUtils.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-import android.support.v4.content.ContextCompat;
-
-public class ColorUtils {
-
- public static String getColorString(Context context, int res) {
- return String.format("#%06X"
- , 0xFFFFFF & ContextCompat.getColor(context
- , res));
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/CustomTextUtils.java b/app/src/main/java/com/loopeer/codereader/utils/CustomTextUtils.java
deleted file mode 100644
index 056772a..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/CustomTextUtils.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.text.TextUtils;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class CustomTextUtils {
-
- public static int[] calculateTextStartEnd(String strings, String target) {
- int[] result = new int[2];
- result[0] = strings.indexOf(target);
- result[1] = result[0] + target.length();
- return result;
- }
-
-
-
- public static boolean isEmail(String email) {
- if (TextUtils.isEmpty(email)) return false;
- Pattern p = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");//复杂匹配
- Matcher m = p.matcher(email);
- return m.matches();
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/DeviceUtils.java b/app/src/main/java/com/loopeer/codereader/utils/DeviceUtils.java
deleted file mode 100644
index affc43a..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/DeviceUtils.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-
-import com.loopeer.codereader.CodeReaderApplication;
-
-public class DeviceUtils {
-
- public static int getStatusBarHeight() {
- int result = 0;
- int resId = CodeReaderApplication.getAppContext()
- .getResources().getIdentifier("status_bar_height", "dimen", "android");
- if (resId > 0) {
- result = CodeReaderApplication.getAppContext()
- .getResources().getDimensionPixelOffset(resId);
- }
- return result;
- }
-
- public static float dpToPx(Context context, float dpValue) {
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, metrics);
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/DownloadFile.java b/app/src/main/java/com/loopeer/codereader/utils/DownloadFile.java
deleted file mode 100644
index 5e249a6..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/DownloadFile.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public class DownloadFile {
- private static final String TAG = "Download";
- private static final int BUFFER_SIZE = 8192;
-
- /**
- * Download a file from a URL somewhere. The download is atomic; that is, it
- * downloads to a temporary file, then renames it to the requested file name
- * only if the download successfully completes.
- *
- * Returns TRUE if download succeeds, FALSE otherwise.
- *
- */
- public DownloadFile(Context context) {
-
- }
-
- /**
- * Copy from one stream to another. Throws IOException in the event of error
- * (for example, SD card is full)
- *
- * @param is
- * Input stream.
- * @param os
- * Output stream.
- * @param buffer
- * Temporary buffer to use for copy.
- * @param bufferSize
- * Size of temporary buffer, in bytes.
- */
- public static void copyStream(InputStream is, OutputStream os,
- byte[] buffer, int bufferSize, String confid, double fileSize,
- Context context) throws IOException {
- double downloaded = 0;
- int[] update = new int[3];
-
- //Intent intent = new Intent();
- // TODO
- //intent.setAction(Const.BROADCAST + confid);
-
- try {
- for (;;) {
- int count = is.read(buffer, 0, bufferSize);
- downloaded += count;
- if (count == -1) {
- if (context != null) {
- //intent.putExtra("zipcomplete", 1);
- //context.sendBroadcast(intent);
- }
- break;
- }
- os.write(buffer, 0, count);
-
- if (context != null) {
- update[0] = (int) downloaded;
- update[1] = (int) fileSize;
- update[2] = (int) ((downloaded / fileSize) * 100);
- //intent.putExtra("zipprogress", update);
- //context.sendBroadcast(intent);
- }
- }
-
- } catch (IOException e) {
- throw e;
- }
- }
-
- public static String humanReadableByteCount(long bytes, boolean si) {
- int unit = si ? 1000 : 1024;
- if (bytes < unit)
- return bytes + " B";
- int exp = (int) (Math.log(bytes) / Math.log(unit));
- String pre = (si ? "KMGTPE" : "KMGTPE").charAt(exp - 1)
- + (si ? "" : "i");
- return String.format("%.2f %sB", bytes / Math.pow(unit, exp), pre);
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/DownloadUrlParser.java b/app/src/main/java/com/loopeer/codereader/utils/DownloadUrlParser.java
deleted file mode 100644
index e2e1e24..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/DownloadUrlParser.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-import android.text.TextUtils;
-
-import com.loopeer.codereader.Navigator;
-import com.loopeer.codereader.model.Repo;
-
-import java.io.File;
-
-public class DownloadUrlParser {
- private static final String GITHUB_REPO_URL_BASE = "https://codeload.github.com/";
- private static final String ZIP_SUFFIX = ".zip";
-
- public static boolean parseGithubUrlAndDownload(Context context, String url) {
- String downloadUrl = parseGithubDownloadUrl(url);
- if (downloadUrl == null) return false;
- String repoName = getRepoName(url);
- Repo repo = new Repo(repoName
- , FileCache.getInstance().getRepoAbsolutePath(repoName), downloadUrl, true, 0);
- Navigator.startDownloadNewRepoService(context, repo);
- return true;
- }
-
- public static String parseGithubDownloadUrl(String url) {
- if (TextUtils.isEmpty(url)) return null;
- StringBuilder sb = new StringBuilder();
- String[] strings = url.split("/");
- if (strings.length < 5) return null;
- sb.append(GITHUB_REPO_URL_BASE);
- sb.append(strings[3]);
- sb.append("/");
- if (strings.length == 5) {
- if (strings[4].contains("?")) {
- String[] lastName = strings[4].split("\\?");
- sb.append(lastName[0]);
- sb.append("/");
- } else {
- sb.append(strings[4]);
- sb.append("/");
- }
- sb.append("zip/master");
- return sb.toString();
- }
- if (strings.length > 5) {
- sb.append(strings[4]);
- sb.append("/");
- if (strings.length >= 7 && strings[5].equals("tree")) {
- sb.append("zip/");
- if (strings[6].contains("?")) {
- String[] lastName = strings[6].split("\\?");
- sb.append(lastName[0]);
- } else {
- sb.append(strings[6]);
- }
- return sb.toString();
- }
- sb.append("zip/master");
- return sb.toString();
- }
- return null;
- }
-
- public static File getRemoteRepoZipFileName(String repoName) {
- return new File(FileCache.getInstance().getCacheDir(), getRepoNameZip(repoName));
- }
-
- public static String getRepoNameZip(String name) {
- return name + ZIP_SUFFIX;
- }
-
- public static String getRepoName(String url) {
- String[] strings = url.split("/");
- StringBuilder sb = new StringBuilder();
- sb.append(strings[4].split("\\.")[0]);
- if (strings.length >= 7 && strings[5].equals("tree")) {
- sb.append("(");
- if (strings[6].contains("?")) {
- String[] lastName = strings[6].split("\\?");
- sb.append(lastName[0]);
- } else {
- sb.append(strings[6]);
- }
- sb.append(")");
- return sb.toString();
- }
- return sb.toString();
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/FileCache.java b/app/src/main/java/com/loopeer/codereader/utils/FileCache.java
deleted file mode 100644
index a6bd345..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/FileCache.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Environment;
-
-import com.loopeer.codereader.CodeReaderApplication;
-import com.loopeer.codereader.model.DirectoryNode;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-
-public class
-
-
-FileCache {
- private static String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
- private static FileCache instance;
- private static String cachePath = Environment.getExternalStorageDirectory() + "/CodeReader/repo/";
- private File cacheDir;
- public final String cacheDirPath = "/repo/";
-
- private FileCache() {
- if (hasSDCard() && hasExternalStoragePermission(CodeReaderApplication.getAppContext())) {
- cacheDir = createFilePath(cachePath);
- } else {
- cacheDir = createFilePath(CodeReaderApplication.getAppContext().getCacheDir() + cacheDirPath);
- }
- }
-
- private File createFilePath(String filePath) {
- return createFilePath(new File(filePath));
- }
-
- private File createFilePath(File file) {
- if (!file.exists()) {
- file.mkdirs();// 按照文件夹路径创建文件夹
- }
- return file;
- }
-
- public static FileCache getInstance() {
- if (null == instance)
- instance = new FileCache();
- return instance;
- }
-
- public boolean hasSDCard() {
- return Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
- }
-
- public DirectoryNode getFileDirectoryNode() {
- File file = new File(cacheDir, "CardStackView");
- if (file.listFiles() == null || file.listFiles().length == 0) return null;
- return getFileDirectory(file);
- }
-
- public File getCacheDir() {
- return cacheDir;
- }
-
- public String getRepoAbsolutePath(String repoName) {
- return getCacheDir().getPath() + File.separator + repoName;
- }
-
- public static DirectoryNode getFileDirectory(File file) {
- if (file == null) return null;
- DirectoryNode directoryNode = new DirectoryNode();
- directoryNode.name = file.getName();
- directoryNode.absolutePath = file.getAbsolutePath();
- if (file.isDirectory()) {
- directoryNode.isDirectory = true;
- directoryNode.pathNodes = new ArrayList<>();
- for (File childFile : file.listFiles()) {
- if (childFile.getName().startsWith(".") || childFile.getName().startsWith("_")) continue;
- DirectoryNode childNode = getFileDirectory(childFile);
- directoryNode.pathNodes.add(childNode);
- }
- if (!directoryNode.pathNodes.isEmpty()) {
- Collections.sort(directoryNode.pathNodes);
- }
- }
- return directoryNode;
- }
-
- public static boolean hasExternalStoragePermission(Context context) {
- int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
- return perm == PackageManager.PERMISSION_GRANTED;
- }
-
- public static void deleteFilesByDirectory(File directory) {
- if (directory != null && directory.exists() && directory.list() != null) {
- for (File item : directory.listFiles()) {
- if (item.isDirectory()) {
- deleteFilesByDirectory(item);
- } else {
- item.delete();
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/FileTypeUtils.java b/app/src/main/java/com/loopeer/codereader/utils/FileTypeUtils.java
deleted file mode 100644
index afab2a6..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/FileTypeUtils.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-public class FileTypeUtils {
-
- // comma separated list of all file extensions supported by the media scanner
- public static String sFileExtensions;
-
- // Audio file types
- public static final int FILE_TYPE_MP3 = 1;
- public static final int FILE_TYPE_M4A = 2;
- public static final int FILE_TYPE_WAV = 3;
- public static final int FILE_TYPE_AMR = 4;
- public static final int FILE_TYPE_AWB = 5;
- public static final int FILE_TYPE_WMA = 6;
- public static final int FILE_TYPE_OGG = 7;
- private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
- private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG;
-
- // MIDI file types
- public static final int FILE_TYPE_MID = 11;
- public static final int FILE_TYPE_SMF = 12;
- public static final int FILE_TYPE_IMY = 13;
- private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID;
- private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY;
-
- // Video file types
- public static final int FILE_TYPE_MP4 = 21;
- public static final int FILE_TYPE_M4V = 22;
- public static final int FILE_TYPE_3GPP = 23;
- public static final int FILE_TYPE_3GPP2 = 24;
- public static final int FILE_TYPE_WMV = 25;
- private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
- private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV;
-
- // Image file types
- public static final int FILE_TYPE_JPEG = 31;
- public static final int FILE_TYPE_GIF = 32;
- public static final int FILE_TYPE_PNG = 33;
- public static final int FILE_TYPE_BMP = 34;
- public static final int FILE_TYPE_WBMP = 35;
- private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG;
- private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP;
-
- // Playlist file types
- public static final int FILE_TYPE_M3U = 41;
- public static final int FILE_TYPE_PLS = 42;
- public static final int FILE_TYPE_WPL = 43;
- private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U;
- private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL;
-
- // MarkDown file types
- public static final int FILE_TYPE_MARKDOWN = 44;
- public static final int FILE_TYPE_MD = 45;
- private static final int FIRST_MARKDOWNLIST_FILE_TYPE = FILE_TYPE_MARKDOWN;
- private static final int LAST_MARKDOWNLIST_FILE_TYPE = FILE_TYPE_MD;
-
- //静态内部类
- static class MediaFileType {
-
- int fileType;
- String mimeType;
-
- MediaFileType(int fileType, String mimeType) {
- this.fileType = fileType;
- this.mimeType = mimeType;
- }
- }
-
- private static HashMap sFileTypeMap
- = new HashMap();
- private static HashMap sMimeTypeMap
- = new HashMap();
-
- static void addFileType(String extension, int fileType, String mimeType) {
- sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType));
- sMimeTypeMap.put(mimeType, new Integer(fileType));
- }
-
- static {
- addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
- addFileType("M4A", FILE_TYPE_M4A, "audio/mp4");
- addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav");
- addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
- addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
- addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
- addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
-
- addFileType("MID", FILE_TYPE_MID, "audio/midi");
- addFileType("XMF", FILE_TYPE_MID, "audio/midi");
- addFileType("RTTTL", FILE_TYPE_MID, "audio/midi");
- addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi");
- addFileType("IMY", FILE_TYPE_IMY, "audio/imelody");
-
- addFileType("MP4", FILE_TYPE_MP4, "video/mp4");
- addFileType("M4V", FILE_TYPE_M4V, "video/mp4");
- addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp");
- addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
- addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
- addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
- addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
-
- addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
- addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
- addFileType("GIF", FILE_TYPE_GIF, "image/gif");
- addFileType("PNG", FILE_TYPE_PNG, "image/png");
- addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp");
- addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
-
- addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl");
- addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls");
- addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl");
-
- addFileType("MD", FILE_TYPE_MD, "text/markdown");
- addFileType("MARKDOWN", FILE_TYPE_MARKDOWN, "text/markdown");
-
- // compute file extensions list for native Media Scanner
- StringBuilder builder = new StringBuilder();
- Iterator iterator = sFileTypeMap.keySet().iterator();
-
- while (iterator.hasNext()) {
- if (builder.length() > 0) {
- builder.append(',');
- }
- builder.append(iterator.next());
- }
- sFileExtensions = builder.toString();
- }
-
- public static final String UNKNOWN_STRING = "";
-
- private static boolean isAudioFileType(int fileType) {
- return ((fileType >= FIRST_AUDIO_FILE_TYPE &&
- fileType <= LAST_AUDIO_FILE_TYPE) ||
- (fileType >= FIRST_MIDI_FILE_TYPE &&
- fileType <= LAST_MIDI_FILE_TYPE));
- }
-
- private static boolean isVideoFileType(int fileType) {
- return (fileType >= FIRST_VIDEO_FILE_TYPE &&
- fileType <= LAST_VIDEO_FILE_TYPE);
- }
-
- private static boolean isImageFileType(int fileType) {
- return (fileType >= FIRST_IMAGE_FILE_TYPE &&
- fileType <= LAST_IMAGE_FILE_TYPE);
- }
-
- private static boolean isPlayListFileType(int fileType) {
- return (fileType >= FIRST_PLAYLIST_FILE_TYPE &&
- fileType <= LAST_PLAYLIST_FILE_TYPE);
- }
-
- private static boolean isMarkDownFileType(int fileType) {
- return (fileType >= FIRST_MARKDOWNLIST_FILE_TYPE &&
- fileType <= LAST_MARKDOWNLIST_FILE_TYPE);
- }
-
- public static MediaFileType getFileType(String path) {
- int lastDot = path.lastIndexOf(".");
- if (lastDot < 0)
- return null;
- return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase());
- }
-
- public static boolean isVideoFileType(String path) {
- MediaFileType type = getFileType(path);
- if (null != type) {
- return isVideoFileType(type.fileType);
- }
- return false;
- }
-
- public static boolean isAudioFileType(String path) {
- MediaFileType type = getFileType(path);
- if (null != type) {
- return isAudioFileType(type.fileType);
- }
- return false;
- }
-
- public static boolean isImageFileType(String path) {
- MediaFileType type = getFileType(path);
- if (null != type) {
- return isImageFileType(type.fileType);
- }
- return false;
- }
-
- public static int getFileTypeForMimeType(String mimeType) {
- Integer value = sMimeTypeMap.get(mimeType);
- return (value == null ? 0 : value.intValue());
- }
-
- public static boolean isMdFileType(String path) {
- MediaFileType type = getFileType(path);
- if (null != type) {
- return isMarkDownFileType(type.fileType);
- }
- return false;
- }
-
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/HtmlParser.java b/app/src/main/java/com/loopeer/codereader/utils/HtmlParser.java
deleted file mode 100644
index 644f320..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/HtmlParser.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-import android.os.Build;
-
-import com.loopeer.codereader.R;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public class HtmlParser {
- public static String buildHtmlContent(Context context, String paramString1, String jsFile
- , String fileName) {
- for (; ; ) {
- try {
- InputStream inputStream = context.getAssets().open("code.html");
- Object localObject = new byte[inputStream.available()];
- inputStream.read((byte[]) localObject);
- inputStream.close();
- localObject = new String((byte[]) localObject);
- StringBuilder localStringBuilder = new StringBuilder();
- localStringBuilder.append("SyntaxHighlighter.defaults['auto-links'] = false;");
- localStringBuilder.append("SyntaxHighlighter.defaults['toolbar'] = false;");
- localStringBuilder.append("SyntaxHighlighter.defaults['wrap-lines'] = false;");
- localStringBuilder.append("SyntaxHighlighter.defaults['quick-code'] = false;");
- if (!PrefUtils.getPrefDisplayLineNumber(context)) {
- localStringBuilder.append("SyntaxHighlighter.defaults['gutter'] = false;");
- }
- localStringBuilder.append("SyntaxHighlighter.all();");
- String temp = "";
- if (Build.VERSION.SDK_INT < 14) {
- temp = "$('.syntaxhighlighter').css('overflow', 'visible !important');";
- }
- jsFile = ((String) localObject)
- .replace("!FONT_SIZE!"
- , String.format(""
- , new Object[]{Float.valueOf(PrefUtils.getPrefFontSize(context))}))
- .replace("!FILENAME!"
- , fileName)
- .replace("!BRUSHJSFILE!", jsFile)
- .replace("!SYNTAXHIGHLIGHTER!"
- , localStringBuilder.toString())
- .replace("!JS_FIX_HSCROLL!", temp);
- temp = "";
- return jsFile
- .replace("!STYLE_MENLO!", PrefUtils.getPrefMenlofont(context) ? temp : "")
- .replace("!THEME!", PrefUtils.getPrefTheme(context))
- .replace("!CODE!", paramString1)
-
- .replace("!WINDOW_BACK_GROUND_COLOR!"
- , ColorUtils.getColorString(context, R.color.code_read_background_color));
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
-
- }
- }
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/PageLinkParser.java b/app/src/main/java/com/loopeer/codereader/utils/PageLinkParser.java
deleted file mode 100644
index 0cd653c..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/PageLinkParser.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.text.TextUtils;
-
-import retrofit2.Response;
-
-public class PageLinkParser {
-
- private static final String SPLIT_LINKS = ",";
- private static final String SPLIT_LINK_PARAM = ";";
-
- private static final String REL_KEY = "rel";
-
- private static final String REL_VALUE_LAST = "last";
- private static final String REL_VALUE_NEXT = "next";
- private static final String REL_VALUE_FIRST = "first";
- private static final String REL_VALUE_PREV = "prev";
-
- private int first;
- private int last;
- private int next;
- private int prev;
-
- private int remain;
-
- public PageLinkParser(Response response) {
- remain = Integer.parseInt(response.headers().get("X-RateLimit-Remaining"));
-
- String linkHeader = response.headers().get("Link");
- if (TextUtils.isEmpty(linkHeader))
- return;
-
- String[] links = linkHeader.split(SPLIT_LINKS);
- for (String link : links) {
- String[] params = link.split(SPLIT_LINK_PARAM);
- if (params.length < 2)
- continue;
-
- String url = params[0].trim();
- if (!url.startsWith("<") || !url.endsWith(">"))
- continue;
- url = url.substring(1, url.length() - 1);
-
- for (int i = 1; i < params.length; i++) {
- String[] rel = params[i].trim().split("=");
- if (rel.length < 2 || !REL_KEY.equals(rel[0]))
- continue;
-
- String relValue = rel[1];
- if (relValue.startsWith("\"") && relValue.endsWith("\""))
- relValue = relValue.substring(1, relValue.length() - 1);
-
- if (REL_VALUE_FIRST.equals(relValue))
- first = getParam(url);
- else if (REL_VALUE_LAST.equals(relValue))
- last = getParam(url);
- else if (REL_VALUE_NEXT.equals(relValue))
- next = getParam(url);
- else if (REL_VALUE_PREV.equals(relValue))
- prev = getParam(url);
- }
- }
- }
-
- private int getParam(String url) {
- if (TextUtils.isEmpty(url))
- return 0;
- final String[] params = url.split("&");
- for (String param : params) {
- final String[] parts = param.split("=");
- if (parts.length != 2)
- continue;
- if (!"page".equals(parts[0]))
- continue;
- return Integer.parseInt(parts[1]);
- }
- return 0;
- }
-
- public int getFirst() {
- return first;
- }
-
- public int getLast() {
- return last;
- }
-
- public int getNext() {
- return next;
- }
-
- public int getPrev() {
- return prev;
- }
-
- public int getRemain() {
- return remain;
- }
-}
diff --git a/app/src/main/java/com/loopeer/codereader/utils/PrefUtils.java b/app/src/main/java/com/loopeer/codereader/utils/PrefUtils.java
deleted file mode 100644
index 50af070..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/PrefUtils.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-
-public class PrefUtils {
-
- public static final String PREF_FONT_SIZE = "pref_font_size";
- public static final String PREF_DISPLAY_LINE_NUMBER = "pref_display_line_number";
- public static final String PREF_MENLO_FONT = "pref_menlo_font";
- public static final String PREF_THEME = "pref_theme";
-
- public static float getPrefFontSize(final Context context) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- return sp.getFloat(PREF_FONT_SIZE, 12f);
- }
-
- public static void setPrefFontSize(final Context context, float size) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- sp.edit().putFloat(PREF_FONT_SIZE, size).commit();
- }
-
- public static String getPrefTheme(final Context context) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- return sp.getString(PREF_THEME, "Default");
- }
-
- public static void setPrefTheme(final Context context, String theme) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- sp.edit().putString(PREF_THEME, theme).commit();
- }
-
- public static boolean getPrefMenlofont(final Context context) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- return sp.getBoolean(PREF_MENLO_FONT, true);
- }
-
- public static void setPrefMenlofont(final Context context, boolean b) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- sp.edit().putBoolean(PREF_MENLO_FONT, b).commit();
- }
-
- public static boolean getPrefDisplayLineNumber(final Context context) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- return sp.getBoolean(PREF_DISPLAY_LINE_NUMBER, true);
- }
-
- public static void setPrefDisplayLineNumber(final Context context, boolean b) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- sp.edit().putBoolean(PREF_DISPLAY_LINE_NUMBER, b).commit();
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/loopeer/codereader/utils/RxBus.java b/app/src/main/java/com/loopeer/codereader/utils/RxBus.java
deleted file mode 100644
index e3b631a..0000000
--- a/app/src/main/java/com/loopeer/codereader/utils/RxBus.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.loopeer.codereader.utils;
-
-import rx.Observable;
-import rx.subjects.PublishSubject;
-import rx.subjects.SerializedSubject;
-import rx.subjects.Subject;
-
-public class RxBus {
-
- private static volatile RxBus mDefaultInstance;
-
- private RxBus() {
- }
-
- public static RxBus getInstance() {
- if (mDefaultInstance == null) {
- synchronized (RxBus.class) {
- if (mDefaultInstance == null) {
- mDefaultInstance = new RxBus();
- }
- }
- }
- return mDefaultInstance;
- }
-
- private final Subject