8000 Allow using lottie files for splashscreen (SDL2 bootstrap) (#2296) · ginolv/python-for-android@524d621 · GitHub
[go: up one dir, main page]

Skip to content

Commit 524d621

Browse files
authored
Allow using lottie files for splashscreen (SDL2 bootstrap) (kivy#2296)
- add `--presplash-lottie` option to `build` command allowing to pass a json file - add lottie to build.gradle if necessary - use an xml layout file to define the view (added/removed appropriately by build.py) - rework PythonActivity to select appropriate view at startup
1 parent 0c7efcd commit 524d621

File tree

5 files changed

+138
-56
lines changed

5 files changed

+138
-56
lines changed

doc/source/buildoptions.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ options (this list may not be exhaustive):
7474
the application is loading.
7575
- ``--presplash-color``: The presplash screen background color, of the
7676
form ``#RRGGBB`` or a color name ``red``, ``green``, ``blue`` etc.
77+
- ``--presplash-lottie``: use a lottie (json) file as a presplash animation. If
78+
used, this will replace the static presplash image.
7779
- ``--wakelock``: If the argument is included, the application will
7880
prevent the device from sleeping.
7981
- ``--window``: If the argument is included, the application will not

pythonforandroid/bootstraps/common/build/build.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,28 @@ def make_package(args):
326326
args.icon or default_icon,
327327
join(res_dir, 'drawable/icon.png')
328328
)
329+
329330
if get_bootstrap_name() != "service_only":
330-
shutil.copy(
331-
args.presplash or default_presplash,
332-
join(res_dir, 'drawable/presplash.jpg')
333-
)
331+
lottie_splashscreen = join(res_dir, 'raw/splashscreen.json')
332+
if args.presplash_lottie:
333+
shutil.copy(
334+
'templates/lottie.xml',
335+
join(res_dir, 'layout/lottie.xml')
336+
)
337+
ensure_dir(join(res_dir, 'raw'))
338+
shutil.copy(
339+
args.presplash_lottie,
340+
join(res_dir, 'raw/splashscreen.json')
341+
)
342+
else:
343+
if exists(lottie_splashscreen):
344+
remove(lottie_splashscreen)
345+
remove(join(res_dir, 'layout/lottie.xml'))
346+
347+
shutil.copy(
348+
args.presplash or default_presplash,
349+
join(res_dir, 'drawable/presplash.jpg')
350+
)
334351

335352
# If extra Java jars were requested, copy them into the libs directory
336353
jars = []
@@ -623,6 +640,9 @@ def parse_args_and_make_package(args=None):
623640
ap.add_argument('--presplash', dest='presplash',
624641
help=('A jpeg file to use as a screen while the '
625642
'application is loading.'))
643+
ap.add_argument('--presplash-lottie', dest='presplash_lottie',
644+
help=('A lottie (json) file to use as an animation while the '
645+
'application is loading.'))
626646
ap.add_argument('--presplash-color',
627647
dest='presplash_color',
628648
default='#000000',

pythonforandroid/bootstraps/common/build/templates/build.tmpl.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,7 @@ dependencies {
109109
compile '{{ depend }}'
110110
{%- endfor %}
111111
{%- endif %}
112+
{% if args.presplash_lottie %}
113+
implementation 'com.airbnb.android:lottie:3.4.0'
114+
{%- endif %}
112115
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:orientation="vertical"
6+
android:layout_width="fill_parent"
7+
android:layout_height="fill_parent"
8+
>
9+
10+
<com.airbnb.lottie.LottieAnimationView
11+
android:id="@+id/progressBar"
12+
android:layout_width="match_parent"
13+
android:layout_height="match_parent"
14+
android:layout_gravity="center"
15+
android:scaleType="centerInside"
16+
android:layout_weight="4"
17+
app:lottie_autoPlay="true"
18+
app:lottie_loop="true"
19+
app:lottie_rawRes="@raw/splashscreen"
20+
/>
21+
</LinearLayout>
22+

pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/PythonActivity.java

Lines changed: 87 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
import android.util.Log;
2828
import android.view.SurfaceView;
2929
import android.view.ViewGroup;
30+
import android.view.View;
3031
import android.widget.ImageView;
3132
import android.widget.Toast;
33+
import android.content.res.Resources.NotFoundException;
3234

3335
import org.libsdl.app.SDLActivity;
3436

@@ -61,7 +63,7 @@ protected void onCreate(Bundle savedInstanceState) {
6163
Log.v(TAG, "Did super onCreate");
6264

6365
this.mActivity = this;
64-
this.showLoadingScreen();
66+
this.showLoadingScreen(this.getLoadingScreen());
6567

6668
new UnpackFilesTask().execute(getAppRoot());
6769
}
@@ -121,7 +123,7 @@ protected void onPostExecute(String result) {
121123
// removed the loading screen. However, we still need it to
122124
// show until the app is ready to render, so pop it back up
123125
// on top of the SDL view.
124-
mActivity.showLoadingScreen();
126+
mActivity.showLoadingScreen(getLoadingScreen());
125127

126128
String app_root_dir = getAppRoot();
127129
if (getIntent() != null && getIntent().getAction() != null &&
@@ -338,6 +340,7 @@ public static void stop_service() {
338340

339341
/** Loading screen view **/
340342
public static ImageView mImageView = null;
343+
public static View mLottieView = null;
341344
/** Whether main routine/actual app has started yet **/
342345
protected boolean mAppConfirmedActive = false;
343346
/** Timer for delayed loading screen removal. **/
@@ -404,11 +407,11 @@ public void run() {
404407
public void removeLoadingScreen() {
405408
runOnUiThread(new Runnable() {
406409
public void run() {
407-
if (PythonActivity.mImageView != null &&
408-
PythonActivity.mImageView.getParent() != null) {
409-
((ViewGroup)PythonActivity.mImageView.getParent()).removeView(
410-
PythonActivity.mImageView);
411-
PythonActivity.mImageView = null;
410+
View view = mLottieView != null ? mLottieView : mImageView;
411+
if (view != null && view.getParent() != null) {
412+
((ViewGroup)view.getParent()).removeView(view);
413+
mLottieView = null;
414+
mImageView = null;
412415
}
413416
}
414417
});
@@ -430,65 +433,97 @@ public String getEntryPoint(String search_dir) {
430433
return "main.py";
431434
}
432435

433-
protected void showLoadingScreen() {
436+
protected void showLoadingScreen(View view) {
437+
try {
438+
if (mLayout == null) {
439+
setContentView(view);
440+
} else if (view.getParent() == null) {
441+
mLayout.addView(view);
442+
}
443+
} catch (IllegalStateException e) {
444+
// The loading screen can be attempted to be applied twice if app
445+
// is tabbed in/out, quickly.
446+
// (Gives error "The specified child already has a parent.
447+
// You must call removeView() on the child's parent first.")
448+
}
449+
}
450+
451+
protected View getLoadingScreen() {
434452
// load the bitmap
435453
// 1. if the image is valid and we don't have layout yet, assign this bitmap
436454
// as main view.
437455
// 2. if we have a layout, just set it in the layout.
438456
// 3. If we have an mImageView already, then do nothing because it will have
439457
// already been made the content view or added to the layout.
440458

441-
if (mImageView == null) {
442-
int presplashId = this.resourceManager.getIdentifier("presplash", "drawable");
443-
InputStream is = this.getResources().openRawResource(presplashId);
444-
Bitmap bitmap = null;
459+
if (mLottieView != null || mImageView != null) {
460+
// we already have a splash screen
461+
return mLottieView != null ? mLottieView : mImageView;
462+
}
463+
464+
// first try to load the lottie one
465+
try {
466+
mLottieView = getLayoutInflater().inflate(
467+
this.resourceManager.getIdentifier("lottie", "layout"),
468+
mLayout,
469+
false
470+
);
445471
try {
446-
bitmap = BitmapFactory.decodeStream(is);
447-
} finally {
448-
try {
449-
is.close();
450-
} catch (IOException e) {};
472+
if (mLayout == null) {
473+
setContentView(mLottieView);
474+
} else if (PythonActivity.mLottieView.getParent() == null) {
475+
mLayout.addView(mLottieView);
476+
}
477+
} catch (IllegalStateException e) {
478+
// The loading screen can be attempted to be applied twice if app
479+
// is tabbed in/out, quickly.
480+
// (Gives error "The specified child already has a parent.
481+
// You must call removeView() on the child's parent first.")
451482
}
452-
453-
mImageView = new ImageView(this);
454-
mImageView.setImageBitmap(bitmap);
455-
456-
/*
457-
* Set the presplash loading screen background color
458-
* https://developer.android.com/reference/android/graphics/Color.html
459-
* Parse the color string, and return the corresponding color-int.
460-
* If the string cannot be parsed, throws an IllegalArgumentException exception.
461-
* Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
462-
* 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta', 'yellow',
463-
* 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey', 'aqua', 'fuchsia',
464-
* 'lime', 'maroon', 'navy', 'olive', 'purple', 'silver', 'teal'.
465-
*/
466-
String backgroundColor = resourceManager.getString("presplash_color");
467-
if (backgroundColor != null) {
468-
try {
469-
mImageView.setBackgroundColor(Color.parseColor(backgroundColor));
470-
} catch (IllegalArgumentException e) {}
471-
}
472-
mImageView.setLayoutParams(new ViewGroup.LayoutParams(
473-
ViewGroup.LayoutParams.FILL_PARENT,
474-
ViewGroup.LayoutParams.FILL_PARENT));
475-
mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
483+
return mLottieView;
484+
}
485+
catch (NotFoundException e) {
486+
Log.v("SDL", "couldn't find lottie layout or animation, trying static splash");
476487
}
477488

489+
// try to load the static image then
490+
int presplashId = this.resourceManager.getIdentifier("presplash", "drawable");
491+
InputStream is = this.getResources().openRawResource(presplashId);
492+
Bitmap bitmap = null;
478493
try {
479-
if (mLayout == null) {
480-
setContentView(mImageView);
481-
} else if (PythonActivity.mImageView.getParent() == null) {
482-
mLayout.addView(mImageView);
483-
}
484-
} catch (IllegalStateException e) {
485-
// The loading screen can be attempted to be applied twice if app
486-
// is tabbed in/out, quickly.
487-
// (Gives error "The specified child already has a parent.
488-
// You must call removeView() on the child's parent first.")
494+
bitmap = BitmapFactory.decodeStream(is);
495+
} finally {
496+
try {
497+
is.close();
498+
} catch (IOException e) {};
489499
}
500+
501+
mImageView = new ImageView(this);
502+
mImageView.setImageBitmap(bitmap);
503+
504+
/*
505+
* Set the presplash loading screen background color
506+
* https://developer.android.com/reference/android/graphics/Color.html
507+
* Parse the color string, and return the corresponding color-int.
508+
* If the string cannot be parsed, throws an IllegalArgumentException exception.
509+
* Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
510+
* 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta', 'yellow',
511+
* 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey', 'aqua', 'fuchsia',
512+
* 'lime', 'maroon', 'navy', 'olive', 'purple', 'silver', 'teal'.
513+
*/
514+
String backgroundColor = resourceManager.getString("presplash_color");
515+
if (backgroundColor != null) {
516+
try {
517+
mImageView.setBackgroundColor(Color.parseColor(backgroundColor));
518+
} catch (IllegalArgumentException e) {}
519+
}
520+
mImageView.setLayoutParams(new ViewGroup.LayoutParams(
521+
ViewGroup.LayoutParams.FILL_PARENT,
522+
ViewGroup.LayoutParams.FILL_PARENT));
523+
mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
524+
return mImageView;
490525
}
491-
526+
492527
@Override
493528
protected void onPause() {
494529
if (this.mWakeLock != null && mWakeLock.isHeld()) {

0 commit comments

Comments
 (0)
0