diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 7c04c19..2179826 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -3,6 +3,9 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index 5d19981..a5ce8ce 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,36 +8,41 @@ - - - - - - - - - - - + diff --git a/Spotlight-library/build.gradle b/Spotlight-library/build.gradle index 6eb714e..4d6ab6e 100644 --- a/Spotlight-library/build.gradle +++ b/Spotlight-library/build.gradle @@ -1,16 +1,15 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 - buildToolsVersion "23.0.3" + compileSdkVersion 29 defaultConfig { - minSdkVersion 11 - targetSdkVersion 23 + minSdkVersion 14 + targetSdkVersion 29 versionCode 1 versionName "1.0" vectorDrawables.useSupportLibrary = true - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -23,9 +22,6 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.4.0' - testCompile 'junit:junit:4.12' - androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' - androidTestCompile 'com.android.support.test:runner:0.5' - androidTestCompile 'com.android.support:support-annotations:23.4.0' + compile 'androidx.appcompat:appcompat:1.0.0' + } diff --git a/Spotlight-library/src/main/java/com/wooplr/spotlight/SpotlightView.java b/Spotlight-library/src/main/java/com/wooplr/spotlight/SpotlightView.java index 3cb3d48..492d98b 100755 --- a/Spotlight-library/src/main/java/com/wooplr/spotlight/SpotlightView.java +++ b/Spotlight-library/src/main/java/com/wooplr/spotlight/SpotlightView.java @@ -17,10 +17,6 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; -import android.support.annotation.Nullable; -import android.support.graphics.drawable.AnimatedVectorDrawableCompat; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -30,12 +26,18 @@ import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; +import android.view.Window; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; +import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; + import com.wooplr.spotlight.prefs.PreferencesManager; import com.wooplr.spotlight.shape.Circle; import com.wooplr.spotlight.shape.NormalLineAnimDrawable; @@ -185,7 +187,7 @@ public class SpotlightView extends FrameLayout { private Typeface mTypeface = null; private int softwareBtnHeight; - + private boolean dismissCalled = false; @@ -239,7 +241,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - try{ + try { if (!isReady) return; if (bitmap == null || canvas == null) { @@ -255,7 +257,7 @@ protected void onDraw(Canvas canvas) { circleShape.draw(this.canvas, eraser, padding); canvas.drawBitmap(bitmap, 0, 0, null); - }catch(Exception e){ + } catch (Exception e) { e.printStackTrace(); } } @@ -325,7 +327,7 @@ private void show(final Activity activity) { handler.postDelayed(new Runnable() { @Override public void run() { - try{ + try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (isRevealAnimationEnabled) @@ -336,7 +338,39 @@ public void run() { } else { startFadinAnimation(activity); } - }catch(Exception e){ + } catch (Exception e) { + e.printStackTrace(); + } + } + } + , 100); + + } + + private void show(final Activity activity, Window viewGroup) { + + if (preferencesManager.isDisplayed(usageId)) + return; + + ((ViewGroup) viewGroup.getDecorView()).addView(this); + + setReady(true); + + handler.postDelayed(new Runnable() { + @Override + public void run() { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + + if (isRevealAnimationEnabled) + startRevealAnimation(activity); + else { + startFadinAnimation(activity); + } + } else { + startFadinAnimation(activity); + } + } catch (Exception e) { e.printStackTrace(); } } @@ -353,7 +387,7 @@ private void dismiss() { return; } dismissCalled = true; - + preferencesManager.setDisplayed(usageId); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (isRevealAnimationEnabled) @@ -588,8 +622,8 @@ private void addPathAnimation(Activity activity) { if (mTypeface != null) headingTv.setTypeface(mTypeface); - if(headingTvSizeDimenUnit != -1) - headingTv.setTextSize(headingTvSizeDimenUnit,headingTvSize); + if (headingTvSizeDimenUnit != -1) + headingTv.setTextSize(headingTvSizeDimenUnit, headingTvSize); else headingTv.setTextSize(headingTvSize); @@ -601,8 +635,8 @@ private void addPathAnimation(Activity activity) { if (mTypeface != null) subHeadingTv.setTypeface(mTypeface); - if(subHeadingTvSizeDimenUnit != -1) - subHeadingTv.setTextSize(subHeadingTvSizeDimenUnit,subHeadingTvSize); + if (subHeadingTvSizeDimenUnit != -1) + subHeadingTv.setTextSize(subHeadingTvSizeDimenUnit, subHeadingTvSize); else subHeadingTv.setTextSize(subHeadingTvSize); @@ -650,7 +684,7 @@ public void onAnimationStart(Animation animation) { @Override public void onAnimationEnd(Animation animation) { - if(enableDismissAfterShown) + if (enableDismissAfterShown) dismissOnTouch = true; } @@ -748,7 +782,7 @@ private List checkLinePoint() { //TextViews - if(screenHeight > screenWidth) + if (screenHeight > screenWidth) headingParams.rightMargin = gutter;//portrait else headingParams.rightMargin = gutter + softwareBtnHeight;//landscape @@ -759,7 +793,7 @@ private List checkLinePoint() { headingTv.setGravity(Gravity.LEFT); - if(screenHeight > screenWidth) + if (screenHeight > screenWidth) subHeadingParams.rightMargin = gutter;//portrait else subHeadingParams.rightMargin = gutter + softwareBtnHeight;//landscape @@ -809,7 +843,7 @@ private List checkLinePoint() { (screenHeight - targetView.getViewBottom()) / 2 + targetView.getViewBottom())); // //TextViews - if(screenHeight > screenWidth) + if (screenHeight > screenWidth) headingParams.rightMargin = gutter;//portrait else headingParams.rightMargin = gutter + softwareBtnHeight;//landscape @@ -819,7 +853,7 @@ private List checkLinePoint() { headingParams.gravity = Gravity.BOTTOM | Gravity.RIGHT; headingTv.setGravity(Gravity.LEFT); - if(screenHeight > screenWidth) + if (screenHeight > screenWidth) subHeadingParams.rightMargin = gutter;//portrait else subHeadingParams.rightMargin = gutter + softwareBtnHeight;//landscape @@ -851,16 +885,17 @@ private void removeSpotlightView() { /** * Remove the spotlight view + * * @param needOnUserClickedCallback true, if user wants a call back when this spotlight view is removed from parent. */ public void removeSpotlightView(boolean needOnUserClickedCallback) { - try{ - if(needOnUserClickedCallback && listener != null) + try { + if (needOnUserClickedCallback && listener != null) listener.onUserClicked(usageId); if (getParent() != null) ((ViewGroup) getParent()).removeView(this); - }catch(Exception e){ + } catch (Exception e) { e.printStackTrace(); } } @@ -947,7 +982,7 @@ public void setHeadingTvSize(int headingTvSize) { this.headingTvSize = headingTvSize; } - public void setHeadingTvSize(int dimenUnit,int headingTvSize) { + public void setHeadingTvSize(int dimenUnit, int headingTvSize) { this.headingTvSizeDimenUnit = dimenUnit; this.headingTvSize = headingTvSize; } @@ -993,7 +1028,7 @@ public void setLineEffect(PathEffect pathEffect) { this.lineEffect = pathEffect; } - private void setSoftwareBtnHeight(int px){ + private void setSoftwareBtnHeight(int px) { this.softwareBtnHeight = px; } @@ -1111,7 +1146,7 @@ public Builder headingTvSize(int headingTvSize) { } public Builder headingTvSize(int dimenUnit, int headingTvSize) { - spotlightView.setHeadingTvSize(dimenUnit,headingTvSize); + spotlightView.setHeadingTvSize(dimenUnit, headingTvSize); return this; } @@ -1131,7 +1166,7 @@ public Builder subHeadingTvSize(int headingTvSize) { } public Builder subHeadingTvSize(int dimenUnit, int headingTvSize) { - spotlightView.setSubHeadingTvSize(dimenUnit,headingTvSize); + spotlightView.setSubHeadingTvSize(dimenUnit, headingTvSize); return this; } @@ -1199,6 +1234,11 @@ public SpotlightView show() { return spotlightView; } + public SpotlightView show(Window view) { + build().show(activity, view); + return spotlightView; + } + } @@ -1217,35 +1257,34 @@ public void logger(String s) { Log.d("Spotlight", s); } - private int getViewHeight(){ - if(getWidth() > getHeight()){ + private int getViewHeight() { + if (getWidth() > getHeight()) { //Landscape return getHeight(); - }else{ + } else { //Portrait return (getHeight() - softwareBtnHeight); } } - private int getViewWidth(){ - if(getWidth() > getHeight()){ + private int getViewWidth() { + if (getWidth() > getHeight()) { //Landscape return (getWidth() - softwareBtnHeight); - }else{ + } else { //Portrait return getWidth(); } } private static int getSoftButtonsBarHeight(Activity activity) { - try{ + try { // getRealMetrics is only available with API 17 and + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { DisplayMetrics metrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - if(metrics.heightPixels > metrics.widthPixels) - { + if (metrics.heightPixels > metrics.widthPixels) { //Portrait int usableHeight = metrics.heightPixels; activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); @@ -1254,7 +1293,7 @@ private static int getSoftButtonsBarHeight(Activity activity) { return realHeight - usableHeight; else return 0; - }else{ + } else { //Landscape int usableHeight = metrics.widthPixels; activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); @@ -1265,7 +1304,7 @@ private static int getSoftButtonsBarHeight(Activity activity) { return 0; } } - }catch(Exception e){ + } catch (Exception e) { e.printStackTrace(); } return 0; @@ -1274,22 +1313,23 @@ private static int getSoftButtonsBarHeight(Activity activity) { /** * This will remove all usage ids from preferences. */ - public void resetAllUsageIds(){ - try{ + public void resetAllUsageIds() { + try { preferencesManager.resetAll(); - }catch(Exception e){ + } catch (Exception e) { e.printStackTrace(); } } /** * This will remove given usage id from preferences. + * * @param id Spotlight usage id to be removed */ - public void resetUsageId(String id){ - try{ + public void resetUsageId(String id) { + try { preferencesManager.reset(id); - }catch(Exception e){ + } catch (Exception e) { e.printStackTrace(); } } diff --git a/Spotlight-library/src/main/java/com/wooplr/spotlight/shape/NormalLineAnimDrawable.java b/Spotlight-library/src/main/java/com/wooplr/spotlight/shape/NormalLineAnimDrawable.java index 2177100..b7bbe56 100755 --- a/Spotlight-library/src/main/java/com/wooplr/spotlight/shape/NormalLineAnimDrawable.java +++ b/Spotlight-library/src/main/java/com/wooplr/spotlight/shape/NormalLineAnimDrawable.java @@ -10,7 +10,9 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; + + +import androidx.annotation.NonNull; import com.wooplr.spotlight.target.AnimPoint; diff --git a/Spotlight-library/src/main/java/com/wooplr/spotlight/utils/SpotlightSequence.java b/Spotlight-library/src/main/java/com/wooplr/spotlight/utils/SpotlightSequence.java index dd0627f..195489a 100644 --- a/Spotlight-library/src/main/java/com/wooplr/spotlight/utils/SpotlightSequence.java +++ b/Spotlight-library/src/main/java/com/wooplr/spotlight/utils/SpotlightSequence.java @@ -7,10 +7,12 @@ import android.app.Activity; import android.content.Context; import android.graphics.Color; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.Log; import android.view.View; +import android.view.Window; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.wooplr.spotlight.SpotlightConfig; import com.wooplr.spotlight.SpotlightView; @@ -27,6 +29,7 @@ public class SpotlightSequence { private Activity activity; private SpotlightConfig config; + private Window window; private Queue queue; private static SpotlightSequence instance; @@ -35,38 +38,51 @@ public class SpotlightSequence { /** * Creates an instance of SpotlightSequence * with an empty queue and a {@link SpotlightConfig} configuration + * * @param activity where this sequence will be executed - * @param config {@link SpotlightConfig} + * @param config {@link SpotlightConfig} */ - private SpotlightSequence(Activity activity, SpotlightConfig config){ - Log.d(TAG,"NEW TOUR_SEQUENCE INSTANCE"); + private SpotlightSequence(Activity activity, SpotlightConfig config) { + Log.d(TAG, "NEW TOUR_SEQUENCE INSTANCE"); this.activity = activity; setConfig(config); queue = new LinkedList<>(); } + /** + * Add window token + * + * @param window where this sequence will be executed + */ + public SpotlightSequence toWindow(Window window) { + this.window = window; + return instance; + } + /** * Retriebes the current instance of SpotlightSequence + * * @param activity where this sequence will be executed - * @param config {@link SpotlightConfig} + * @param config {@link SpotlightConfig} * @return If no instance was found. {@link SpotlightSequence()} will be called. */ - public static SpotlightSequence getInstance(Activity activity, SpotlightConfig config){ - if(instance == null){ - instance = new SpotlightSequence(activity,config); + public static SpotlightSequence getInstance(Activity activity, SpotlightConfig config) { + if (instance == null) { + instance = new SpotlightSequence(activity, config); } return instance; } /** * Adds a new SpotlightView.Builder object to {@link this.queue} - * @param target View where the spotlight will focus - * @param title Spotlight title + * + * @param target View where the spotlight will focus + * @param title Spotlight title * @param subtitle Spotlight subtitle * * @param usageId id used to store the SpotlightView in {@link PreferencesManager} * @return SpotlightSequence instance */ - public SpotlightSequence addSpotlight(View target, String title, String subtitle, String usageId){ + public SpotlightSequence addSpotlight(View target, String title, String subtitle, String usageId) { Log.d(TAG, "Adding " + usageId); SpotlightView.Builder builder = new SpotlightView.Builder(activity) .setConfiguration(config) @@ -87,13 +103,14 @@ public void onUserClicked(String s) { /** * Adds a new SpotlightView.Builder object to {@link this.queue} - * @param target View where the spotlight will focus - * @param titleResId Spotlight title + * + * @param target View where the spotlight will focus + * @param titleResId Spotlight title * @param subTitleResId Spotlight subtitle - * @param usageId id used to store the SpotlightView in {@link PreferencesManager} + * @param usageId id used to store the SpotlightView in {@link PreferencesManager} * @return SpotlightSequence instance */ - public SpotlightSequence addSpotlight(@NonNull View target, int titleResId, int subTitleResId, String usageId){ + public SpotlightSequence addSpotlight(@NonNull View target, int titleResId, int subTitleResId, String usageId) { String title = activity.getString(titleResId); String subtitle = activity.getString(subTitleResId); SpotlightView.Builder builder = new SpotlightView.Builder(activity) @@ -116,14 +133,18 @@ public void onUserClicked(String s) { /** * Starts the sequence. */ - public void startSequence(){ - if(queue.isEmpty()) { + public void startSequence() { + if (queue.isEmpty()) { Log.d(TAG, "EMPTY SEQUENCE"); - }else{ - queue.poll().show(); + } else { + if (window != null) + queue.poll().show(window); + else + queue.poll().show(); } } + /** * Free variables. Executed when the tour has finished */ @@ -138,13 +159,17 @@ private void resetTour() { * Executes the next Spotlight animation in the queue. * If no more animations are found, resetTour()is called. */ - private void playNext(){ + private void playNext() { SpotlightView.Builder next = queue.poll(); - if(next != null){ + if (next != null) { // Log.d(TAG,"PLAYING NEXT SPOTLIGHT"); - next.show().setReady(true); + if (window != null) { + next.show(window).setReady(true); + } else { + next.show().setReady(true); + } - }else { + } else { Log.d(TAG, "END OF QUEUE"); resetTour(); } @@ -152,9 +177,10 @@ private void playNext(){ /** * Clear all Spotlights usageId from shared preferences. + * * @param context */ - public static void resetSpotlights(@NonNull Context context){ + public static void resetSpotlights(@NonNull Context context) { new PreferencesManager(context).resetAll(); } @@ -162,14 +188,15 @@ public static void resetSpotlights(@NonNull Context context){ * Sets the specified {@link SpotlightConfig} configuration * as the configuration to use. * If no configuration is specified, the default configuration is used. + * * @param config {@link SpotlightConfig} */ private void setConfig(@Nullable SpotlightConfig config) { - if(config == null){ + if (config == null) { config = new SpotlightConfig(); config.setLineAndArcColor(Color.parseColor("#eb273f")); config.setDismissOnTouch(true); - config.setMaskColor(Color.argb(240,0,0,0)); + config.setMaskColor(Color.argb(240, 0, 0, 0)); config.setHeadingTvColor(Color.parseColor("#eb273f")); config.setHeadingTvSize(32); config.setSubHeadingTvSize(16); diff --git a/app/build.gradle b/app/build.gradle index c6ff6a1..8c45aef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,16 +1,15 @@ apply plugin: 'com.android.application' -apply plugin: 'android-apt' + android { - compileSdkVersion 23 - buildToolsVersion "23.0.3" + compileSdkVersion 29 defaultConfig { applicationId "com.example.spotlight" - minSdkVersion 11 - targetSdkVersion 23 + minSdkVersion 14 + targetSdkVersion 29 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -18,17 +17,17 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - compile project(':Spotlight-library') - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.4.0' - compile 'com.android.support:design:23.4.0' - compile 'com.jakewharton:butterknife:8.0.1' - apt 'com.jakewharton:butterknife-compiler:8.0.1' - testCompile 'junit:junit:4.12' - androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' - androidTestCompile 'com.android.support.test:runner:0.5' - androidTestCompile 'com.android.support:support-annotations:23.4.0' + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'com.google.android.material:material:1.0.0' + implementation 'com.jakewharton:butterknife:10.1.0' + implementation 'androidx.annotation:annotation:1.1.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0' + implementation project(path: ':Spotlight-library') } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6276386..fbcca9f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ - @@ -7,7 +7,7 @@ - - + diff --git a/app/src/main/res/layout/bottom_sheet.xml b/app/src/main/res/layout/bottom_sheet.xml new file mode 100644 index 0000000..1931d92 --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet.xml @@ -0,0 +1,25 @@ + + + +