Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf3769959f | ||
|
|
10e853f968 | ||
|
|
ac6995be8d | ||
|
|
045d6f15a7 | ||
|
|
2d16f1cb57 | ||
|
|
ebe1d451b0 | ||
|
|
7faa4bea0d | ||
|
|
3785d3130c | ||
|
|
9daa1c27c4 | ||
|
|
67c722ed43 | ||
|
|
3c8f1809aa | ||
|
|
c5a3059e31 | ||
|
|
f305a59880 | ||
|
|
aa18e5f2f1 | ||
|
|
ac25b95eae | ||
|
|
a92fa304f1 | ||
|
|
2f3f3d6480 | ||
|
|
0d108393fc | ||
|
|
8d02f8c6a3 | ||
|
|
87d284ad97 | ||
|
|
c7ffdbec93 | ||
|
|
f9aad6ce9c | ||
|
|
7a64fd4c11 | ||
|
|
909af0cbed | ||
|
|
34db6fc79f | ||
|
|
b025f150c9 | ||
|
|
fea6b38c1e | ||
|
|
e2a03427f9 | ||
|
|
654cb5fdd5 | ||
|
|
333419b716 | ||
|
|
c66b1e4622 |
No files matched your search
@@ -43,17 +43,6 @@ Only Support Android S and above!
|
||||
|
||||

