diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 00000000..7f3affe8 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,40 @@ + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index e805548a..c224ad56 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 00000000..fdeea4f6 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 00000000..16660f1d --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2fd4ea19..55797df6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -68,7 +68,7 @@ dependencies { implementation(libs.gif.drawable) implementation(libs.highlightjs) implementation(libs.appintro) - implementation(libs.expandablelayout) + //implementation(libs.expandablelayout) implementation(libs.timber) implementation(libs.glide) diff --git a/app/src/main/java/sk/styk/martin/apkanalyzer/ui/appdetail/recycler/LazyExpandableViewHolder.kt b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/appdetail/recycler/LazyExpandableViewHolder.kt index 4d883ace..d56cc9bb 100644 --- a/app/src/main/java/sk/styk/martin/apkanalyzer/ui/appdetail/recycler/LazyExpandableViewHolder.kt +++ b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/appdetail/recycler/LazyExpandableViewHolder.kt @@ -4,11 +4,11 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.ViewDataBinding import androidx.recyclerview.widget.RecyclerView -import net.cachapa.expandablelayout.ExpandableLayout import sk.styk.martin.apkanalyzer.BR import sk.styk.martin.apkanalyzer.ui.appdetail.page.activity.ARROW_ANIMATION_DURATION import sk.styk.martin.apkanalyzer.ui.appdetail.page.activity.ROTATION_FLIPPED import sk.styk.martin.apkanalyzer.ui.appdetail.page.activity.ROTATION_STANDARD +import sk.styk.martin.apkanalyzer.ui.expandableLayout.ExpandableLayout abstract class LazyExpandableViewHolder(val baseBinding: BaseBinding) : RecyclerView.ViewHolder(baseBinding.root) { diff --git a/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/ExpandableLayout.java b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/ExpandableLayout.java new file mode 100644 index 00000000..ca841c8c --- /dev/null +++ b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/ExpandableLayout.java @@ -0,0 +1,327 @@ +package sk.styk.martin.apkanalyzer.ui.expandableLayout; + +import static sk.styk.martin.apkanalyzer.ui.expandableLayout.ExpandableLayout.State.COLLAPSED; +import static sk.styk.martin.apkanalyzer.ui.expandableLayout.ExpandableLayout.State.COLLAPSING; +import static sk.styk.martin.apkanalyzer.ui.expandableLayout.ExpandableLayout.State.EXPANDED; +import static sk.styk.martin.apkanalyzer.ui.expandableLayout.ExpandableLayout.State.EXPANDING; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import sk.styk.martin.apkanalyzer.R; +import sk.styk.martin.apkanalyzer.ui.expandableLayout.util.FastOutSlowInInterpolator; + +public class ExpandableLayout extends FrameLayout { + public interface State { + int COLLAPSED = 0; + int COLLAPSING = 1; + int EXPANDING = 2; + int EXPANDED = 3; + } + + public static final String KEY_SUPER_STATE = "super_state"; + public static final String KEY_EXPANSION = "expansion"; + + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + + private static final int DEFAULT_DURATION = 300; + + private int duration = DEFAULT_DURATION; + private float parallax; + private float expansion; + private int orientation; + private int state; + + private Interpolator interpolator = new FastOutSlowInInterpolator(); + private ValueAnimator animator; + + private OnExpansionUpdateListener listener; + + public ExpandableLayout(Context context) { + this(context, null); + } + + public ExpandableLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + if (attrs != null) { + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ExpandableLayout); + duration = a.getInt(R.styleable.ExpandableLayout_el_duration, DEFAULT_DURATION); + expansion = a.getBoolean(R.styleable.ExpandableLayout_el_expanded, false) ? 1 : 0; + orientation = a.getInt(R.styleable.ExpandableLayout_android_orientation, VERTICAL); + parallax = a.getFloat(R.styleable.ExpandableLayout_el_parallax, 1); + a.recycle(); + + state = expansion == 0 ? COLLAPSED : EXPANDED; + setParallax(parallax); + } + } + + @Override + protected Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + Bundle bundle = new Bundle(); + + expansion = isExpanded() ? 1 : 0; + + bundle.putFloat(KEY_EXPANSION, expansion); + bundle.putParcelable(KEY_SUPER_STATE, superState); + + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable parcelable) { + Bundle bundle = (Bundle) parcelable; + expansion = bundle.getFloat(KEY_EXPANSION); + state = expansion == 1 ? EXPANDED : COLLAPSED; + Parcelable superState = bundle.getParcelable(KEY_SUPER_STATE); + + super.onRestoreInstanceState(superState); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + + int size = orientation == LinearLayout.HORIZONTAL ? width : height; + + setVisibility(expansion == 0 && size == 0 ? GONE : VISIBLE); + + int expansionDelta = size - Math.round(size * expansion); + if (parallax > 0) { + float parallaxDelta = expansionDelta * parallax; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (orientation == HORIZONTAL) { + int direction = -1; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1 && getLayoutDirection() == LAYOUT_DIRECTION_RTL) { + direction = 1; + } + child.setTranslationX(direction * parallaxDelta); + } else { + child.setTranslationY(-parallaxDelta); + } + } + } + + if (orientation == HORIZONTAL) { + setMeasuredDimension(width - expansionDelta, height); + } else { + setMeasuredDimension(width, height - expansionDelta); + } + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + if (animator != null) { + animator.cancel(); + } + super.onConfigurationChanged(newConfig); + } + + /** + * Get expansion state + * + * @return one of {@link State} + */ + public int getState() { + return state; + } + + public boolean isExpanded() { + return state == EXPANDING || state == EXPANDED; + } + + public void toggle() { + toggle(true); + } + + public void toggle(boolean animate) { + if (isExpanded()) { + collapse(animate); + } else { + expand(animate); + } + } + + public void expand() { + expand(true); + } + + public void expand(boolean animate) { + setExpanded(true, animate); + } + + public void collapse() { + collapse(true); + } + + public void collapse(boolean animate) { + setExpanded(false, animate); + } + + /** + * Convenience method - same as calling setExpanded(expanded, true) + */ + public void setExpanded(boolean expand) { + setExpanded(expand, true); + } + + public void setExpanded(boolean expand, boolean animate) { + if (expand == isExpanded()) { + return; + } + + int targetExpansion = expand ? 1 : 0; + if (animate) { + animateSize(targetExpansion); + } else { + setExpansion(targetExpansion); + } + } + + public int getDuration() { + return duration; + } + + public void setInterpolator(Interpolator interpolator) { + this.interpolator = interpolator; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public float getExpansion() { + return expansion; + } + + public void setExpansion(float expansion) { + if (this.expansion == expansion) { + return; + } + + // Infer state from previous value + float delta = expansion - this.expansion; + if (expansion == 0) { + state = COLLAPSED; + } else if (expansion == 1) { + state = EXPANDED; + } else if (delta < 0) { + state = COLLAPSING; + } else if (delta > 0) { + state = EXPANDING; + } + + setVisibility(state == COLLAPSED ? GONE : VISIBLE); + this.expansion = expansion; + requestLayout(); + + if (listener != null) { + listener.onExpansionUpdate(expansion, state); + } + } + + public float getParallax() { + return parallax; + } + + public void setParallax(float parallax) { + // Make sure parallax is between 0 and 1 + parallax = Math.min(1, Math.max(0, parallax)); + this.parallax = parallax; + } + + public int getOrientation() { + return orientation; + } + + public void setOrientation(int orientation) { + if (orientation < 0 || orientation > 1) { + throw new IllegalArgumentException("Orientation must be either 0 (horizontal) or 1 (vertical)"); + } + this.orientation = orientation; + } + + public void setOnExpansionUpdateListener(OnExpansionUpdateListener listener) { + this.listener = listener; + } + + private void animateSize(int targetExpansion) { + if (animator != null) { + animator.cancel(); + animator = null; + } + + animator = ValueAnimator.ofFloat(expansion, targetExpansion); + animator.setInterpolator(interpolator); + animator.setDuration(duration); + + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + setExpansion((float) valueAnimator.getAnimatedValue()); + } + }); + + animator.addListener(new ExpansionListener(targetExpansion)); + + animator.start(); + } + + public interface OnExpansionUpdateListener { + /** + * Callback for expansion updates + * + * @param expansionFraction Value between 0 (collapsed) and 1 (expanded) representing the the expansion progress + * @param state One of {@link State} repesenting the current expansion state + */ + void onExpansionUpdate(float expansionFraction, int state); + } + + private class ExpansionListener implements Animator.AnimatorListener { + private int targetExpansion; + private boolean canceled; + + public ExpansionListener(int targetExpansion) { + this.targetExpansion = targetExpansion; + } + + @Override + public void onAnimationStart(Animator animation) { + state = targetExpansion == 0 ? COLLAPSING : EXPANDING; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!canceled) { + state = targetExpansion == 0 ? COLLAPSED : EXPANDED; + setExpansion(targetExpansion); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + canceled = true; + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + } +} diff --git a/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/util/FastOutSlowInInterpolator.java b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/util/FastOutSlowInInterpolator.java new file mode 100644 index 00000000..31c5cedd --- /dev/null +++ b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/util/FastOutSlowInInterpolator.java @@ -0,0 +1,71 @@ +package sk.styk.martin.apkanalyzer.ui.expandableLayout.util; + +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * Interpolator corresponding to {@link android.R.interpolator#fast_out_slow_in}. + * + * Uses a lookup table for the Bezier curve from (0,0) to (1,1) with control points: + * P0 (0, 0) + * P1 (0.4, 0) + * P2 (0.2, 1.0) + * P3 (1.0, 1.0) + */ +public class FastOutSlowInInterpolator extends LookupTableInterpolator { + + /** + * Lookup table values sampled with x at regular intervals between 0 and 1 for a total of + * 201 points. + */ + private static final float[] VALUES = new float[] { + 0.0000f, 0.0001f, 0.0002f, 0.0005f, 0.0009f, 0.0014f, 0.0020f, + 0.0027f, 0.0036f, 0.0046f, 0.0058f, 0.0071f, 0.0085f, 0.0101f, + 0.0118f, 0.0137f, 0.0158f, 0.0180f, 0.0205f, 0.0231f, 0.0259f, + 0.0289f, 0.0321f, 0.0355f, 0.0391f, 0.0430f, 0.0471f, 0.0514f, + 0.0560f, 0.0608f, 0.0660f, 0.0714f, 0.0771f, 0.0830f, 0.0893f, + 0.0959f, 0.1029f, 0.1101f, 0.1177f, 0.1257f, 0.1339f, 0.1426f, + 0.1516f, 0.1610f, 0.1707f, 0.1808f, 0.1913f, 0.2021f, 0.2133f, + 0.2248f, 0.2366f, 0.2487f, 0.2611f, 0.2738f, 0.2867f, 0.2998f, + 0.3131f, 0.3265f, 0.3400f, 0.3536f, 0.3673f, 0.3810f, 0.3946f, + 0.4082f, 0.4217f, 0.4352f, 0.4485f, 0.4616f, 0.4746f, 0.4874f, + 0.5000f, 0.5124f, 0.5246f, 0.5365f, 0.5482f, 0.5597f, 0.5710f, + 0.5820f, 0.5928f, 0.6033f, 0.6136f, 0.6237f, 0.6335f, 0.6431f, + 0.6525f, 0.6616f, 0.6706f, 0.6793f, 0.6878f, 0.6961f, 0.7043f, + 0.7122f, 0.7199f, 0.7275f, 0.7349f, 0.7421f, 0.7491f, 0.7559f, + 0.7626f, 0.7692f, 0.7756f, 0.7818f, 0.7879f, 0.7938f, 0.7996f, + 0.8053f, 0.8108f, 0.8162f, 0.8215f, 0.8266f, 0.8317f, 0.8366f, + 0.8414f, 0.8461f, 0.8507f, 0.8551f, 0.8595f, 0.8638f, 0.8679f, + 0.8720f, 0.8760f, 0.8798f, 0.8836f, 0.8873f, 0.8909f, 0.8945f, + 0.8979f, 0.9013f, 0.9046f, 0.9078f, 0.9109f, 0.9139f, 0.9169f, + 0.9198f, 0.9227f, 0.9254f, 0.9281f, 0.9307f, 0.9333f, 0.9358f, + 0.9382f, 0.9406f, 0.9429f, 0.9452f, 0.9474f, 0.9495f, 0.9516f, + 0.9536f, 0.9556f, 0.9575f, 0.9594f, 0.9612f, 0.9629f, 0.9646f, + 0.9663f, 0.9679f, 0.9695f, 0.9710f, 0.9725f, 0.9739f, 0.9753f, + 0.9766f, 0.9779f, 0.9791f, 0.9803f, 0.9815f, 0.9826f, 0.9837f, + 0.9848f, 0.9858f, 0.9867f, 0.9877f, 0.9885f, 0.9894f, 0.9902f, + 0.9910f, 0.9917f, 0.9924f, 0.9931f, 0.9937f, 0.9944f, 0.9949f, + 0.9955f, 0.9960f, 0.9964f, 0.9969f, 0.9973f, 0.9977f, 0.9980f, + 0.9984f, 0.9986f, 0.9989f, 0.9991f, 0.9993f, 0.9995f, 0.9997f, + 0.9998f, 0.9999f, 0.9999f, 1.0000f, 1.0000f + }; + + public FastOutSlowInInterpolator() { + super(VALUES); + } + +} diff --git a/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/util/LookupTableInterpolator.java b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/util/LookupTableInterpolator.java new file mode 100644 index 00000000..56c3d560 --- /dev/null +++ b/app/src/main/java/sk/styk/martin/apkanalyzer/ui/expandableLayout/util/LookupTableInterpolator.java @@ -0,0 +1,58 @@ +package sk.styk.martin.apkanalyzer.ui.expandableLayout.util; + +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import android.view.animation.Interpolator; + +/** + * An {@link Interpolator} that uses a lookup table to compute an interpolation based on a + * given input. + */ +abstract class LookupTableInterpolator implements Interpolator { + + private final float[] mValues; + private final float mStepSize; + + public LookupTableInterpolator(float[] values) { + mValues = values; + mStepSize = 1f / (mValues.length - 1); + } + + @Override + public float getInterpolation(float input) { + if (input >= 1.0f) { + return 1.0f; + } + if (input <= 0f) { + return 0f; + } + + // Calculate index - We use min with length - 2 to avoid IndexOutOfBoundsException when + // we lerp (linearly interpolate) in the return statement + int position = Math.min((int) (input * (mValues.length - 1)), mValues.length - 2); + + // Calculate values to account for small offsets as the lookup table has discrete values + float quantized = position * mStepSize; + float diff = input - quantized; + float weight = diff / mStepSize; + + // Linearly interpolate between the table values + return mValues[position] + weight * (mValues[position + 1] - mValues[position]); + } + +} diff --git a/app/src/main/res/layout/fragment_statistics.xml b/app/src/main/res/layout/fragment_statistics.xml index 2f9db927..1ab8cff0 100644 --- a/app/src/main/res/layout/fragment_statistics.xml +++ b/app/src/main/res/layout/fragment_statistics.xml @@ -95,7 +95,7 @@ - - + @@ -174,7 +174,7 @@ - - + @@ -233,7 +233,7 @@ - - + @@ -291,7 +291,7 @@ - - + @@ -349,7 +349,7 @@ - - + @@ -407,7 +407,7 @@ - - + diff --git a/app/src/main/res/layout/list_item_activity_detail_expanded.xml b/app/src/main/res/layout/list_item_activity_detail_expanded.xml index 064ce766..ff4e5f0a 100644 --- a/app/src/main/res/layout/list_item_activity_detail_expanded.xml +++ b/app/src/main/res/layout/list_item_activity_detail_expanded.xml @@ -13,7 +13,7 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_provider_detail_expanded.xml b/app/src/main/res/layout/list_item_provider_detail_expanded.xml index dce18373..867264a8 100644 --- a/app/src/main/res/layout/list_item_provider_detail_expanded.xml +++ b/app/src/main/res/layout/list_item_provider_detail_expanded.xml @@ -12,7 +12,7 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_receiver_detail_expanded.xml b/app/src/main/res/layout/list_item_receiver_detail_expanded.xml index a36287e8..36ca95b4 100644 --- a/app/src/main/res/layout/list_item_receiver_detail_expanded.xml +++ b/app/src/main/res/layout/list_item_receiver_detail_expanded.xml @@ -10,7 +10,7 @@ type="sk.styk.martin.apkanalyzer.ui.appdetail.page.provider.AppReceiverDetailListAdapter.ReceiverDataViewModel" /> - - + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_service_detail_expanded.xml b/app/src/main/res/layout/list_item_service_detail_expanded.xml index 1e5dbc8b..c49a9d2c 100644 --- a/app/src/main/res/layout/list_item_service_detail_expanded.xml +++ b/app/src/main/res/layout/list_item_service_detail_expanded.xml @@ -12,7 +12,7 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/layout/view_math_statistics_card.xml b/app/src/main/res/layout/view_math_statistics_card.xml index efcdfed6..6b21004d 100644 --- a/app/src/main/res/layout/view_math_statistics_card.xml +++ b/app/src/main/res/layout/view_math_statistics_card.xml @@ -33,7 +33,7 @@ - - + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 367dd062..35c3ab96 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -30,4 +30,11 @@ + + + + + + + \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/sk/styk/martin/apkanalyzer/AndroidSdk.kt b/build-logic/convention/src/main/kotlin/sk/styk/martin/apkanalyzer/AndroidSdk.kt index 82ee0c7f..6ec9326a 100644 --- a/build-logic/convention/src/main/kotlin/sk/styk/martin/apkanalyzer/AndroidSdk.kt +++ b/build-logic/convention/src/main/kotlin/sk/styk/martin/apkanalyzer/AndroidSdk.kt @@ -1,4 +1,4 @@ package sk.styk.martin.apkanalyzer -const val TargetSdk = 34 +const val TargetSdk = 35 const val MinSdk = 21 \ No newline at end of file diff --git a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AndroidManifestManager.kt b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AndroidManifestManager.kt index a6f2a532..0958ed7c 100644 --- a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AndroidManifestManager.kt +++ b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AndroidManifestManager.kt @@ -28,7 +28,7 @@ class AndroidManifestManager @Inject constructor(private val packageManager: Pac packageManager.getResourcesForApplication(packageName) } catch (exception: PackageManager.NameNotFoundException) { packageManager.getPackageArchiveInfo(packagePath, 0)?.let { - packageManager.getResourcesForApplication(it.applicationInfo) + it.applicationInfo?.let { it1 -> packageManager.getResourcesForApplication(it1) } } } diff --git a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppGeneralDataManager.kt b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppGeneralDataManager.kt index 9d403e9a..b21dea9f 100644 --- a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppGeneralDataManager.kt +++ b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppGeneralDataManager.kt @@ -25,35 +25,35 @@ class AppGeneralDataManager @Inject constructor( fun get(packageInfo: PackageInfo, analysisMode: AnalysisMode): GeneralData { val applicationInfo = packageInfo.applicationInfo - val minSdk = getMinSdk(applicationInfo, analysisMode) + val minSdk = applicationInfo?.let { getMinSdk(it, analysisMode) } return GeneralData( packageName = packageInfo.packageName, - applicationName = applicationInfo.loadLabel(packageManager).toString(), - processName = applicationInfo.processName, + applicationName = applicationInfo?.loadLabel(packageManager).toString(), + processName = applicationInfo?.processName, versionName = packageInfo.versionName, versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) packageInfo.longVersionCode else packageInfo.versionCode.toLong(), isSystemApp = appInstallSourceManager.isSystemInstalledApp(packageInfo), - uid = applicationInfo.uid, - description = applicationInfo.loadDescription(packageManager)?.toString(), - apkDirectory = applicationInfo.sourceDir, - dataDirectory = applicationInfo.dataDir, + uid = applicationInfo?.uid?.toInt() ?: 0, + description = applicationInfo?.loadDescription(packageManager)?.toString(), + apkDirectory = applicationInfo?.sourceDir.toString(), + dataDirectory = applicationInfo?.dataDir, source = appInstallSourceManager.getAppInstallSource(packageInfo), appInstaller = appInstallSourceManager.appInstallingPackage(packageInfo), installLocation = InstallLocation.from(packageInfo.installLocation), - apkSize = computeApkSize(applicationInfo.sourceDir), + apkSize = computeApkSize(applicationInfo?.sourceDir.toString()), firstInstallTime = if (packageInfo.firstInstallTime > 0) packageInfo.firstInstallTime else null, lastUpdateTime = if (packageInfo.lastUpdateTime > 0) packageInfo.lastUpdateTime else null, minSdkVersion = minSdk, minSdkLabel = androidVersionManager.resolveVersion(minSdk), - targetSdkVersion = applicationInfo.targetSdkVersion, - targetSdkLabel = androidVersionManager.resolveVersion(applicationInfo.targetSdkVersion), + targetSdkVersion = applicationInfo?.targetSdkVersion?:35, + targetSdkLabel = androidVersionManager.resolveVersion(applicationInfo?.targetSdkVersion), - icon = applicationInfo.loadIcon(packageManager), + icon = applicationInfo?.loadIcon(packageManager), ) } diff --git a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppInstallSourceManager.kt b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppInstallSourceManager.kt index fd747ddc..9a7b3522 100644 --- a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppInstallSourceManager.kt +++ b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppInstallSourceManager.kt @@ -36,6 +36,6 @@ class AppInstallSourceManager @Inject constructor(private val packageManager: Pa } fun isSystemInstalledApp(packageInfo: PackageInfo): Boolean { - return (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0 + return (packageInfo.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM)) != 0 } } \ No newline at end of file diff --git a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppPermissionManager.kt b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppPermissionManager.kt index 16c6bc8e..d0b85c52 100644 --- a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppPermissionManager.kt +++ b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/AppPermissionManager.kt @@ -42,7 +42,7 @@ class AppPermissionManager @Inject internal constructor(private val packageManag val requestedPermissions: MutableList = ArrayList(requestedPermissionNames.size) requestedPermissionNames.forEachIndexed { index, name -> - val isGranted = (requestedPermissionFlags[index] and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0) + val isGranted = ((requestedPermissionFlags?.get(index) ?: 0) and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0) val permissionData = try { diff --git a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/CertificateManager.kt b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/CertificateManager.kt index 16052106..349ba0f0 100644 --- a/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/CertificateManager.kt +++ b/core/app-analysis-core/src/main/java/sk/styk/martin/apkanalyzer/core/appanalysis/CertificateManager.kt @@ -15,7 +15,7 @@ import javax.security.auth.x500.X500Principal.RFC1779 class CertificateManager @Inject internal constructor(private val digestManager: DigestManager) { fun getCertificateData(packageInfo: PackageInfo): CertificateData { - val signature = packageInfo.signatures[0] ?: throw IllegalStateException("No signature") + val signature = packageInfo.signatures!!?.get(0) ?: throw IllegalStateException("No signature") return ByteArrayInputStream(signature.toByteArray()).use { val certFactory = CertificateFactory.getInstance("X509") @@ -43,9 +43,9 @@ class CertificateManager @Inject internal constructor(private val digestManager: } fun getSignAlgorithm(packageInfo: PackageInfo): String? { - val signature = packageInfo.signatures[0] + val signature = packageInfo.signatures?.get(0) - ByteArrayInputStream(signature.toByteArray()).use { + ByteArrayInputStream(signature?.toByteArray()).use { try { val certFactory = CertificateFactory.getInstance("X509") val certificate = certFactory.generateCertificate(it) as X509Certificate diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7abbcfc4..a091fe47 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,10 +1,10 @@ [versions] -kotlin = "1.9.20" -gradle-plugin = "8.4.0" -hilt = "2.46.1" -lifecycle = "2.8.0" -coroutines = "1.7.3" -androidx-appcompat = "1.6.1" +kotlin = "2.0.21" +gradle-plugin = "8.4.2" +hilt = "2.51" +lifecycle = "2.8.7" +coroutines = "1.8.0" +androidx-appcompat = "1.7.0" material = "1.12.0" glide = "4.15.1" spotless = "6.19.0" @@ -25,36 +25,37 @@ androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "a androidx-legacy = "androidx.legacy:legacy-support-v4:1.0.0" androidx-multidex = "androidx.multidex:multidex:2.0.1" -fragment-ktx = "androidx.fragment:fragment-ktx:1.7.1" +fragment-ktx = "androidx.fragment:fragment-ktx:1.8.6" preference-ktx = "androidx.preference:preference-ktx:1.2.1" palette-ktx = "androidx.palette:palette-ktx:1.0.0" -constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" -recyclerview = "androidx.recyclerview:recyclerview:1.3.2" +constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.0" +recyclerview = "androidx.recyclerview:recyclerview:1.4.0" cardview = "androidx.cardview:cardview:1.0.0" mp-chart = "com.github.PhilJay:MPAndroidChart:v3.1.0-alpha" gif-drawable = "pl.droidsonroids.gif:android-gif-drawable:1.2.25" highlightjs = "com.pddstudio:highlightjs-android:1.5.0" appintro = "com.github.AppIntro:AppIntro:6.1.0" -expandablelayout = "net.cachapa.expandablelayout:expandablelayout:2.9.2" +#expandablelayout = "net.cachapa.expandablelayout:expandablelayout:2.9.2" timber = "com.jakewharton.timber:timber:5.0.1" glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" } +#noinspection RiskyLibrary google-play-core = "com.google.android.play:core:1.10.3" google-play-core-ktx = "com.google.android.play:core-ktx:1.8.1" hilt = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } hilt-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" } -firebase-bom = "com.google.firebase:firebase-bom:33.0.0" +firebase-bom = "com.google.firebase:firebase-bom:33.9.0" firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" } firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics-ktx" } firebase-performance = { group = "com.google.firebase", name = "firebase-perf-ktx" } leakcannary = "com.squareup.leakcanary:leakcanary-android:2.9.1" junit = "junit:junit:4.13.2" -espresso-core = "androidx.test.espresso:espresso-core:3.5.1" +espresso-core = "androidx.test.espresso:espresso-core:3.6.1" # Dependencies of the included build-logic android-gradle-plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "gradle-plugin" } @@ -66,9 +67,9 @@ android-application = { id = "com.android.application", version.ref = "gradle-pl android-library = { id = "com.android.library", version.ref = "gradle-plugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } -crashlytics = "com.google.firebase.crashlytics:3.0.1" +crashlytics = "com.google.firebase.crashlytics:3.0.3" firebase-perf = "com.google.firebase.firebase-perf:1.4.2" -google-services = "com.google.gms.google-services:4.4.1" +google-services = "com.google.gms.google-services:4.4.2" spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } dependency-updates = "com.github.ben-manes.versions:0.46.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3d753093..a088562d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Apr 17 20:31:51 CEST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME