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