|
||||
|
||||
|
||||
# Build
|
||||
|
||||
本项目使用了 CMake 3.23.1 作为构建工具链之一,而当前版本的 Android Studio SDK Tool 无法满足本项目需求。
|
||||
|
||||
因此,在构建本项目前需要提前配置好 CMake >=3.23.1。
|
||||
|
||||
This Project use CMake 3.23.1, with is highter than Android Studio bundle CMake.
|
||||
|
||||
So you need to pre-install CMake>=3.23.1 before build.
|
||||
|
||||
# Thanks
|
||||
|
||||
本项目受到了诸多开源项目的帮助
|
||||
@@ -76,6 +65,7 @@ Here is the libraries
|
||||
- [TagSoup](http://home.ccil.org/~cowan/tagsoup/)
|
||||
- [libarchive](http://www.libarchive.org/)
|
||||
- [XZ Utils](https://tukaani.org/xz/)
|
||||
- [Zstd](http://www.zstd.net/)
|
||||
|
||||
|
||||
# License
|
||||
|
||||
+3
-9
@@ -38,8 +38,8 @@ android {
|
||||
applicationId "moe.tarsin.ehviewer"
|
||||
minSdkVersion 31
|
||||
targetSdkVersion 32
|
||||
versionCode 114525
|
||||
versionName "1.7.27.5"
|
||||
versionCode 114526
|
||||
versionName "1.7.27.6"
|
||||
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
|
||||
}
|
||||
|
||||
@@ -104,14 +104,13 @@ dependencies {
|
||||
implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha04'
|
||||
implementation 'androidx.browser:browser:1.4.0'
|
||||
implementation 'androidx.core:core:1.7.0'
|
||||
implementation 'androidx.dynamicanimation:dynamicanimation:1.1.0-alpha03'
|
||||
implementation 'androidx.fragment:fragment:1.4.1'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
|
||||
implementation 'androidx.webkit:webkit:1.4.0'
|
||||
implementation 'com.drakeet.drawer:drawer:1.0.3'
|
||||
implementation 'com.google.android.material:material:1.6.0'
|
||||
implementation 'com.google.android.material:material:1.7.0-alpha02'
|
||||
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
|
||||
implementation 'com.github.seven332:beerbelly:0.1.4'
|
||||
implementation 'com.github.seven332:glgallery:0.1.2'
|
||||
@@ -126,13 +125,8 @@ dependencies {
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3'
|
||||
implementation 'com.takisoft.preferencex:preferencex:1.1.0'
|
||||
implementation 'com.gitlab.NekoInverter:yorozuya:723dc867a9'
|
||||
implementation 'dev.rikka.rikkax.appcompat:appcompat:1.4.1'
|
||||
implementation 'dev.rikka.rikkax.core:core:1.4.0'
|
||||
implementation 'dev.rikka.rikkax.insets:insets:1.2.0'
|
||||
implementation 'dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0'
|
||||
implementation 'dev.rikka.rikkax.material:material:2.4.0'
|
||||
implementation 'dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.1'
|
||||
implementation 'dev.rikka.rikkax.preference:simplemenu-preference:1.0.3'
|
||||
implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1'
|
||||
implementation 'org.greenrobot:greendao:3.3.0'
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28"
|
||||
tools:ignore="ScopedStorage" />
|
||||
android:maxSdkVersion="28" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
@@ -41,8 +39,7 @@
|
||||
android:largeHeap="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="UnusedAttribute">
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.MainActivity"
|
||||
|
||||
@@ -65,7 +65,7 @@ import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||
import com.google.android.material.materialswitch.MaterialSwitch;
|
||||
import com.hippo.ehviewer.AppConfig;
|
||||
import com.hippo.ehviewer.BuildConfig;
|
||||
import com.hippo.ehviewer.R;
|
||||
@@ -1047,15 +1047,15 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
private final Spinner mScaleMode;
|
||||
private final Spinner mStartPosition;
|
||||
private final Spinner mReadTheme;
|
||||
private final SwitchMaterial mKeepScreenOn;
|
||||
private final SwitchMaterial mShowClock;
|
||||
private final SwitchMaterial mShowProgress;
|
||||
private final SwitchMaterial mShowBattery;
|
||||
private final SwitchMaterial mShowPageInterval;
|
||||
private final SwitchMaterial mVolumePage;
|
||||
private final SwitchMaterial mReverseVolumePage;
|
||||
private final SwitchMaterial mReadingFullscreen;
|
||||
private final SwitchMaterial mCustomScreenLightness;
|
||||
private final MaterialSwitch mKeepScreenOn;
|
||||
private final MaterialSwitch mShowClock;
|
||||
private final MaterialSwitch mShowProgress;
|
||||
private final MaterialSwitch mShowBattery;
|
||||
private final MaterialSwitch mShowPageInterval;
|
||||
private final MaterialSwitch mVolumePage;
|
||||
private final MaterialSwitch mReverseVolumePage;
|
||||
private final MaterialSwitch mReadingFullscreen;
|
||||
private final MaterialSwitch mCustomScreenLightness;
|
||||
private final SeekBar mScreenLightness;
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
|
||||
@@ -12,7 +12,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.hippo.ehviewer.ui.SettingsActivity;
|
||||
import com.takisoft.preferencex.PreferenceFragmentCompat;
|
||||
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public class BasePreferenceFragment extends PreferenceFragmentCompat
|
||||
implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
|
||||
@@ -53,11 +52,4 @@ public class BasePreferenceFragment extends PreferenceFragmentCompat
|
||||
public void showTip(CharSequence message, int length) {
|
||||
((SettingsActivity) requireActivity()).showTip(message, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
|
||||
RecyclerView recyclerView = super.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
RecyclerViewKt.fixEdgeEffect(recyclerView, false, true);
|
||||
return recyclerView;
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
public class DownloadsScene extends ToolbarScene
|
||||
@@ -378,8 +377,6 @@ public class DownloadsScene extends ToolbarScene
|
||||
mRecyclerView.scrollToPosition(mInitPosition);
|
||||
mInitPosition = -1;
|
||||
}
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4, 4, 4, 4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
|
||||
mFastScroller.attachToRecyclerView(mRecyclerView);
|
||||
HandlerDrawable handlerDrawable = new HandlerDrawable();
|
||||
|
||||
@@ -94,7 +94,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public final class GalleryCommentsScene extends ToolbarScene
|
||||
implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener {
|
||||
@@ -176,7 +175,6 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.scene_gallery_comments, container, false);
|
||||
mRecyclerView = (EasyRecyclerView) ViewUtils.$$(view, R.id.recycler_view);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
TextView tip = (TextView) ViewUtils.$$(view, R.id.tip);
|
||||
mEditPanel = ViewUtils.$$(view, R.id.edit_panel);
|
||||
mSendImage = (ImageView) ViewUtils.$$(mEditPanel, R.id.send);
|
||||
@@ -223,7 +221,6 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
if (itemAnimator instanceof DefaultItemAnimator) {
|
||||
((DefaultItemAnimator) itemAnimator).setSupportsChangeAnimations(false);
|
||||
}
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 0, 0, 0, 80, TypedValue.COMPLEX_UNIT_DIP);
|
||||
|
||||
mSendImage.setOnClickListener(this);
|
||||
mFab.setOnClickListener(this);
|
||||
|
||||
@@ -44,7 +44,6 @@ import com.hippo.yorozuya.ViewUtils;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public final class GalleryInfoScene extends ToolbarScene {
|
||||
|
||||
@@ -174,7 +173,6 @@ public final class GalleryInfoScene extends ToolbarScene {
|
||||
mRecyclerView.addItemDecoration(decoration);
|
||||
mRecyclerView.setClipToPadding(false);
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public class HistoryScene extends ToolbarScene {
|
||||
|
||||
/*---------------
|
||||
@@ -232,8 +230,6 @@ public class HistoryScene extends ToolbarScene {
|
||||
mRecyclerView.addItemDecoration(decoration);
|
||||
guardManager.attachRecyclerView(mRecyclerView);
|
||||
swipeManager.attachRecyclerView(mRecyclerView);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4, 4, 4, 4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
|
||||
mFastScroller.attachToRecyclerView(mRecyclerView);
|
||||
HandlerDrawable handlerDrawable = new HandlerDrawable();
|
||||
|
||||
@@ -56,8 +56,6 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public class ContentLayout extends FrameLayout {
|
||||
|
||||
private CircularProgressIndicator mProgressView;
|
||||
@@ -124,9 +122,6 @@ public class ContentLayout extends FrameLayout {
|
||||
resources.getColor(R.color.loading_indicator_orange));
|
||||
mBottomProgress.setIndeterminateAnimationType(LinearProgressIndicator.INDETERMINATE_ANIMATION_TYPE_CONTIGUOUS);
|
||||
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4, 4, 4, 4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
|
||||
mRecyclerViewOriginBottom = mRecyclerView.getPaddingBottom();
|
||||
mFastScrollerOriginBottom = mFastScroller.getPaddingBottom();
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* 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.hippo.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
|
||||
public class MaxSizeContainer extends ViewGroup {
|
||||
|
||||
private int mMaxWidth;
|
||||
private int mMaxHeight;
|
||||
|
||||
public MaxSizeContainer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
public MaxSizeContainer(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MaxSizeContainer);
|
||||
mMaxWidth = a.getDimensionPixelOffset(R.styleable.MaxSizeContainer_maxWidth, -1);
|
||||
mMaxHeight = a.getDimensionPixelOffset(R.styleable.MaxSizeContainer_maxHeight, -1);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
private int getMeasureSpec(int measureSpec, int max) {
|
||||
if (max < 0) {
|
||||
return measureSpec;
|
||||
}
|
||||
|
||||
int size = MeasureSpec.getSize(measureSpec);
|
||||
int mode = MeasureSpec.getMode(measureSpec);
|
||||
|
||||
switch (mode) {
|
||||
case MeasureSpec.AT_MOST:
|
||||
size = Math.min(size, max);
|
||||
break;
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
size = max;
|
||||
mode = MeasureSpec.AT_MOST;
|
||||
break;
|
||||
}
|
||||
return MeasureSpec.makeMeasureSpec(size, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
AssertUtils.assertEquals("getChildCount() must be 1", 1, getChildCount());
|
||||
|
||||
View child = getChildAt(0);
|
||||
if (child.getVisibility() != GONE) {
|
||||
child.measure(getMeasureSpec(widthMeasureSpec, mMaxWidth),
|
||||
getMeasureSpec(heightMeasureSpec, mMaxHeight));
|
||||
setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
|
||||
} else {
|
||||
setMeasuredDimension(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
AssertUtils.assertEquals("getChildCount() must be 1", 1, getChildCount());
|
||||
|
||||
View child = getChildAt(0);
|
||||
if (child.getVisibility() != GONE) {
|
||||
child.layout(0, 0, r - l, b - t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
|
||||
|
||||
public final class AnimationUtils {
|
||||
private AnimationUtils() {
|
||||
}
|
||||
|
||||
public static final Interpolator FAST_SLOW_INTERPOLATOR = new LinearOutSlowInInterpolator();
|
||||
public static final Interpolator SLOW_FAST_INTERPOLATOR = new FastOutLinearInInterpolator();
|
||||
public static final Interpolator SLOW_FAST_SLOW_INTERPOLATOR = new FastOutSlowInInterpolator();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public class AssertError extends Error {
|
||||
|
||||
public AssertError(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public class AssertException extends Exception {
|
||||
|
||||
public AssertException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public final class AssertUtils {
|
||||
private AssertUtils() {}
|
||||
|
||||
public static void assertTrue(boolean cond) {
|
||||
assertTrue("Condition has to be true.", cond);
|
||||
}
|
||||
|
||||
public static void assertTrueEx(boolean cond) throws AssertException {
|
||||
assertTrueEx("Condition has to be true.", cond);
|
||||
}
|
||||
|
||||
public static void assertTrue(String message, boolean cond) {
|
||||
if (!cond) {
|
||||
throw new AssertError(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertTrueEx(String message, boolean cond) throws AssertException {
|
||||
if (!cond) {
|
||||
throw new AssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertNull(Object object) {
|
||||
assertNull("Should be null", object);
|
||||
}
|
||||
|
||||
public static void assertNullEx(Object object) throws AssertException {
|
||||
assertNullEx("Should be null", object);
|
||||
}
|
||||
|
||||
public static void assertNull(String message, Object object) {
|
||||
if (object != null) {
|
||||
throw new AssertError(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertNullEx(String message, Object object) throws AssertException {
|
||||
if (object != null) {
|
||||
throw new AssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertNotNull(Object object) {
|
||||
assertNotNull("Should not be null", object);
|
||||
}
|
||||
|
||||
public static void assertNotNullEx(Object object) throws AssertException {
|
||||
assertNotNullEx("Should not be null", object);
|
||||
}
|
||||
|
||||
public static void assertNotNull(String message, Object object) {
|
||||
if (object == null) {
|
||||
throw new AssertError(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertNotNullEx(String message, Object object) throws AssertException {
|
||||
if (object == null) {
|
||||
throw new AssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertEquals(int expected, int actual) {
|
||||
assertEquals("Should be " + expected + ", but it is " + actual, expected, actual);
|
||||
}
|
||||
|
||||
public static void assertEqualsEx(int expected, int actual) throws AssertException {
|
||||
assertEqualsEx("Should be " + expected + ", but it is " + actual, expected, actual);
|
||||
}
|
||||
|
||||
public static void assertEquals(String message, int expected, int actual) {
|
||||
if (expected != actual) {
|
||||
throw new AssertError(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertEqualsEx(String message, int expected, int actual) throws AssertException {
|
||||
if (expected != actual) {
|
||||
throw new AssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertInstanceOf(Object obj, Class clazz) {
|
||||
assertInstanceOf("The object should be instance of " + clazz.getName(), obj, clazz);
|
||||
}
|
||||
|
||||
public static void assertInstanceOfEx(Object obj, Class clazz) throws AssertException {
|
||||
assertInstanceOfEx("The object should be instance of " + clazz.getName(), obj, clazz);
|
||||
}
|
||||
|
||||
public static void assertInstanceOf(String message, Object obj, Class clazz) {
|
||||
if (!clazz.isInstance(obj)) {
|
||||
throw new AssertError(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertInstanceOfEx(String message, Object obj, Class clazz) throws AssertException {
|
||||
if (!clazz.isInstance(obj)) {
|
||||
throw new AssertException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public final class ColorUtils {
|
||||
private ColorUtils() {}
|
||||
|
||||
/**
|
||||
* Check is it the color opaque
|
||||
*
|
||||
* @param color the color
|
||||
* @return true if it is opaque
|
||||
*/
|
||||
public static boolean isOpaque(int color) {
|
||||
return color >>> 24 == 0xFF;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public class ConcurrentPool<T> {
|
||||
|
||||
private final T[] mArray;
|
||||
private final int mMaxSize;
|
||||
private int mSize;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ConcurrentPool(int size) {
|
||||
if (size <= 0) {
|
||||
throw new IllegalStateException("Pool size must > 0, it is " + size);
|
||||
}
|
||||
mArray = (T[]) new Object[size];
|
||||
mMaxSize = size;
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
public synchronized void push(T t) {
|
||||
if (t != null && mSize < mMaxSize) {
|
||||
mArray[mSize++] = t;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized T pop() {
|
||||
if (mSize > 0) {
|
||||
T t = mArray[--mSize];
|
||||
mArray[mSize] = null;
|
||||
return t;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class FileUtils {
|
||||
private FileUtils() {}
|
||||
|
||||
public static boolean ensureFile(File file) {
|
||||
return file != null && (!file.exists() || file.isFile());
|
||||
}
|
||||
|
||||
public static boolean ensureDirectory(File file) {
|
||||
if (file != null) {
|
||||
if (file.exists()) {
|
||||
return file.isDirectory();
|
||||
} else {
|
||||
return file.mkdirs();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert byte to human readable string.<br/>
|
||||
* http://stackoverflow.com/questions/3758606/
|
||||
*
|
||||
* @param bytes the bytes to convert
|
||||
* @param si si units
|
||||
* @return the human readable string
|
||||
*/
|
||||
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(Locale.US, "%.1f %sB", bytes / Math.pow(unit, exp), pre);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to delete file, dir and it's children
|
||||
*
|
||||
* @param file the file to delete
|
||||
* The dir to deleted
|
||||
*/
|
||||
public static boolean delete(File file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
boolean success = true;
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
success &= delete(f);
|
||||
}
|
||||
}
|
||||
/*
|
||||
final File to = new File(file.getAbsolutePath()
|
||||
+ System.currentTimeMillis());
|
||||
if (file.renameTo(to)) {
|
||||
success &= to.delete();
|
||||
} else
|
||||
success &= file.delete();
|
||||
}
|
||||
*/
|
||||
success &= file.delete();
|
||||
return success;
|
||||
}
|
||||
|
||||
public static boolean deleteContent(File file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean success = true;
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
success &= delete(f);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code null} for get exception
|
||||
*/
|
||||
@Nullable
|
||||
public static String read(File file) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(file);
|
||||
return IOUtils.readString(is, "utf-8");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean write(File file, String str) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
if (str == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = new FileOutputStream(file);
|
||||
os.write(str.getBytes("utf-8"));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
|
||||
private static final char[] FORBIDDEN_FILENAME_CHARACTERS = {
|
||||
'\\',
|
||||
'/',
|
||||
':',
|
||||
'*',
|
||||
'?',
|
||||
'"',
|
||||
'<',
|
||||
'>',
|
||||
'|',
|
||||
};
|
||||
|
||||
public static String sanitizeFilename(@NonNull String filename) {
|
||||
// Remove forbidden_filename_characters
|
||||
filename = StringUtils.remove(filename, FORBIDDEN_FILENAME_CHARACTERS);
|
||||
|
||||
// Ensure utf-8 byte count <= 255
|
||||
int byteCount = 0;
|
||||
int length = 0;
|
||||
for (int len = filename.length(); length < len; length++) {
|
||||
char ch = filename.charAt(length);
|
||||
if (ch <= 0x7F) {
|
||||
byteCount++;
|
||||
} else if (ch <= 0x7FF) {
|
||||
byteCount += 2;
|
||||
} else if (Character.isHighSurrogate(ch)) {
|
||||
byteCount += 4;
|
||||
++length;
|
||||
} else {
|
||||
byteCount += 3;
|
||||
}
|
||||
// Meet max byte count
|
||||
if (byteCount > 255) {
|
||||
filename = filename.substring(0, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Trim
|
||||
return StringUtils.trim(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extension from filename
|
||||
*
|
||||
* @param filename the complete filename
|
||||
* @return null for can't find extension, "" empty String for ending with . dot
|
||||
*/
|
||||
public static String getExtensionFromFilename(@Nullable String filename) {
|
||||
if (null == filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = filename.lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
return filename.substring(index + 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name from filename
|
||||
*
|
||||
* @param filename the complete filename
|
||||
* @return null for start with . dot
|
||||
*/
|
||||
public static String getNameFromFilename(@Nullable String filename) {
|
||||
if (null == filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = filename.lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
String name = filename.substring(0, index);
|
||||
return TextUtils.isEmpty(name) ? null : name;
|
||||
} else {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temp file, you need to delete it by you self.
|
||||
*
|
||||
* @param parent The temp file's parent
|
||||
* @param extension The extension of temp file
|
||||
* @return The temp file or null
|
||||
*/
|
||||
@Nullable
|
||||
public static File createTempFile(@Nullable File parent, @Nullable String extension) {
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String filename = Long.toString(now + i);
|
||||
if (extension != null) {
|
||||
filename = filename + '.' + extension;
|
||||
}
|
||||
File tempFile = new File(parent, filename);
|
||||
if (!tempFile.exists()) {
|
||||
return tempFile;
|
||||
}
|
||||
}
|
||||
|
||||
// Unbelievable
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temp dir, you need to delete it by you self.
|
||||
*
|
||||
* @param parent The temp file's parent
|
||||
* @return The temp dir or null
|
||||
*/
|
||||
@Nullable
|
||||
public static File createTempDir(@Nullable File parent) {
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String filename = Long.toString(now + i);
|
||||
File tempFile = new File(parent, filename);
|
||||
if (!tempFile.exists() && tempFile.mkdirs()) {
|
||||
return tempFile;
|
||||
}
|
||||
}
|
||||
|
||||
// Unbelievable
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only support file now
|
||||
*/
|
||||
public static boolean rename(@NonNull File from, @NonNull File to) {
|
||||
if (!from.isFile() || to.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ok = from.renameTo(to);
|
||||
if (ok && !from.exists() && to.isFile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy content
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
is = new FileInputStream(from);
|
||||
os = new FileOutputStream(to);
|
||||
IOUtils.copy(is, os);
|
||||
ok = true;
|
||||
} catch (IOException e) {
|
||||
IOUtils.closeQuietly(is);
|
||||
IOUtils.closeQuietly(os);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
to.delete();
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete old one
|
||||
from.delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public final class IOUtils {
|
||||
private IOUtils() {}
|
||||
|
||||
private static final int EOF = -1;
|
||||
|
||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
||||
|
||||
/**
|
||||
* Close the closeable stuff. Don't worry about anything.
|
||||
*
|
||||
* @param is the closeable stuff
|
||||
*/
|
||||
public static void closeQuietly(Closeable is) {
|
||||
try {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from an <code>InputStream</code> to an
|
||||
* <code>OutputStream</code>.
|
||||
*
|
||||
* @param input the InputStream
|
||||
* @param output the OutputStream
|
||||
* @return the number of bytes copied
|
||||
* @throws IOException
|
||||
*/
|
||||
public static long copy(InputStream input, OutputStream output)
|
||||
throws IOException {
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
||||
long count = 0;
|
||||
int n;
|
||||
while (EOF != (n = input.read(buffer))) {
|
||||
output.write(buffer, 0, n);
|
||||
count += n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ASCII characters up to but not including the next "\r\n", or
|
||||
* "\n".
|
||||
*
|
||||
* @throws java.io.EOFException if the stream is exhausted before the next
|
||||
* newline character.
|
||||
*/
|
||||
public static String readAsciiLine(final InputStream in) throws IOException {
|
||||
final StringBuilder result = new StringBuilder(80);
|
||||
while (true) {
|
||||
final int c = in.read();
|
||||
if (c == -1) {
|
||||
throw new EOFException();
|
||||
} else if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
|
||||
result.append((char)c);
|
||||
}
|
||||
final int length = result.length();
|
||||
if (length > 0 && result.charAt(length - 1) == '\r') {
|
||||
result.setLength(length - 1);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String readString(final InputStream is, String encoding) throws IOException {
|
||||
InputStreamReader reader = new InputStreamReader(is, encoding);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
|
||||
int n;
|
||||
while (EOF != (n = reader.read(buffer))) {
|
||||
sb.append(buffer, 0, n);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static byte[] getAllByte(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
copy(is, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public final class IntIdGenerator {
|
||||
|
||||
public static final int INVALID_ID = -1;
|
||||
|
||||
private final AtomicInteger mId = new AtomicInteger();
|
||||
|
||||
public IntIdGenerator() {}
|
||||
|
||||
public IntIdGenerator(int init) {
|
||||
setNextId(init);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
public int nextId() {
|
||||
int id;
|
||||
while ((id = mId.getAndIncrement()) == INVALID_ID);
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setNextId(int id) {
|
||||
checkInValidId(id);
|
||||
mId.set(id);
|
||||
}
|
||||
|
||||
private void checkInValidId(int id) {
|
||||
if (INVALID_ID == id) {
|
||||
throw new IllegalStateException("Can't set INVALID_ID");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public final class LayoutUtils {
|
||||
private LayoutUtils() {}
|
||||
|
||||
/**
|
||||
* dp conversion to pix
|
||||
*
|
||||
* @param context The context
|
||||
* @param dp The value you want to conversion
|
||||
* @return value in pix
|
||||
*/
|
||||
public static int dp2pix(Context context, float dp) {
|
||||
return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* pix conversion to dp
|
||||
*
|
||||
* @param context The context
|
||||
* @param pix The value you want to conversion
|
||||
* @return value in dp
|
||||
*/
|
||||
public static float pix2dp(Context context, int pix) {
|
||||
return pix / context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
/**
|
||||
* sp conversion to pix
|
||||
*
|
||||
* @param sp The value you want to conversion
|
||||
* @return value in pix
|
||||
*/
|
||||
public static int sp2pix(Context context, float sp) {
|
||||
return (int) (sp * context.getResources().getDisplayMetrics().scaledDensity + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* pix conversion to sp
|
||||
*
|
||||
* @param pix The value you want to conversion
|
||||
* @return value in sp
|
||||
*/
|
||||
public static float pix2sp(Context context, float pix) {
|
||||
return pix / context.getResources().getDisplayMetrics().scaledDensity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public final class LongIdGenerator {
|
||||
|
||||
public static final long INVALID_ID = -1L;
|
||||
|
||||
private final AtomicLong mId = new AtomicLong();
|
||||
|
||||
public LongIdGenerator() {}
|
||||
|
||||
public LongIdGenerator(long init) {
|
||||
setNextId(init);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
public long nextId() {
|
||||
long id;
|
||||
while ((id = mId.getAndIncrement()) == INVALID_ID);
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setNextId(long id) {
|
||||
checkInValidId(id);
|
||||
mId.set(id);
|
||||
}
|
||||
|
||||
private void checkInValidId(long id) {
|
||||
if (INVALID_ID == id) {
|
||||
throw new IllegalStateException("Can't set INVALID_ID");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
// Get most code from android.util.MathUtils
|
||||
public final class MathUtils {
|
||||
private MathUtils() {}
|
||||
|
||||
private static final Random sRandom = new Random();
|
||||
private static final float DEG_TO_RAD = 3.1415926f / 180.0f;
|
||||
private static final float RAD_TO_DEG = 180.0f / 3.1415926f;
|
||||
|
||||
public static float abs(float v) {
|
||||
return v > 0 ? v : -v;
|
||||
}
|
||||
|
||||
public static float log(float a) {
|
||||
return (float) Math.log(a);
|
||||
}
|
||||
|
||||
public static float exp(float a) {
|
||||
return (float) Math.exp(a);
|
||||
}
|
||||
|
||||
public static float pow(float a, float b) {
|
||||
return (float) Math.pow(a, b);
|
||||
}
|
||||
|
||||
public static float max(float a, float b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
public static float max(int a, int b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
public static float max(float a, float b, float c) {
|
||||
return a > b ? (a > c ? a : c) : (b > c ? b : c);
|
||||
}
|
||||
|
||||
public static float max(int a, int b, int c) {
|
||||
return a > b ? (a > c ? a : c) : (b > c ? b : c);
|
||||
}
|
||||
|
||||
public static float max(float... arg) {
|
||||
int length = arg.length;
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Empty argument");
|
||||
} else {
|
||||
float n = arg[0];
|
||||
float m;
|
||||
for (int i = 1; i < length; i++) {
|
||||
m = arg[i];
|
||||
if (m > n)
|
||||
n = m;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static int max(int... arg) {
|
||||
int length = arg.length;
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Empty argument");
|
||||
} else {
|
||||
int n = arg[0];
|
||||
int m;
|
||||
for (int i = 1; i < length; i++) {
|
||||
m = arg[i];
|
||||
if (m > n)
|
||||
n = m;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static float min(float a, float b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
public static float min(int a, int b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
public static float min(float a, float b, float c) {
|
||||
return a < b ? (a < c ? a : c) : (b < c ? b : c);
|
||||
}
|
||||
|
||||
public static float min(int a, int b, int c) {
|
||||
return a < b ? (a < c ? a : c) : (b < c ? b : c);
|
||||
}
|
||||
|
||||
public static float min(float... args) {
|
||||
int length = args.length;
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Empty argument");
|
||||
} else {
|
||||
float n = args[0];
|
||||
float m;
|
||||
for (int i = 1; i < length; i++) {
|
||||
m = args[i];
|
||||
if (m < n)
|
||||
n = m;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static int min(int... args) {
|
||||
int length = args.length;
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Empty argument");
|
||||
} else {
|
||||
int n = args[0];
|
||||
int m;
|
||||
for (int i = 1; i < length; i++) {
|
||||
m = args[i];
|
||||
if (m < n)
|
||||
n = m;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static float dist(float x1, float y1, float x2, float y2) {
|
||||
final float x = (x2 - x1);
|
||||
final float y = (y2 - y1);
|
||||
return (float) Math.hypot(x, y);
|
||||
}
|
||||
|
||||
public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||
final float x = (x2 - x1);
|
||||
final float y = (y2 - y1);
|
||||
final float z = (z2 - z1);
|
||||
return (float) Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
public static boolean near(float x1, float y1, float x2, float y2, float slop) {
|
||||
return dist(x1, y1, x2, y2) < slop;
|
||||
}
|
||||
|
||||
public static boolean near(float x1, float y1, float z1, float x2, float y2, float z2, float slop) {
|
||||
return dist(x1, y1, z1, x2, y2, z2) < slop;
|
||||
}
|
||||
|
||||
public static float mag(float a, float b) {
|
||||
return (float) Math.hypot(a, b);
|
||||
}
|
||||
|
||||
public static float mag(float a, float b, float c) {
|
||||
return (float) Math.sqrt(a * a + b * b + c * c);
|
||||
}
|
||||
|
||||
public static float sq(float v) {
|
||||
return v * v;
|
||||
}
|
||||
|
||||
public static float cross(float v1x, float v1y, float v2x, float v2y) {
|
||||
return v1x * v2y - v1y * v2x;
|
||||
}
|
||||
|
||||
public static float radians(float degrees) {
|
||||
return degrees * DEG_TO_RAD;
|
||||
}
|
||||
|
||||
public static float degrees(float radians) {
|
||||
return radians * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
public static float acos(float value) {
|
||||
return (float) Math.acos(value);
|
||||
}
|
||||
|
||||
public static float asin(float value) {
|
||||
return (float) Math.asin(value);
|
||||
}
|
||||
|
||||
public static float atan(float value) {
|
||||
return (float) Math.atan(value);
|
||||
}
|
||||
|
||||
public static float atan2(float a, float b) {
|
||||
return (float) Math.atan2(a, b);
|
||||
}
|
||||
|
||||
public static float tan(float angle) {
|
||||
return (float) Math.tan(angle);
|
||||
}
|
||||
|
||||
public static int lerp(int start, int stop, float amount) {
|
||||
return start + (int) ((stop - start) * amount);
|
||||
}
|
||||
|
||||
public static float lerp(float start, float stop, float amount) {
|
||||
return start + (stop - start) * amount;
|
||||
}
|
||||
|
||||
public static float delerp(int start, int stop, int value) {
|
||||
if (stop == start) {
|
||||
return 1.0f;
|
||||
} else {
|
||||
return (float) (value - start) / (float) (stop - start);
|
||||
}
|
||||
}
|
||||
|
||||
public static float delerp(float start, float stop, float value) {
|
||||
if (stop == start) {
|
||||
return 1.0f;
|
||||
} else {
|
||||
return (value - start) / (stop - start);
|
||||
}
|
||||
}
|
||||
|
||||
public static float norm(float start, float stop, float value) {
|
||||
return (value - start) / (stop - start);
|
||||
}
|
||||
|
||||
public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) {
|
||||
return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input value x clamped to the range [min, max].
|
||||
*/
|
||||
public static int clamp(int x, int min, int max) {
|
||||
if (x > max) return max;
|
||||
if (x < min) return min;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input value x clamped to the range [min, max].
|
||||
*/
|
||||
public static float clamp(float x, float min, float max) {
|
||||
if (x > max) return max;
|
||||
if (x < min) return min;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input value x clamped to the range [min, max].
|
||||
*/
|
||||
public static long clamp(long x, long min, long max) {
|
||||
if (x > max) return max;
|
||||
if (x < min) return min;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next power of two.
|
||||
* Returns the input if it is already power of 2.
|
||||
* Throws IllegalArgumentException if the input is <= 0 or
|
||||
* the answer overflows.
|
||||
*/
|
||||
public static int nextPowerOf2(int n) {
|
||||
if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n);
|
||||
n -= 1;
|
||||
n |= n >> 16;
|
||||
n |= n >> 8;
|
||||
n |= n >> 4;
|
||||
n |= n >> 2;
|
||||
n |= n >> 1;
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the previous power of two.
|
||||
* Returns the input if it is already power of 2.
|
||||
* Throws IllegalArgumentException if the input is <= 0 or
|
||||
* the answer overflows.
|
||||
*/
|
||||
public static int previousPowerOf2 (int n) {
|
||||
if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n);
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
|
||||
public static int hammingWeight(int n) {
|
||||
n = n - ((n >>> 1) & 0x55555555);
|
||||
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
|
||||
return (((n + (n >>> 4)) & 0x0F0F0F0F) * 0x01010101) >>> 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* divide and ceil
|
||||
*/
|
||||
public static int ceilDivide(int a, int b) {
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
/**
|
||||
* divide and ceil
|
||||
*/
|
||||
public static long ceilDivide(long a, long b) {
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coverage radius of a area
|
||||
*
|
||||
* @param w the width of the area
|
||||
* @param h the height of the area
|
||||
* @param x the x of point in area
|
||||
* @param y the y of point in area
|
||||
* @return the radius
|
||||
*/
|
||||
public static float coverageRadius(float w, float h, float x, float y) {
|
||||
float x2;
|
||||
float y2;
|
||||
if (x > w / 2) {
|
||||
x2 = 0;
|
||||
} else {
|
||||
x2 = w;
|
||||
}
|
||||
if (y > h / 2) {
|
||||
y2 = 0;
|
||||
} else {
|
||||
y2 = h;
|
||||
}
|
||||
return dist(x, y, x2, y2);
|
||||
}
|
||||
|
||||
public static float positiveModulo(float x, float y) {
|
||||
float result = x % y;
|
||||
if (x < 0) {
|
||||
result += y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float negativeModulo(float x, float y) {
|
||||
float result = x % y;
|
||||
if (x > 0) {
|
||||
result -= y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* [0, howbig)
|
||||
*/
|
||||
public static int random(int howbig) {
|
||||
return (int) (sRandom.nextFloat() * howbig);
|
||||
}
|
||||
|
||||
/**
|
||||
* [howsmall, howbig)
|
||||
*/
|
||||
public static int random(int howsmall, int howbig) {
|
||||
if (howsmall >= howbig)
|
||||
return howsmall;
|
||||
return lerp(howsmall, howbig, sRandom.nextFloat());
|
||||
}
|
||||
|
||||
/**
|
||||
* [0, howbig)
|
||||
*/
|
||||
public static float random(float howbig) {
|
||||
return sRandom.nextFloat() * howbig;
|
||||
}
|
||||
|
||||
/**
|
||||
* [howsmall, howbig)
|
||||
*/
|
||||
public static float random(float howsmall, float howbig) {
|
||||
if (howsmall >= howbig)
|
||||
return howsmall;
|
||||
return lerp(howsmall, howbig, sRandom.nextFloat());
|
||||
}
|
||||
|
||||
public static void randomSeed(long seed) {
|
||||
sRandom.setSeed(seed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public final class Messenger {
|
||||
|
||||
private final IntIdGenerator mIdGenerator;
|
||||
private final SparseArray<List<Receiver>> mReceiverListMap;
|
||||
|
||||
private static Messenger sInstance;
|
||||
|
||||
public static Messenger getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new Messenger();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private Messenger() {
|
||||
mIdGenerator = new IntIdGenerator();
|
||||
mReceiverListMap = new SparseArray<>();
|
||||
}
|
||||
|
||||
public int newId() {
|
||||
return mIdGenerator.nextId();
|
||||
}
|
||||
|
||||
private void notifyInternal(int id, Object obj) {
|
||||
List<Receiver> receiverList = mReceiverListMap.get(id);
|
||||
if (receiverList != null) {
|
||||
List<Receiver> temp = new LinkedList<>(receiverList);
|
||||
for (Receiver r : temp) {
|
||||
r.onReceive(id, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void notify(final int id, final Object obj) {
|
||||
// Make sure do it in UI thread
|
||||
SimpleHandler.getInstance().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
notifyInternal(id, obj);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyAtOnce(int id, Object obj) {
|
||||
notifyInternal(id, obj);
|
||||
}
|
||||
|
||||
public void register(int id, Receiver receiver) {
|
||||
List<Receiver> receiverList = mReceiverListMap.get(id);
|
||||
if (receiverList == null) {
|
||||
receiverList = new ArrayList<>();
|
||||
mReceiverListMap.put(id, receiverList);
|
||||
}
|
||||
|
||||
receiverList.add(receiver);
|
||||
}
|
||||
|
||||
public void unregister(int id, Receiver receiver) {
|
||||
List<Receiver> receiverList = mReceiverListMap.get(id);
|
||||
if (receiverList != null) {
|
||||
receiverList.remove(receiver);
|
||||
if (receiverList.isEmpty()) {
|
||||
mReceiverListMap.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Receiver {
|
||||
void onReceive(final int id, final Object obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public final class NumberUtils {
|
||||
private NumberUtils() {}
|
||||
|
||||
/**
|
||||
* 0 for false, Non 0 for true
|
||||
*
|
||||
* @param integer the int
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean int2boolean(int integer) {
|
||||
return integer != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* false for 0, true for 1
|
||||
*
|
||||
* @param bool the boolean
|
||||
* @return the int
|
||||
*/
|
||||
public static int boolean2int(boolean bool) {
|
||||
return bool ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not throw NumberFormatException, use default value
|
||||
*
|
||||
* @param str the string to be parsed
|
||||
* @param defaultValue the value to return when get error
|
||||
* @return the value of the string
|
||||
*/
|
||||
public static int parseIntSafely(String str, int defaultValue) {
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
} catch (Throwable e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not throw NumberFormatException, use default value
|
||||
*
|
||||
* @param str the string to be parsed
|
||||
* @param defaultValue the value to return when get error
|
||||
* @return the value of the string
|
||||
*/
|
||||
public static long parseLongSafely(String str, long defaultValue) {
|
||||
try {
|
||||
return Long.parseLong(str);
|
||||
} catch (Throwable e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not throw NumberFormatException, use default value
|
||||
*
|
||||
* @param str the string to be parsed
|
||||
* @param defaultValue the value to return when get error
|
||||
* @return the value of the string
|
||||
*/
|
||||
public static float parseFloatSafely(String str, float defaultValue) {
|
||||
try {
|
||||
return Float.parseFloat(str);
|
||||
} catch (Throwable e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.os.Looper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class OSUtils {
|
||||
private OSUtils() {}
|
||||
|
||||
private static final String PROCFS_MEMFILE = "/proc/meminfo";
|
||||
private static final Pattern PROCFS_MEMFILE_FORMAT =
|
||||
Pattern.compile("^([a-zA-Z]*):[ \t]*([0-9]*)[ \t]kB");
|
||||
private static final String MEMTOTAL_STRING = "MemTotal";
|
||||
|
||||
private static long sTotalMem = Long.MIN_VALUE;
|
||||
|
||||
public static void checkMainLoop() {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
throw new IllegalStateException("It is in not main loop!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get application allocated memory size
|
||||
*/
|
||||
public static long getAppAllocatedMemory() {
|
||||
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get application max memory size
|
||||
*/
|
||||
public static long getAppMaxMemory() {
|
||||
return Runtime.getRuntime().maxMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device RAM size
|
||||
*/
|
||||
public static long getTotalMemory() {
|
||||
if (sTotalMem == Long.MIN_VALUE) {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(PROCFS_MEMFILE), 64);
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
Matcher matcher = PROCFS_MEMFILE_FORMAT.matcher(line);
|
||||
if (matcher.find() && MEMTOTAL_STRING.equals(matcher.group(1))) {
|
||||
long mem = NumberUtils.parseLongSafely(matcher.group(2), -1L);
|
||||
if (mem != -1L) {
|
||||
mem *= 1024;
|
||||
}
|
||||
sTotalMem = mem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(reader);
|
||||
}
|
||||
if (sTotalMem == Long.MIN_VALUE) {
|
||||
sTotalMem = -1L;
|
||||
}
|
||||
}
|
||||
return sTotalMem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ObjectUtils {
|
||||
private ObjectUtils() {}
|
||||
|
||||
/**
|
||||
* Returns true if two possibly-null objects are equal.
|
||||
*/
|
||||
public static boolean equal(@Nullable Object a, @Nullable Object b) {
|
||||
return a == b || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns "null" for null or {@code o.toString()}.
|
||||
*/
|
||||
public static String toString(Object o) {
|
||||
return (o == null) ? "null" : o.toString();
|
||||
}
|
||||
|
||||
private static void dumpObject(Object o, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(o.getClass().getName());writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpBoolean(boolean z, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Boolean.toString(z));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpByte(byte b, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Byte.toString(b));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpChar(char c, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Character.toString(c));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpShort(short s, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Short.toString(s));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpInt(int i, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Integer.toString(i));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpLong(long j, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Long.toString(j));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpFloat(float f, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Float.toString(f));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpDouble(double d, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(Double.toString(d));writer.write('\n');
|
||||
}
|
||||
|
||||
private static void dumpArray(Object array, PrintWriter writer, String prefix, boolean skipFirstPrefix) {
|
||||
if (skipFirstPrefix) {
|
||||
dumpObject(array, writer, "");
|
||||
} else {
|
||||
dumpObject(array, writer, prefix);
|
||||
}
|
||||
|
||||
String newPrefix = prefix + " ";
|
||||
writer.write(newPrefix);writer.write('[');writer.write('\n');
|
||||
|
||||
if (array instanceof Object[]) {
|
||||
Object[] a = (Object[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dump(a[i], writer, newPrefix, false);
|
||||
}
|
||||
} else if (array instanceof boolean[]) {
|
||||
boolean[] a = (boolean[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpBoolean(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof byte[]) {
|
||||
byte[] a = (byte[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpByte(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof char[]) {
|
||||
char[] a = (char[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpChar(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof short[]) {
|
||||
short[] a = (short[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpShort(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof int[]) {
|
||||
int[] a = (int[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpInt(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof long[]) {
|
||||
long[] a = (long[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpLong(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof float[]) {
|
||||
float[] a = (float[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpFloat(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof double[]) {
|
||||
double[] a = (double[]) array;
|
||||
for (int i = 0, l = a.length; i < l; i++) {
|
||||
dumpDouble(a[i], writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof List) {
|
||||
for (Object o : (List) array) {
|
||||
dump(o, writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof Set) {
|
||||
for (Object o : (Set) array) {
|
||||
dump(o, writer, newPrefix);
|
||||
}
|
||||
} else if (array instanceof Map) {
|
||||
Map map = (Map) array;
|
||||
for (Object key : map.keySet()) {
|
||||
Object value = map.get(key);
|
||||
writer.write(newPrefix);writer.write(key.toString());writer.write(": ");dump(value, writer, newPrefix, true);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(array + " is not array");
|
||||
}
|
||||
|
||||
writer.write(newPrefix);writer.write(']');writer.write('\n');
|
||||
}
|
||||
|
||||
public static void dump(Object o, PrintWriter writer) {
|
||||
dump(o, writer, "", false);
|
||||
}
|
||||
|
||||
public static void dump(Object o, PrintWriter writer, String prefix) {
|
||||
dump(o, writer, prefix, false);
|
||||
}
|
||||
|
||||
public static void dump(Object o, PrintWriter writer, String prefix, boolean skipFirstPrefix) {
|
||||
if (o == null) {
|
||||
if (!skipFirstPrefix) {
|
||||
writer.write(prefix);
|
||||
}
|
||||
writer.write("null\n");
|
||||
} else if (o.getClass().isArray() || o instanceof List || o instanceof Set || o instanceof Map) {
|
||||
dumpArray(o, writer, prefix, skipFirstPrefix);
|
||||
} else if (o.getClass().isPrimitive() || o instanceof Boolean ||
|
||||
o instanceof Byte || o instanceof Character || o instanceof Short ||
|
||||
o instanceof Integer || o instanceof Long || o instanceof Float ||
|
||||
o instanceof Double || o instanceof String) {
|
||||
if (!skipFirstPrefix) {
|
||||
writer.write(prefix);
|
||||
}
|
||||
writer.write(o.toString());
|
||||
writer.write('\n');
|
||||
} else {
|
||||
if (skipFirstPrefix) {
|
||||
dumpObject(o, writer, "");
|
||||
} else {
|
||||
dumpObject(o, writer, prefix);
|
||||
}
|
||||
|
||||
String newPrefix = prefix + " ";
|
||||
for (Field field : o.getClass().getDeclaredFields()) {
|
||||
// Skip static filed
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
String name = field.getName();
|
||||
try {
|
||||
Object value = field.get(o);
|
||||
writer.write(newPrefix);writer.write(name);writer.write(": ");dump(value, writer, newPrefix, true);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
public class Pool<T> {
|
||||
|
||||
private final T[] mArray;
|
||||
private final int mMaxSize;
|
||||
private int mSize;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Pool(int size) {
|
||||
if (size <= 0) {
|
||||
throw new IllegalStateException("Pool size must > 0, it is " + size);
|
||||
}
|
||||
mArray = (T[]) new Object[size];
|
||||
mMaxSize = size;
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
public void push(T t) {
|
||||
if (t != null && mSize < mMaxSize) {
|
||||
mArray[mSize++] = t;
|
||||
}
|
||||
}
|
||||
|
||||
public T pop() {
|
||||
if (mSize > 0) {
|
||||
T t = mArray[--mSize];
|
||||
mArray[mSize] = null;
|
||||
return t;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
|
||||
public final class ResourcesUtils {
|
||||
private ResourcesUtils() {}
|
||||
|
||||
private static final Object mAccessLock = new Object();
|
||||
private static TypedValue mTmpValue = new TypedValue();
|
||||
|
||||
public static float getFloat(Resources resources, int resId) {
|
||||
TypedValue outValue = new TypedValue();
|
||||
resources.getValue(resId, outValue, true);
|
||||
return outValue.getFloat();
|
||||
}
|
||||
|
||||
private static void getAttrValue(Context context, int attrId, TypedValue value) {
|
||||
context.getTheme().resolveAttribute(attrId, value, true);
|
||||
}
|
||||
|
||||
public static int getAttrColor(Context context, @AttrRes int attrId) {
|
||||
TypedValue value;
|
||||
synchronized (mAccessLock) {
|
||||
value = mTmpValue;
|
||||
if (value == null) {
|
||||
value = new TypedValue();
|
||||
}
|
||||
getAttrValue(context, attrId, value);
|
||||
if (value.type >= TypedValue.TYPE_FIRST_INT
|
||||
&& value.type <= TypedValue.TYPE_LAST_INT) {
|
||||
mTmpValue = value;
|
||||
return value.data;
|
||||
} else {
|
||||
throw new Resources.NotFoundException(
|
||||
"Attribute ID #0x" + Integer.toHexString(attrId) + " type #0x"
|
||||
+ Integer.toHexString(value.type) + " is not valid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean getAttrBoolean(Context context, @AttrRes int attrId) {
|
||||
synchronized (mAccessLock) {
|
||||
TypedValue value = mTmpValue;
|
||||
if (value == null) {
|
||||
mTmpValue = value = new TypedValue();
|
||||
}
|
||||
getAttrValue(context, attrId, value);
|
||||
if (value.type >= TypedValue.TYPE_FIRST_INT
|
||||
&& value.type <= TypedValue.TYPE_LAST_INT) {
|
||||
return value.data != 0;
|
||||
}
|
||||
throw new Resources.NotFoundException(
|
||||
"Attribute ID #0x" + Integer.toHexString(attrId) + " type #0x"
|
||||
+ Integer.toHexString(value.type) + " is not valid");
|
||||
}
|
||||
}
|
||||
|
||||
public static int getAttrDimensionPixelOffset(Context context, @AttrRes int attrId) {
|
||||
synchronized (mAccessLock) {
|
||||
TypedValue value = mTmpValue;
|
||||
if (value == null) {
|
||||
mTmpValue = value = new TypedValue();
|
||||
}
|
||||
getAttrValue(context, attrId, value);
|
||||
if (value.type == TypedValue.TYPE_DIMENSION) {
|
||||
return TypedValue.complexToDimensionPixelOffset(
|
||||
value.data, context.getResources().getDisplayMetrics());
|
||||
}
|
||||
throw new Resources.NotFoundException(
|
||||
"Attribute ID #0x" + Integer.toHexString(attrId) + " type #0x"
|
||||
+ Integer.toHexString(value.type) + " is not valid");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.view.animation.Animation;
|
||||
|
||||
public class SimpleAnimationListener implements Animation.AnimationListener {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
||||
public abstract class SimpleAnimatorListener implements Animator.AnimatorListener {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
public final class SimpleHandler extends Handler {
|
||||
|
||||
private static Handler sInstance;
|
||||
|
||||
public static Handler getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private SimpleHandler(Looper mainLooper) {
|
||||
super(mainLooper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class StringUtils {
|
||||
private StringUtils() {}
|
||||
|
||||
public static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
private static final String[] ESCAPE_CHARATER_LIST = {
|
||||
"&",
|
||||
"<",
|
||||
">",
|
||||
""",
|
||||
"'",
|
||||
"×",
|
||||
" "
|
||||
};
|
||||
|
||||
private static final String[] UNESCAPE_CHARATER_LIST = {
|
||||
"&",
|
||||
"<",
|
||||
">",
|
||||
"\"",
|
||||
"'",
|
||||
"×",
|
||||
" "
|
||||
};
|
||||
|
||||
/**
|
||||
* Unescape xml. It do not work perfectly.
|
||||
*/
|
||||
public static String unescapeXml(String str) {
|
||||
return replaceEach(str, ESCAPE_CHARATER_LIST, UNESCAPE_CHARATER_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Replaces all occurrences of a String within another String.</p>
|
||||
*
|
||||
* <p>A {@code null} reference passed to this method is a no-op.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.replace(null, *, *) = null
|
||||
* StringUtils.replace("", *, *) = ""
|
||||
* StringUtils.replace("any", null, *) = "any"
|
||||
* StringUtils.replace("any", *, null) = "any"
|
||||
* StringUtils.replace("any", "", *) = "any"
|
||||
* StringUtils.replace("aba", "a", null) = "aba"
|
||||
* StringUtils.replace("aba", "a", "") = "b"
|
||||
* StringUtils.replace("aba", "a", "z") = "zbz"
|
||||
* </pre>
|
||||
*
|
||||
* @see #replace(String text, String searchString, String replacement, int max)
|
||||
* @param text text to search and replace in, may be null
|
||||
* @param searchString the String to search for, may be null
|
||||
* @param replacement the String to replace it with, may be null
|
||||
* @return the text with any replacements processed,
|
||||
* {@code null} if null String input
|
||||
*/
|
||||
public static String replace(final String text, final String searchString, final String replacement) {
|
||||
return replace(text, searchString, replacement, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Replaces a String with another String inside a larger String,
|
||||
* for the first {@code max} values of the search String.</p>
|
||||
*
|
||||
* <p>A {@code null} reference passed to this method is a no-op.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.replace(null, *, *, *) = null
|
||||
* StringUtils.replace("", *, *, *) = ""
|
||||
* StringUtils.replace("any", null, *, *) = "any"
|
||||
* StringUtils.replace("any", *, null, *) = "any"
|
||||
* StringUtils.replace("any", "", *, *) = "any"
|
||||
* StringUtils.replace("any", *, *, 0) = "any"
|
||||
* StringUtils.replace("abaa", "a", null, -1) = "abaa"
|
||||
* StringUtils.replace("abaa", "a", "", -1) = "b"
|
||||
* StringUtils.replace("abaa", "a", "z", 0) = "abaa"
|
||||
* StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
|
||||
* StringUtils.replace("abaa", "a", "z", 2) = "zbza"
|
||||
* StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
|
||||
* </pre>
|
||||
*
|
||||
* @param text text to search and replace in, may be null
|
||||
* @param searchString the String to search for, may be null
|
||||
* @param replacement the String to replace it with, may be null
|
||||
* @param max maximum number of values to replace, or {@code -1} if no maximum
|
||||
* @return the text with any replacements processed,
|
||||
* {@code null} if null String input
|
||||
*/
|
||||
public static String replace(final String text, final String searchString, final String replacement, int max) {
|
||||
if (TextUtils.isEmpty(text) || TextUtils.isEmpty(searchString) || replacement == null || max == 0) {
|
||||
return text;
|
||||
}
|
||||
int start = 0;
|
||||
int end = text.indexOf(searchString, start);
|
||||
if (end < 0) {
|
||||
return text;
|
||||
}
|
||||
final int replLength = searchString.length();
|
||||
int increase = replacement.length() - replLength;
|
||||
increase = increase < 0 ? 0 : increase;
|
||||
increase *= max < 0 ? 16 : max > 64 ? 64 : max;
|
||||
final StringBuilder buf = new StringBuilder(text.length() + increase);
|
||||
while (end >= 0) {
|
||||
buf.append(text.substring(start, end)).append(replacement);
|
||||
start = end + replLength;
|
||||
if (--max == 0) {
|
||||
break;
|
||||
}
|
||||
end = text.indexOf(searchString, start);
|
||||
}
|
||||
buf.append(text.substring(start));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Replaces all occurrences of Strings within another String.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} reference passed to this method is a no-op, or if
|
||||
* any "search string" or "string to replace" is null, that replace will be
|
||||
* ignored. This will not repeat. For repeating replaces, call the
|
||||
* overloaded method.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.replaceEach(null, *, *) = null
|
||||
* StringUtils.replaceEach("", *, *) = ""
|
||||
* StringUtils.replaceEach("aba", null, null) = "aba"
|
||||
* StringUtils.replaceEach("aba", new String[0], null) = "aba"
|
||||
* StringUtils.replaceEach("aba", null, new String[0]) = "aba"
|
||||
* StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
|
||||
* StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
|
||||
* StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
|
||||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
|
||||
* (example of how it does not repeat)
|
||||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
|
||||
* </pre>
|
||||
*
|
||||
* @param text
|
||||
* text to search and replace in, no-op if null
|
||||
* @param searchList
|
||||
* the Strings to search for, no-op if null
|
||||
* @param replacementList
|
||||
* the Strings to replace them with, no-op if null
|
||||
* @return the text with any replacements processed, {@code null} if
|
||||
* null String input
|
||||
* @throws IllegalArgumentException
|
||||
* if the lengths of the arrays are not the same (null is ok,
|
||||
* and/or size 0)
|
||||
*/
|
||||
// Get from org.apache.commons.lang3.StringUtils
|
||||
public static String replaceEach(final String text, final String[] searchList,
|
||||
final String[] replacementList) {
|
||||
return replaceEach(text, searchList, replacementList, false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Replaces all occurrences of Strings within another String.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} reference passed to this method is a no-op, or if
|
||||
* any "search string" or "string to replace" is null, that replace will be
|
||||
* ignored.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.replaceEach(null, *, *, *) = null
|
||||
* StringUtils.replaceEach("", *, *, *) = ""
|
||||
* StringUtils.replaceEach("aba", null, null, *) = "aba"
|
||||
* StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
|
||||
* StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
|
||||
* StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
|
||||
* StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
|
||||
* StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
|
||||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
|
||||
* (example of how it repeats)
|
||||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
|
||||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
|
||||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
|
||||
* </pre>
|
||||
*
|
||||
* @param text
|
||||
* text to search and replace in, no-op if null
|
||||
* @param searchList
|
||||
* the Strings to search for, no-op if null
|
||||
* @param replacementList
|
||||
* the Strings to replace them with, no-op if null
|
||||
* @param repeat if true, then replace repeatedly
|
||||
* until there are no more possible replacements or timeToLive < 0
|
||||
* @param timeToLive
|
||||
* if less than 0 then there is a circular reference and endless
|
||||
* loop
|
||||
* @return the text with any replacements processed, {@code null} if
|
||||
* null String input
|
||||
* @throws IllegalStateException
|
||||
* if the search is repeating and there is an endless loop due
|
||||
* to outputs of one being inputs to another
|
||||
* @throws IllegalArgumentException
|
||||
* if the lengths of the arrays are not the same (null is ok,
|
||||
* and/or size 0)
|
||||
*/
|
||||
// Get from org.apache.commons.lang3.StringUtils
|
||||
private static String replaceEach(
|
||||
final String text, final String[] searchList,
|
||||
final String[] replacementList, final boolean repeat,
|
||||
final int timeToLive) {
|
||||
|
||||
// mchyzer Performance note: This creates very few new objects (one major goal)
|
||||
// let me know if there are performance requests, we can create a harness to measure
|
||||
|
||||
if (text == null || TextUtils.isEmpty(text) || searchList == null ||
|
||||
searchList.length == 0 || replacementList == null || replacementList.length == 0) {
|
||||
return text;
|
||||
}
|
||||
|
||||
// if recursing, this shouldn't be less than 0
|
||||
if (timeToLive < 0) {
|
||||
throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
|
||||
"output of one loop is the input of another");
|
||||
}
|
||||
|
||||
final int searchLength = searchList.length;
|
||||
final int replacementLength = replacementList.length;
|
||||
|
||||
// make sure lengths are ok, these need to be equal
|
||||
if (searchLength != replacementLength) {
|
||||
throw new IllegalArgumentException("Search and Replace array lengths don't match: "
|
||||
+ searchLength
|
||||
+ " vs "
|
||||
+ replacementLength);
|
||||
}
|
||||
|
||||
// keep track of which still have matches
|
||||
final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
|
||||
|
||||
// index on index that the match was found
|
||||
int textIndex = -1;
|
||||
int replaceIndex = -1;
|
||||
int tempIndex = -1;
|
||||
|
||||
// index of replace array that will replace the search string found
|
||||
// NOTE: logic duplicated below START
|
||||
for (int i = 0; i < searchLength; i++) {
|
||||
if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
|
||||
TextUtils.isEmpty(searchList[i]) || replacementList[i] == null) {
|
||||
continue;
|
||||
}
|
||||
tempIndex = text.indexOf(searchList[i]);
|
||||
|
||||
// see if we need to keep searching for this
|
||||
if (tempIndex == -1) {
|
||||
noMoreMatchesForReplIndex[i] = true;
|
||||
} else {
|
||||
if (textIndex == -1 || tempIndex < textIndex) {
|
||||
textIndex = tempIndex;
|
||||
replaceIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: logic mostly below END
|
||||
|
||||
// no search strings found, we are done
|
||||
if (textIndex == -1) {
|
||||
return text;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
|
||||
// get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
|
||||
int increase = 0;
|
||||
|
||||
// count the replacement text elements that are larger than their corresponding text being replaced
|
||||
for (int i = 0; i < searchList.length; i++) {
|
||||
if (searchList[i] == null || replacementList[i] == null) {
|
||||
continue;
|
||||
}
|
||||
final int greater = replacementList[i].length() - searchList[i].length();
|
||||
if (greater > 0) {
|
||||
increase += 3 * greater; // assume 3 matches
|
||||
}
|
||||
}
|
||||
// have upper-bound at 20% increase, then let Java take over
|
||||
increase = Math.min(increase, text.length() / 5);
|
||||
|
||||
final StringBuilder buf = new StringBuilder(text.length() + increase);
|
||||
|
||||
while (textIndex != -1) {
|
||||
|
||||
for (int i = start; i < textIndex; i++) {
|
||||
buf.append(text.charAt(i));
|
||||
}
|
||||
buf.append(replacementList[replaceIndex]);
|
||||
|
||||
start = textIndex + searchList[replaceIndex].length();
|
||||
|
||||
textIndex = -1;
|
||||
replaceIndex = -1;
|
||||
tempIndex = -1;
|
||||
// find the next earliest match
|
||||
// NOTE: logic mostly duplicated above START
|
||||
for (int i = 0; i < searchLength; i++) {
|
||||
if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
|
||||
TextUtils.isEmpty(searchList[i]) || replacementList[i] == null) {
|
||||
continue;
|
||||
}
|
||||
tempIndex = text.indexOf(searchList[i], start);
|
||||
|
||||
// see if we need to keep searching for this
|
||||
if (tempIndex == -1) {
|
||||
noMoreMatchesForReplIndex[i] = true;
|
||||
} else {
|
||||
if (textIndex == -1 || tempIndex < textIndex) {
|
||||
textIndex = tempIndex;
|
||||
replaceIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: logic duplicated above END
|
||||
|
||||
}
|
||||
final int textLength = text.length();
|
||||
for (int i = start; i < textLength; i++) {
|
||||
buf.append(text.charAt(i));
|
||||
}
|
||||
final String result = buf.toString();
|
||||
if (!repeat) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
|
||||
}
|
||||
|
||||
public static boolean endsWith(String string, String[] suffixs) {
|
||||
for (int i = 0, n = suffixs.length; i < n; i++) {
|
||||
if (string.endsWith(suffixs[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Splits the provided text into an array, separator specified.
|
||||
* This is an alternative to using StringTokenizer.</p>
|
||||
*
|
||||
* <p>The separator is not included in the returned String array.
|
||||
* Adjacent separators are treated as one separator.
|
||||
* For more control over the split use the StrTokenizer class.</p>
|
||||
*
|
||||
* <p>A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.split(null, *) = null
|
||||
* StringUtils.split("", *) = []
|
||||
* StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
|
||||
* StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
|
||||
* StringUtils.split("a:b:c", '.') = ["a:b:c"]
|
||||
* StringUtils.split("a b c", ' ') = ["a", "b", "c"]
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to parse, may be null
|
||||
* @param separatorChar the character used as the delimiter
|
||||
* @return an array of parsed Strings, {@code null} if null String input
|
||||
* @since 2.0
|
||||
*/
|
||||
// Get from org.apache.commons.lang3.StringUtils
|
||||
public static String[] split(final String str, final char separatorChar) {
|
||||
return splitWorker(str, separatorChar, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logic for the {@code split} and
|
||||
* {@code splitPreserveAllTokens} methods that do not return a
|
||||
* maximum array length.
|
||||
*
|
||||
* @param str the String to parse, may be {@code null}
|
||||
* @param separatorChar the separate character
|
||||
* @param preserveAllTokens if {@code true}, adjacent separators are
|
||||
* treated as empty token separators; if {@code false}, adjacent
|
||||
* separators are treated as one separator.
|
||||
* @return an array of parsed Strings, {@code null} if null String input
|
||||
*/
|
||||
// Get from org.apache.commons.lang3.StringUtils
|
||||
private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
|
||||
// Performance tuned for 2.0 (JDK1.4)
|
||||
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
final int len = str.length();
|
||||
if (len == 0) {
|
||||
return EMPTY_STRING_ARRAY;
|
||||
}
|
||||
final List<String> list = new ArrayList<>();
|
||||
int i = 0, start = 0;
|
||||
boolean match = false;
|
||||
boolean lastMatch = false;
|
||||
while (i < len) {
|
||||
if (str.charAt(i) == separatorChar) {
|
||||
if (match || preserveAllTokens) {
|
||||
list.add(str.substring(start, i));
|
||||
match = false;
|
||||
lastMatch = true;
|
||||
}
|
||||
start = ++i;
|
||||
continue;
|
||||
}
|
||||
lastMatch = false;
|
||||
match = true;
|
||||
i++;
|
||||
}
|
||||
if (match || preserveAllTokens && lastMatch) {
|
||||
list.add(str.substring(start, i));
|
||||
}
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
public static String avoidNull(String value) {
|
||||
return avoidNull(value, "");
|
||||
}
|
||||
|
||||
public static String avoidNull(String value, String defaultValue) {
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
public static boolean isAllDigit(String str) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 0, n = str.length(); i < n; i++) {
|
||||
char ch = str.charAt(i);
|
||||
if (ch < '0' || ch > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static int length(String str) {
|
||||
return null == str ? 0 : str.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Counts how many times the char appears in the given string.</p>
|
||||
*
|
||||
* <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.countMatches(null, *) = 0
|
||||
* StringUtils.countMatches("", *) = 0
|
||||
* StringUtils.countMatches("abba", 0) = 0
|
||||
* StringUtils.countMatches("abba", 'a') = 2
|
||||
* StringUtils.countMatches("abba", 'b') = 2
|
||||
* StringUtils.countMatches("abba", 'x') = 0
|
||||
* </pre>
|
||||
*
|
||||
* @param str the CharSequence to check, may be null
|
||||
* @param ch the char to count
|
||||
* @return the number of occurrences, 0 if the CharSequence is {@code null}
|
||||
*/
|
||||
public static int countMatches(final CharSequence str, final char ch) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
// We could also call str.toCharArray() for faster look ups but that would generate more garbage.
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (ch == str.charAt(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* All null or empty, or all not
|
||||
*/
|
||||
public static boolean equals(String str1, String str2) {
|
||||
return (TextUtils.isEmpty(str1) && TextUtils.isEmpty(str2)) ||
|
||||
(!TextUtils.isEmpty(str1) && !TextUtils.isEmpty(str2) && str1.equals(str2));
|
||||
}
|
||||
|
||||
public static int ordinalIndexOf(String str, char c, int n) {
|
||||
if (null == str || n < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pos = -1;
|
||||
do {
|
||||
pos = str.indexOf(c, pos + 1);
|
||||
} while (n-- > 0 && pos != -1);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static final char[] WHITE_SPACE_ARRAY = {
|
||||
'\u0009', // TAB
|
||||
'\u0020', // SPACE
|
||||
'\u00A0', // NO-BREAK SPACE
|
||||
'\u3000', // IDEOGRAPHIC SPACE
|
||||
};
|
||||
|
||||
/**
|
||||
* Works like {@link String#trim()}, but more white space is excluded.
|
||||
* The white space characters is {@link #WHITE_SPACE_ARRAY}.
|
||||
*
|
||||
* @see {@link #trim(String, char[])}
|
||||
*/
|
||||
public static String trim(String str) {
|
||||
return trim(str, WHITE_SPACE_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Works like {@link String#trim()}, but custom characters is excluded.
|
||||
*
|
||||
* @see {@link #trim(String)}
|
||||
*/
|
||||
public static String trim(String str, char[] excluded) {
|
||||
if (null == str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int start = 0, last = str.length() - 1;
|
||||
int end = last;
|
||||
while ((start <= end) && (Arrays.binarySearch(excluded, str.charAt(start)) >= 0)) {
|
||||
start++;
|
||||
}
|
||||
while ((end >= start) && (Arrays.binarySearch(excluded, str.charAt(end)) >= 0)) {
|
||||
end--;
|
||||
}
|
||||
if (start == 0 && end == last) {
|
||||
return str;
|
||||
}
|
||||
|
||||
return str.substring(start, end + 1);
|
||||
}
|
||||
|
||||
public static String remove(String str, char[] removed) {
|
||||
if (TextUtils.isEmpty(str) || null == removed || 0 == removed.length) {
|
||||
return str;
|
||||
}
|
||||
|
||||
final char[] chars = str.toCharArray();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
if (!Utilities.contain(removed, chars[i])) {
|
||||
chars[pos++] = chars[i];
|
||||
}
|
||||
}
|
||||
return new String(chars, 0, pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class Utilities {
|
||||
|
||||
/**
|
||||
* Whether the array contain the element
|
||||
*
|
||||
* @param array the array
|
||||
* @param obj the element
|
||||
* @return true for the array contain the element
|
||||
*/
|
||||
public static boolean contain(@Nullable Object[] array, @Nullable Object obj) {
|
||||
if (null == array) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Object o : array) {
|
||||
if (ObjectUtils.equal(o, obj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the array contain the element
|
||||
*
|
||||
* @param array the array
|
||||
* @param ch the element
|
||||
* @return true for the array contain the element
|
||||
*/
|
||||
public static boolean contain(@Nullable char[] array, char ch) {
|
||||
if (null == array) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (char c: array) {
|
||||
if (c == ch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getNameFromUrl(String url) {
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
int fragment = url.lastIndexOf('#');
|
||||
if (fragment > 0) {
|
||||
url = url.substring(0, fragment);
|
||||
}
|
||||
|
||||
int query = url.lastIndexOf('?');
|
||||
if (query > 0) {
|
||||
url = url.substring(0, query);
|
||||
}
|
||||
|
||||
int filenamePos = url.lastIndexOf('/');
|
||||
String filename =
|
||||
0 <= filenamePos ? url.substring(filenamePos + 1) : url;
|
||||
|
||||
// if the filename contains special characters, we don't
|
||||
// consider it valid for our matching purposes:
|
||||
if (filename.length() != 0 &&
|
||||
Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)%]+", filename)) {
|
||||
int dotPos = filename.lastIndexOf('.');
|
||||
if (0 < dotPos) {
|
||||
return filename.substring(0, dotPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final String[] MIME_TYPE_ARRAY = {
|
||||
"image/jpg"
|
||||
};
|
||||
|
||||
private static final String[] EXTENSION_ARRAY = {
|
||||
"jpg"
|
||||
};
|
||||
|
||||
public static String getExtensionFromMimeType(String mimeType) {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0, n = MIME_TYPE_ARRAY.length; i < n; i++) {
|
||||
if (MIME_TYPE_ARRAY[i].equals(mimeType)) {
|
||||
return EXTENSION_ARRAY[i];
|
||||
}
|
||||
}
|
||||
|
||||
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.yorozuya;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public final class ViewUtils {
|
||||
private ViewUtils() {}
|
||||
|
||||
public static final int MAX_SIZE = Integer.MAX_VALUE & ~(0x3 << 30);
|
||||
|
||||
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* Get view center location in window
|
||||
*
|
||||
* @param view the view to check
|
||||
* @param location an array of two integers in which to hold the coordinates
|
||||
*/
|
||||
public static void getCenterInWindows(View view, int[] location) {
|
||||
getLocationInWindow(view, location);
|
||||
location[0] += view.getWidth() / 2;
|
||||
location[1] += view.getHeight() / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get view location in window
|
||||
*
|
||||
* @param view the view to check
|
||||
* @param location an array of two integers in which to hold the coordinates
|
||||
*/
|
||||
public static void getLocationInWindow(View view, int[] location) {
|
||||
getLocationInAncestor(view, location, android.R.id.content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get view center in ths ancestor
|
||||
*
|
||||
* @param view the view to start with
|
||||
* @param location the container of result
|
||||
* @param ancestorId the ancestor id
|
||||
*/
|
||||
public static void getCenterInAncestor(View view, int[] location, int ancestorId) {
|
||||
getLocationInAncestor(view, location, ancestorId);
|
||||
location[0] += view.getWidth() / 2;
|
||||
location[1] += view.getHeight() / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get view location in ths ancestor
|
||||
*
|
||||
* @param view the view to start with
|
||||
* @param location the container of result
|
||||
* @param ancestorId the ancestor id
|
||||
*/
|
||||
public static void getLocationInAncestor(View view, int[] location, int ancestorId) {
|
||||
if (location == null || location.length < 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"location must be an array of two integers");
|
||||
}
|
||||
|
||||
float[] position = new float[2];
|
||||
|
||||
position[0] = view.getLeft();
|
||||
position[1] = view.getTop();
|
||||
|
||||
ViewParent viewParent = view.getParent();
|
||||
while (viewParent instanceof View) {
|
||||
view = (View) viewParent;
|
||||
if (view.getId() == ancestorId) {
|
||||
break;
|
||||
}
|
||||
|
||||
position[0] -= view.getScrollX();
|
||||
position[1] -= view.getScrollY();
|
||||
|
||||
position[0] += view.getLeft();
|
||||
position[1] += view.getTop();
|
||||
|
||||
viewParent = view.getParent();
|
||||
}
|
||||
|
||||
location[0] = (int) (position[0] + 0.5f);
|
||||
location[1] = (int) (position[1] + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get view center in ths ancestor
|
||||
*
|
||||
* @param view the view to start with
|
||||
* @param location the container of result
|
||||
* @param ancestor the ancestor
|
||||
*/
|
||||
public static void getCenterInAncestor(View view, int[] location, View ancestor) {
|
||||
getLocationInAncestor(view, location, ancestor);
|
||||
location[0] += view.getWidth() / 2;
|
||||
location[1] += view.getHeight() / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get view location in ths ancestor
|
||||
*
|
||||
* @param view the view to start with
|
||||
* @param location the container of result
|
||||
* @param ancestor the ancestor
|
||||
*/
|
||||
public static void getLocationInAncestor(View view, int[] location, View ancestor) {
|
||||
if (location == null || location.length < 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"location must be an array of two integers");
|
||||
}
|
||||
|
||||
float[] position = new float[2];
|
||||
|
||||
position[0] = view.getLeft();
|
||||
position[1] = view.getTop();
|
||||
|
||||
ViewParent viewParent = view.getParent();
|
||||
while (viewParent instanceof View) {
|
||||
view = (View) viewParent;
|
||||
if (viewParent == ancestor) {
|
||||
break;
|
||||
}
|
||||
|
||||
position[0] -= view.getScrollX();
|
||||
position[1] -= view.getScrollY();
|
||||
|
||||
position[0] += view.getLeft();
|
||||
position[1] += view.getTop();
|
||||
|
||||
viewParent = view.getParent();
|
||||
}
|
||||
|
||||
location[0] = (int) (position[0] + 0.5f);
|
||||
location[1] = (int) (position[1] + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a ancestor view with the given id. If this view has the given
|
||||
* id, return this view.
|
||||
*
|
||||
* @param view the view to start with
|
||||
* @param id The id to search for.
|
||||
* @return The view that has the given id in the hierarchy or null
|
||||
*/
|
||||
public static View getAncestor(View view, int id) {
|
||||
if (view.getId() == id) {
|
||||
return view;
|
||||
}
|
||||
|
||||
ViewParent viewParent = view.getParent();
|
||||
while (viewParent instanceof View) {
|
||||
view = (View) viewParent;
|
||||
if (view.getId() == id) {
|
||||
return view;
|
||||
}
|
||||
viewParent = view.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a child view with the given id. If this view has the given
|
||||
* id, return this view.
|
||||
*
|
||||
* @param view the view to start with
|
||||
* @param id the id to search for
|
||||
* @return the view that has the given id in the hierarchy or null
|
||||
*/
|
||||
public static View getChild(View view, int id) {
|
||||
if (view.getId() == id) {
|
||||
return view;
|
||||
}
|
||||
|
||||
if (view instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
for (int i = 0, n = viewGroup.getChildCount(); i < n; i++) {
|
||||
View child = viewGroup.getChildAt(i);
|
||||
View result = getChild(child, id);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bitmap showing a screenshot of the view passed in.
|
||||
*
|
||||
* @param v The view to get screenshot
|
||||
* @return The screenshot
|
||||
*/
|
||||
public static Bitmap getBitmapFromView(View v) {
|
||||
int width = v.getWidth();
|
||||
int height = v.getHeight();
|
||||
if (width == 0 && height == 0) {
|
||||
width = v.getMeasuredWidth();
|
||||
height = v.getMeasuredHeight();
|
||||
}
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.translate(-v.getScrollX(), -v.getScrollY());
|
||||
v.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove view from its parent
|
||||
*
|
||||
* @param view the view to remove
|
||||
*/
|
||||
public static void removeFromParent(View view) {
|
||||
ViewParent vp = view.getParent();
|
||||
if (vp instanceof ViewGroup)
|
||||
((ViewGroup) vp).removeView(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that removes the support for HardwareAcceleration from a
|
||||
* {@link View}.<br/>
|
||||
* <br/>
|
||||
* Check AOSP notice:<br/>
|
||||
*
|
||||
* <pre>
|
||||
* 'ComposeShader can only contain shaders of different types (a BitmapShader and a
|
||||
* LinearGradient for instance, but not two instances of BitmapShader)'. But, 'If your
|
||||
* application is affected by any of these missing features or limitations, you can turn
|
||||
* off hardware acceleration for just the affected portion of your application by calling
|
||||
* setLayerType(View.LAYER_TYPE_SOFTWARE, null).'
|
||||
* </pre>
|
||||
*
|
||||
* @param v
|
||||
* The view
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public static void removeHardwareAccelerationSupport(View v) {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
|
||||
if (v.getLayerType() != View.LAYER_TYPE_SOFTWARE) {
|
||||
v.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public static void addHardwareAccelerationSupport(View v) {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
|
||||
if (v.getLayerType() != View.LAYER_TYPE_HARDWARE) {
|
||||
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void measureView(View v, int width, int height) {
|
||||
int widthMeasureSpec;
|
||||
int heightMeasureSpec;
|
||||
if (width == ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0,
|
||||
View.MeasureSpec.UNSPECIFIED);
|
||||
else
|
||||
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(Math.max(width, 0),
|
||||
View.MeasureSpec.EXACTLY);
|
||||
if (height == ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0,
|
||||
View.MeasureSpec.UNSPECIFIED);
|
||||
else
|
||||
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(Math.max(height, 0),
|
||||
View.MeasureSpec.EXACTLY);
|
||||
|
||||
v.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param slop the slop out of the view, or negative for inside
|
||||
* @return true if the supplied view is under the given point, false otherwise
|
||||
*/
|
||||
public static boolean isViewUnder(@Nullable View view, int x, int y, int slop) {
|
||||
if (view == null) {
|
||||
return false;
|
||||
} else {
|
||||
float translationX = 0.0f;
|
||||
float translationY = 0.0f;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
translationX = view.getTranslationX();
|
||||
translationY = view.getTranslationY();
|
||||
}
|
||||
return x >= view.getLeft() + translationX - slop &&
|
||||
x < view.getRight() + translationX + slop &&
|
||||
y >= view.getTop() + translationY - slop &&
|
||||
y < view.getBottom() + translationY + slop;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to return a default size. Uses the supplied size if the
|
||||
* MeasureSpec imposed no constraints. Will get suitable if allowed
|
||||
* by the MeasureSpec.
|
||||
*
|
||||
* @param size Default size for this view
|
||||
* @param measureSpec Constraints imposed by the parent
|
||||
* @return The size this view should be.
|
||||
*/
|
||||
public static int getSuitableSize(int size, int measureSpec) {
|
||||
int result = size;
|
||||
int specMode = View.MeasureSpec.getMode(measureSpec);
|
||||
int specSize = View.MeasureSpec.getSize(measureSpec);
|
||||
|
||||
switch (specMode) {
|
||||
case View.MeasureSpec.UNSPECIFIED:
|
||||
result = size;
|
||||
break;
|
||||
case View.MeasureSpec.EXACTLY:
|
||||
result = specSize;
|
||||
break;
|
||||
case View.MeasureSpec.AT_MOST:
|
||||
return size == 0 ? specSize : Math.min(size, specSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* removeOnGlobalLayoutListener
|
||||
*
|
||||
* @param viewTreeObserver the ViewTreeObserver
|
||||
* @param l the OnGlobalLayoutListener
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void removeOnGlobalLayoutListener(ViewTreeObserver viewTreeObserver,
|
||||
ViewTreeObserver.OnGlobalLayoutListener l) {
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
viewTreeObserver.removeGlobalOnLayoutListener(l);
|
||||
} else {
|
||||
viewTreeObserver.removeOnGlobalLayoutListener(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index in parent
|
||||
*
|
||||
* @param view The view
|
||||
* @return The index
|
||||
*/
|
||||
public static int getIndexInParent(View view) {
|
||||
ViewParent parent = view.getParent();
|
||||
if (parent instanceof ViewGroup) {
|
||||
ViewGroup viewParent = (ViewGroup) parent;
|
||||
int count = viewParent.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View v = viewParent.getChildAt(i);
|
||||
if (v == view) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform point from parent to child
|
||||
*
|
||||
* @param point the point
|
||||
* @param parent the parent
|
||||
* @param child the child
|
||||
*/
|
||||
public static void transformPointToViewLocal(float[] point, View parent, View child) {
|
||||
point[0] += parent.getScrollX() - child.getLeft();
|
||||
point[1] += parent.getScrollY() - child.getTop();
|
||||
}
|
||||
|
||||
public static void setEnabledRecursively(View view, boolean enabled) {
|
||||
if (view instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
for (int i = 0, n = viewGroup.getChildCount(); i < n; i++) {
|
||||
setEnabledRecursively(viewGroup.getChildAt(i), enabled);
|
||||
}
|
||||
}
|
||||
view.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public static void dumpViewHierarchy(View view, PrintWriter writer) {
|
||||
dumpViewHierarchy(view, writer, "");
|
||||
}
|
||||
|
||||
private static void dumpViewHierarchy(View view, PrintWriter writer, String prefix) {
|
||||
writer.write(prefix);writer.write(view.getClass().getName());writer.write('\n');
|
||||
if (view instanceof ViewGroup) {
|
||||
String newPrefix = prefix + " ";
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
|
||||
View child = viewGroup.getChildAt(i);
|
||||
dumpViewHierarchy(child, writer, newPrefix);
|
||||
}
|
||||
}
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a value suitable for use in {@link View#setId(int)}.
|
||||
* This value will not collide with ID values generated at build time by aapt for R.id.
|
||||
*
|
||||
* @return a generated ID value
|
||||
*/
|
||||
public static int generateViewId() {
|
||||
for (;;) {
|
||||
final int result = sNextGeneratedId.get();
|
||||
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
|
||||
int newValue = result + 1;
|
||||
if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
|
||||
if (sNextGeneratedId.compareAndSet(result, newValue)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset this view translationX
|
||||
*/
|
||||
public static void translationXBy(View view, float offset) {
|
||||
view.setTranslationX(view.getTranslationX() + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset this view translationY
|
||||
*/
|
||||
public static void translationYBy(View view, float offset) {
|
||||
view.setTranslationY(view.getTranslationY() + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* The visual right position of this view, in pixels. This is equivalent to the
|
||||
* {@link View#setTranslationX(float) translationX} property plus the current
|
||||
* {@link View#getRight() right} property.
|
||||
*
|
||||
* @return The visual right position of this view, in pixels.
|
||||
*/
|
||||
public static float getX2(View view) {
|
||||
return view.getRight() + view.getTranslationX();
|
||||
}
|
||||
|
||||
/**
|
||||
* The visual bottom position of this view, in pixels. This is equivalent to the
|
||||
* {@link View#setTranslationY(float) translationY} property plus the current
|
||||
* {@link View#getBottom()} () bottom} property.
|
||||
*
|
||||
* @return The visual bottom position of this view, in pixels.
|
||||
*/
|
||||
public static float getY2(View view) {
|
||||
return view.getBottom() + view.getTranslationY();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static View $$(Activity activity, @IdRes int id) {
|
||||
View result = activity.findViewById(id);
|
||||
if (null == result) {
|
||||
throw new NullPointerException("Can't find view with id: " + id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static View $$(Dialog dialog, @IdRes int id) {
|
||||
View result = dialog.findViewById(id);
|
||||
if (null == result) {
|
||||
throw new NullPointerException("Can't find view with id: " + id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static View $$(View view, @IdRes int id) {
|
||||
View result = view.findViewById(id);
|
||||
if (null == result) {
|
||||
throw new NullPointerException("Can't find view with id: " + id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -137,56 +137,56 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/keep_screen_on"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_keep_screen_on" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/show_clock"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_show_clock" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/show_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_show_progress" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/show_battery"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_show_battery" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/show_page_interval"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_show_page_interval" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/volume_page"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_volume_page"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/reverse_volume_page"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_reverse_volume" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/reading_fullscreen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_read_reading_fullscreen" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/custom_screen_lightness"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="materialSwitchStyle">@style/Widget.Material3.CompoundButton.MaterialSwitch</item>
|
||||
<item name="switchStyle">@style/Widget.Material3.CompoundButton.MaterialSwitch</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay" />
|
||||
@@ -45,7 +47,6 @@
|
||||
<item name="dividerColor">@color/divider_black</item>
|
||||
<item name="drawableColorSecondary">@color/secondary_drawable_black</item>
|
||||
<item name="drawableColorThemePrimary">@color/primary_drawable_black</item>
|
||||
<item name="guideBackgroundColor">#e5000000</item>
|
||||
</style>
|
||||
|
||||
<!-- ============ -->
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.android.application' version '7.2.0' apply false
|
||||
id 'com.android.application' version '7.2.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ android {
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version "3.23.1"
|
||||
path 'src/main/jni/CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
project(ehviewer)
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
# Build liblzma as shared lib
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
# Build liblzma
|
||||
add_subdirectory(liblzma)
|
||||
|
||||
# Build libzstd
|
||||
SET(ZSTD_BUILD_SHARED OFF)
|
||||
add_subdirectory(libzstd/build/cmake)
|
||||
|
||||
# Configure libarchive for android platform
|
||||
@@ -38,4 +38,4 @@ include_directories(libfuse/libfuse/include)
|
||||
# Build and link our app's native lib
|
||||
add_library(${PROJECT_NAME} SHARED main.c archive.c)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC image/image libarchive/libarchive)
|
||||
target_link_libraries(${PROJECT_NAME} image archive fuse)
|
||||
target_link_libraries(${PROJECT_NAME} image archive_static fuse)
|
||||
@@ -23,5 +23,5 @@ set(GIFLIB_SOURCES
|
||||
)
|
||||
set(GIFLIB_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/giflib)
|
||||
|
||||
add_library(gif SHARED ${GIFLIB_SOURCES})
|
||||
add_library(gif STATIC ${GIFLIB_SOURCES})
|
||||
target_include_directories(gif PUBLIC ${GIFLIB_INCLUDES})
|
||||
@@ -39,6 +39,6 @@ set(IMAGE_LIBRARIES
|
||||
gif
|
||||
)
|
||||
|
||||
add_library(image SHARED ${IMAGE_SOURCES})
|
||||
add_library(image STATIC ${IMAGE_SOURCES})
|
||||
target_include_directories(image PRIVATE ${IMAGE_INCLUDES})
|
||||
target_link_libraries(image PRIVATE ${IMAGE_LIBRARIES})
|
||||
@@ -207,5 +207,5 @@ else ()
|
||||
|
||||
endif ()
|
||||
|
||||
add_library(jpeg SHARED ${LIBJPEG_TURBO_SOURCES})
|
||||
add_library(jpeg STATIC ${LIBJPEG_TURBO_SOURCES})
|
||||
target_include_directories(jpeg PUBLIC ${LIBJPEG_TURBO_INCLUDES})
|
||||
@@ -91,7 +91,7 @@ elseif (${ANDROID_ABI} STREQUAL "arm64-v8a")
|
||||
|
||||
endif ()
|
||||
|
||||
add_library(png SHARED ${LIBPNG_SOURCES})
|
||||
add_library(png STATIC ${LIBPNG_SOURCES})
|
||||
target_include_directories(png PUBLIC ${LIBPNG_INCLUDES})
|
||||
target_compile_definitions(png PRIVATE ${LIBPNG_DEFINITIONS})
|
||||
target_link_libraries(png PRIVATE ${LIBPNG_LIBRARIES})
|
||||
@@ -24,6 +24,5 @@ set(STREAM_SOURCES
|
||||
)
|
||||
set(STREAM_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(stream SHARED ${STREAM_SOURCES})
|
||||
add_library(stream STATIC ${STREAM_SOURCES})
|
||||
target_include_directories(stream PUBLIC ${STREAM_INCLUDES})
|
||||
target_link_libraries(stream PRIVATE log)
|
||||
Submodule native/src/main/jni/libarchive updated: f06bdccdfb...c0896da37f.
@@ -26,5 +26,5 @@ set(FUSE_INCLUDES
|
||||
libfuse/lib
|
||||
libfuse/include)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/libfuse/libfuse/lib/fuse_versionscript")
|
||||
add_library(${PROJECT_NAME} SHARED ${FUSE_SOURCES})
|
||||
add_library(${PROJECT_NAME} STATIC ${FUSE_SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${FUSE_INCLUDES})
|
||||
Reference in new issue
Block a user