diff --git a/.github/workflows/copy-branch.yml b/.github/workflows/copy-branch.yml new file mode 100644 index 00000000..f8f8572d --- /dev/null +++ b/.github/workflows/copy-branch.yml @@ -0,0 +1,31 @@ +# Duplicates default main branch to the old master branch + +name: Duplicates main to old master branch + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the main branch +on: + push: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "copy-branch" + copy-branch: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it, + # but specifies master branch (old default). + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: master + + - run: | + git config user.name github-actions + git config user.email github-actions@github.com + git merge origin/main + git push diff --git a/AnimationsInterpolatorPlayground/build.gradle b/AnimationsInterpolatorPlayground/build.gradle index d7253487..05b5265d 100644 --- a/AnimationsInterpolatorPlayground/build.gradle +++ b/AnimationsInterpolatorPlayground/build.gradle @@ -3,10 +3,10 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -16,7 +16,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/AnimationsInterpolatorPlayground/gradle/wrapper/gradle-wrapper.properties b/AnimationsInterpolatorPlayground/gradle/wrapper/gradle-wrapper.properties index b47c75ba..d037e648 100644 --- a/AnimationsInterpolatorPlayground/gradle/wrapper/gradle-wrapper.properties +++ b/AnimationsInterpolatorPlayground/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/CardView/Application/build.gradle b/CardView/Application/build.gradle index 36284f56..ff2f5e33 100644 --- a/CardView/Application/build.gradle +++ b/CardView/Application/build.gradle @@ -2,11 +2,11 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:4.2.1' } } @@ -14,19 +14,11 @@ apply plugin: 'com.android.application' repositories { google() - jcenter() + mavenCentral() } dependencies { - - - - implementation 'com.android.support:cardview-v7:24.0.0' - - - - } // The sample build uses multiple directories to diff --git a/CardView/gradle/wrapper/gradle-wrapper.properties b/CardView/gradle/wrapper/gradle-wrapper.properties index c4486d47..1f3fdbc5 100644 --- a/CardView/gradle/wrapper/gradle-wrapper.properties +++ b/CardView/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/CardViewKotlin/build.gradle b/CardViewKotlin/build.gradle index 9870e4b4..77d53ba5 100644 --- a/CardViewKotlin/build.gradle +++ b/CardViewKotlin/build.gradle @@ -6,16 +6,16 @@ buildscript { espressoVersion = '3.0.1' junitVersion = '4.12' - kotlinVersion = '1.3.11' + kotlinVersion = '1.3.20' supportLibVersion = '27.0.2' supportTestVersion = '1.0.1' } repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:4.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } @@ -23,7 +23,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/CardViewKotlin/gradle/wrapper/gradle-wrapper.properties b/CardViewKotlin/gradle/wrapper/gradle-wrapper.properties index 8e7447f0..1f3fdbc5 100644 --- a/CardViewKotlin/gradle/wrapper/gradle-wrapper.properties +++ b/CardViewKotlin/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ConstraintLayoutExamples/README.md b/ConstraintLayoutExamples/README.md index 58d582f3..f22d4202 100644 --- a/ConstraintLayoutExamples/README.md +++ b/ConstraintLayoutExamples/README.md @@ -1,3 +1,11 @@ +> **Warning** +> This sample has been migraated to the new [platform-samples repository](https://github.com/android/platform-samples) +> and will no longer be maintained. +> +> Please use the following [sample](https://github.com/android/platform-samples/tree/main/samples/user-interface/constraintlayout) instead. +> +> Thank you for your understanding. + MotionLayout / Constraint Layout Samples ========================= This repository contains a list of layouts that showcases the various features and usage of diff --git a/ConstraintLayoutExamples/build.gradle b/ConstraintLayoutExamples/build.gradle index 03d67a32..6e30fe99 100644 --- a/ConstraintLayoutExamples/build.gradle +++ b/ConstraintLayoutExamples/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -19,25 +19,25 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } ext { compileSdkVersion = 28 targetSdkVersion = 28 - appCompatVersion = '1.1.0-alpha03' - constraintLayoutVersion = '2.0.0-beta3' + appCompatVersion = '1.3.0-alpha01' + constraintLayoutVersion = '2.0.1' glideVersion = '4.8.0' - kotlinVersion = '1.3.11' - lifeCycleVersion = '2.0.0' + kotlinVersion = '1.4.0' + lifeCycleVersion = '2.2.0' lottieVersion = '2.5.1' - materialVersion = '1.1.0-alpha05' + materialVersion = '1.3.0-alpha02' junitVersion = '4.12' } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.android.tools.build:gradle:4.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" // NOTE: Do not place your application dependencies here; they belong @@ -48,7 +48,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/ConstraintLayoutExamples/gradle.properties b/ConstraintLayoutExamples/gradle.properties index 9e6fce10..a07447ce 100644 --- a/ConstraintLayoutExamples/gradle.properties +++ b/ConstraintLayoutExamples/gradle.properties @@ -1,3 +1,19 @@ +# +# Copyright (C) 2020 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. +# + # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: diff --git a/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.jar b/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.jar index 13372aef..f6b961fd 100644 Binary files a/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.jar and b/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.properties b/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.properties index 692e90b1..01559123 100644 --- a/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.properties +++ b/ConstraintLayoutExamples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,22 @@ -#Tue Nov 19 18:33:58 JST 2019 +# +# Copyright (C) 2020 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. +# + +#Tue Jun 09 14:03:26 PDT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/ConstraintLayoutExamples/gradlew b/ConstraintLayoutExamples/gradlew index 9d82f789..cccdd3d5 100755 --- a/ConstraintLayoutExamples/gradlew +++ b/ConstraintLayoutExamples/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/ConstraintLayoutExamples/gradlew.bat b/ConstraintLayoutExamples/gradlew.bat old mode 100644 new mode 100755 index 8a0b282a..e95643d6 --- a/ConstraintLayoutExamples/gradlew.bat +++ b/ConstraintLayoutExamples/gradlew.bat @@ -1,90 +1,84 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ConstraintLayoutExamples/motionlayout/build.gradle b/ConstraintLayoutExamples/motionlayout/build.gradle index 175eaf0b..a212e22d 100644 --- a/ConstraintLayoutExamples/motionlayout/build.gradle +++ b/ConstraintLayoutExamples/motionlayout/build.gradle @@ -29,6 +29,7 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables.useSupportLibrary = true } buildTypes { release { diff --git a/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/utils/BoundsImageView.kt b/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/utils/BoundsImageView.kt index 700fc771..36058da5 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/utils/BoundsImageView.kt +++ b/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/utils/BoundsImageView.kt @@ -20,11 +20,11 @@ import android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.util.AttributeSet -import android.widget.ImageView +import androidx.appcompat.widget.AppCompatImageView class BoundsImageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : ImageView(context, attrs, defStyleAttr) { +) : AppCompatImageView(context, attrs, defStyleAttr) { private var paint = Paint() diff --git a/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/viewpagerdemo/ViewPagerActivity.kt b/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/viewpagerdemo/ViewPagerActivity.kt index de0c74ea..c0b51947 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/viewpagerdemo/ViewPagerActivity.kt +++ b/ConstraintLayoutExamples/motionlayout/src/main/java/com/google/androidstudio/motionlayoutexample/viewpagerdemo/ViewPagerActivity.kt @@ -19,8 +19,8 @@ package com.google.androidstudio.motionlayoutexample.viewpagerdemo import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.motion.widget.MotionLayout -import androidx.viewpager.widget.ViewPager import com.google.androidstudio.motionlayoutexample.R +import com.google.androidstudio.motionlayoutexample.utils.ViewpagerHeader import kotlinx.android.synthetic.main.motion_16_viewpager.* class ViewPagerActivity : AppCompatActivity() { @@ -29,7 +29,7 @@ class ViewPagerActivity : AppCompatActivity() { super.onCreate(savedInstanceState) val layout = R.layout.motion_16_viewpager setContentView(layout) - val motionLayout = findViewById(R.id.motionLayout) + val viewPagerHeader = findViewById(R.id.motionLayout) val adapter = ViewPagerAdapter(supportFragmentManager) adapter.addPage("Page 1", R.layout.motion_16_viewpager_page1) @@ -37,8 +37,8 @@ class ViewPagerActivity : AppCompatActivity() { adapter.addPage("Page 3", R.layout.motion_16_viewpager_page3) pager.adapter = adapter tabs.setupWithViewPager(pager) - if (motionLayout != null) { - pager.addOnPageChangeListener(motionLayout as ViewPager.OnPageChangeListener) + if (viewPagerHeader != null) { + pager.addOnPageChangeListener(viewPagerHeader) } val debugMode = if (intent.getBooleanExtra("showPaths", false)) { @@ -46,6 +46,6 @@ class ViewPagerActivity : AppCompatActivity() { } else { MotionLayout.DEBUG_SHOW_NONE } - motionLayout.setDebugMode(debugMode) + viewPagerHeader.setDebugMode(debugMode) } } \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_18_coordination.xml b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_18_coordination.xml index 9b60d664..fb65026f 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_18_coordination.xml +++ b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_18_coordination.xml @@ -26,6 +26,6 @@ android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/ic_add_a_photo_24dp"/> + app:srcCompat="@drawable/ic_add_a_photo_24dp"/> \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_19_coordination.xml b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_19_coordination.xml index 911cb54e..2d40c5f3 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_19_coordination.xml +++ b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_19_coordination.xml @@ -28,6 +28,6 @@ android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/ic_add_a_photo_24dp"/> + app:srcCompat="@drawable/ic_add_a_photo_24dp"/> \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_23_parallax.xml b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_23_parallax.xml index 27fc29b0..0521d690 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_23_parallax.xml +++ b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_23_parallax.xml @@ -4,7 +4,7 @@ android:id="@+id/motionLayout" app:layoutDescription="@xml/scene_23" android:layout_width="match_parent" - app:progress="0" + app:motionProgress="0" android:layout_height="230dp"> diff --git a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_26_multistate.xml b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_26_multistate.xml index 910fdda2..d3351c48 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_26_multistate.xml +++ b/ConstraintLayoutExamples/motionlayout/src/main/res/layout/motion_26_multistate.xml @@ -25,7 +25,7 @@ android:id="@+id/arrow_right" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/ic_keyboard_arrow_right" + app:srcCompat="@drawable/ic_keyboard_arrow_right" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -35,7 +35,7 @@ android:id="@+id/arrow_up" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/ic_keyboard_arrow_up" + app:srcCompat="@drawable/ic_keyboard_arrow_up" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" diff --git a/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_17.xml b/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_17.xml index 87bf4e92..448e9ba7 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_17.xml +++ b/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_17.xml @@ -48,7 +48,7 @@ android:layout_width="match_parent" android:layout_height="56dp" motion:layout_constraintTop_toTopOf="parent" - motion:progress="1" /> + motion:motionProgress="1" /> + motion:motionProgress="1" /> + motion:motionProgress="1" /> + motion:motionProgress="0"/> @@ -34,7 +34,7 @@ android:id="@id/animation_view" android:layout_width="match_parent" android:layout_height="match_parent" - motion:progress="1"/> + motion:motionProgress="1"/> diff --git a/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_25.xml b/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_25.xml index 7a77a031..7da68ea1 100644 --- a/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_25.xml +++ b/ConstraintLayoutExamples/motionlayout/src/main/res/xml/scene_25.xml @@ -68,7 +68,7 @@ android:layout_width="match_parent" android:layout_height="56dp" motion:layout_constraintTop_toTopOf="parent" - motion:progress="1" /> + motion:motionProgress="1" /> Animation is created by chaining multiple ConstraintSets + +| File | Content | +| ----------------------------------------------------------------------------------------- | -------------------------------------------------------------- | +| [Activity](src/main/java/com/example/androidstudio/motionlayoutintegrations/Entrance.kt) | Regular Activity (no extra code) | +| [layout](src/main/res/layout/activity_entrance.xml) | Layout all Views used in this animation | +| [scene](src/main/res/xml/activity_entrance_scene.xml) | Scene containing multiple ConstraintSet and Transition | + +## CollapsingToolbar +Build a collapsing toolbar with support for insets using MotionLayout. + +![Preview of Collapsing Toolbar animation](https://user-images.githubusercontent.com/119115/91504419-f0681680-e881-11ea-9143-fa3810c01abd.gif) + +This example shows a complex custom collapsing toolbar built using +MotionLayout. It shows how to use insets to set guidelines in a MotionLayout +to avoid drawing under cutouts and display an animated systembar underlay. + +It also shows how to integrate MotionLayout with a custom view which draws the +circular coutouts and animates the background. + +| File | Content | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| [Activity](src/main/java/com/example/androidstudio/motionlayoutintegrations/CollapsingToolbar.kt) | Integrate MotionLayout, CoordanatorLayout, and Custom View, and Insets | +| [layout](src/main/res/layout/activity_collapsing_toolbar.xml) | Layout all Views used in this animation, including inset guidelines & custom view | +| [scene](src/main/res/xml/activity_collapsing_toolbar_scene.xml) | Scene showing how to integrate with custom views using CustomAttribute | diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/build.gradle b/ConstraintLayoutExamples/motionlayoutintegrations/build.gradle new file mode 100644 index 00000000..d71ef69c --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/build.gradle @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 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. + */ + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 30 + buildToolsVersion "29.0.3" + + defaultConfig { + applicationId "com.example.androidstudio.motionlayoutintegrations" + minSdkVersion 18 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + buildFeatures { + viewBinding = true + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "androidx.appcompat:appcompat:$appCompatVersion" + implementation 'androidx.core:core-ktx:1.3.1' + implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" + testImplementation 'junit:junit:4.13' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + + implementation "com.google.android.material:material:$materialVersion" +} diff --git a/RecyclerViewKotlin/app/proguard-rules.pro b/ConstraintLayoutExamples/motionlayoutintegrations/proguard-rules.pro similarity index 100% rename from RecyclerViewKotlin/app/proguard-rules.pro rename to ConstraintLayoutExamples/motionlayoutintegrations/proguard-rules.pro diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/androidTest/java/com/example/androidstudio/motionlayoutintegrations/ExampleInstrumentedTest.kt b/ConstraintLayoutExamples/motionlayoutintegrations/src/androidTest/java/com/example/androidstudio/motionlayoutintegrations/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..5dacaa84 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/androidTest/java/com/example/androidstudio/motionlayoutintegrations/ExampleInstrumentedTest.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.androidstudio.motionlayoutintegrations + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.androidstudio.motionlayoutintegrations", appContext.packageName) + } +} diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/AndroidManifest.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/AndroidManifest.xml new file mode 100644 index 00000000..f3e9bc6a --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/AndroidManifest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/CollapsingToolbar.kt b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/CollapsingToolbar.kt new file mode 100644 index 00000000..e3bfe4af --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/CollapsingToolbar.kt @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.androidstudio.motionlayoutintegrations + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import android.os.Build +import android.os.Bundle +import android.util.AttributeSet +import android.util.TypedValue +import android.view.View +import android.view.Window +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import com.example.androidstudio.motionlayoutintegrations.databinding.ActivityCollapsingToolbarBinding +import com.google.android.material.appbar.AppBarLayout + +/** + * Display a collapsing toolbar built using MotionLayout that handles insets and uses a custom view + */ +class CollapsingToolbar : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + window.goEdgeToEdge() + + val binding = ActivityCollapsingToolbarBinding.inflate(layoutInflater) + setContentView(binding.root) + + // When the AppBarLayout progress changes, snap MotionLayout to the current progress + val listener = AppBarLayout.OnOffsetChangedListener { appBar, verticalOffset -> + // convert offset into % scrolled + val seekPosition = -verticalOffset / appBar.totalScrollRange.toFloat() + // inform both both MotionLayout and CutoutImage of the animation progress. + binding.motionLayout.progress = seekPosition + binding.background.translationProgress = (100 * seekPosition).toInt() + } + binding.appbarLayout.addOnOffsetChangedListener(listener) + + // get the collapsed height from the motion layout specified in XML + val desiredToolbarHeight = binding.motionLayout.minHeight + + // Set two guidelines in the collapsed state for displaying a scrim based on the inset. Also + // resize the MotionLayout when collapsed to add the inset height. + ViewCompat.setOnApplyWindowInsetsListener(binding.motionLayout) { _, insets: WindowInsetsCompat -> + // resize the motionLayout in collapsed state to add the needed inset height + val insetTopHeight = insets.systemWindowInsetTop + binding.motionLayout.minimumHeight = desiredToolbarHeight + insetTopHeight + + // modify the end ConstraintSet to set a guideline at the top and bottom of inset + val endConstraintSet = binding.motionLayout.getConstraintSet(R.id.collapsed) + // this guideline is the bottom of the inset area + endConstraintSet.setGuidelineEnd(R.id.inset, desiredToolbarHeight) + // this guideline is the top of the inset area (top of screen) + endConstraintSet.setGuidelineEnd(R.id.collapsed_top, desiredToolbarHeight + insetTopHeight) + + // set the guideline for the start constraint set as well + val startConstraintSet = binding.motionLayout.getConstraintSet(R.id.expanded) + startConstraintSet.setGuidelineBegin(R.id.collapsed_top, insetTopHeight) + + insets + } + } + + /** + * Set various flags to go edge to edge + */ + private fun Window.goEdgeToEdge() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) + statusBarColor = Color.TRANSPARENT + } + // TODO: replace this with non-deprecated edge to edge option + decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + } +} + +/** + * A custom view to display a circular cutout on an image that can be controlled by MotionLayout. + * + * Animation of this view is driven by motionLayout controlling [bottomCutSize] and [endCutSize] + * and [translationProgress]. + * + * This View will overwrite scaleType from XML to be matrix to allow custom translation. This is + * a slightly more efficient way to translate a background than oversizing the view and changing + * constraints as is done in [Entrance]. + */ +class CutoutImage @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : androidx.appcompat.widget.AppCompatImageView(context, attrs, defStyleAttr) { + + private val scratchRect = RectF() + + private var _bottomCutSize: Float + + /** + * Set the size of the bottomCut. + * + * This can directly be called by MotionLayout to animate the size. + */ + var bottomCutSize: Float + get() = _bottomCutSize + set(value) { + _bottomCutSize = value + invalidate() + } + + private var _endCutSize: Float + + /** + * Set the size of the endCut. + * + * This can directly be called by MotionLayout to animate the size. + */ + var endCutSize: Float + get() = _endCutSize + set(value) { + _endCutSize = value + invalidate() + } + + /** + * Fixed image translation progress to make the image scroll as animation progresses. + * + * This uses a Matrix to scale then translate the image based on the current progress. + * + * This can be directly called by MotionLayout, or be called in response to progress change like + * we do in this sample. + */ + var translationProgress: Int = 0 + set(value) { + field = value + val matrix = imageMatrix + val imageWidth = drawable.intrinsicWidth.toFloat() + val scaleFactor = width.toFloat() / imageWidth + matrix.setScale(scaleFactor, scaleFactor) + matrix.postTranslate(0f, -100f + value) + imageMatrix = matrix + } + + private val painter = Paint() + + private val grayPainter = Paint().also { + it.color = 0x33000000 + it.strokeWidth = dpToF(1) + } + + /** + * Read the endCut, bottomCut, and cutoutColor from XML + */ + init { + val typedArray = context.theme.obtainStyledAttributes( + attrs, + R.styleable.CutoutImage, + 0, + 0 + ) + + _endCutSize = typedArray.getDimension(R.styleable.CutoutImage_endCut, dpToF(0)) + _bottomCutSize = typedArray.getDimension(R.styleable.CutoutImage_bottomCut, dpToF(0)) + painter.color = typedArray.getColor(R.styleable.CutoutImage_cutoutColor, 0xFFaaFFaa.toInt()) + typedArray.recycle() + } + + /** + * Force the scaleType to matrix + */ + init { + scaleType = ScaleType.MATRIX // ignore any other scale types + } + + private fun dpToF(value: Int): Float = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + value.toFloat(), + resources.displayMetrics + ) + + /** + * Draw the image with current cutouts applied + */ + override fun onDraw(canvas: Canvas?) { + // let the parent draw the bitmap + super.onDraw(canvas) + + // draw the bottom circle at the correct position and size + canvas?.drawCircle( + width.toFloat() / 2, // midpoint of view + height.toFloat(), // bottom of view + _bottomCutSize / 2, // radius from diameter + painter + ) + + // draw the end circle at the correct position and size + val margin = dpToF(16) + canvas?.drawCircle( + width - margin, // end of view, with custom margin applied + 2 * height.toFloat() / 3, // 2/3 down on view (determined by designer) + _endCutSize / 2, // radius from diameter + painter + ) + + // add a 1px gray line to the bottom of the end circle region so it clearly divides from + // surrounding region (this effectively brings the shadow in early on the end circle) + canvas?.drawLine( + // start at the left edge of circle (this could do trig to calculate intersection + // between circle and bottom, but visually this works fine) + width - margin - _endCutSize / 2, + height.toFloat(), // bottom of view + width.toFloat(), // to end of view X + height.toFloat(), // bottom of view + grayPainter + ) + } +} \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/Entrance.kt b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/Entrance.kt new file mode 100644 index 00000000..84ff6870 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/Entrance.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.androidstudio.motionlayoutintegrations + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.example.androidstudio.motionlayoutintegrations.databinding.ActivityEntranceBinding + +/** + * Show an entrance animation built using MotionLayout + */ +class Entrance : AppCompatActivity() { + + private lateinit var binding: ActivityEntranceBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityEntranceBinding.inflate(layoutInflater) + setContentView(binding.root) + } +} diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/MainActivity.kt b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/MainActivity.kt new file mode 100644 index 00000000..7a512211 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/MainActivity.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.androidstudio.motionlayoutintegrations + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.example.androidstudio.motionlayoutintegrations.databinding.ActivityMainBinding + +/** + * Launcher activity for navigating the sample. + */ +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val binding = ActivityMainBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + + binding.entranceButton.setOnClickListener { + val intent = Intent(this, Entrance::class.java) + startActivity(intent) + } + binding.toolbarButton.setOnClickListener { + val intent = Intent(this, CollapsingToolbar::class.java) + startActivity(intent) + } + binding.viewPagerButton.setOnClickListener { + val intent = Intent(this, ViewPagerIntegration::class.java) + startActivity(intent) + } + } +} diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/ViewPagerIntegration.kt b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/ViewPagerIntegration.kt new file mode 100644 index 00000000..16284e61 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/java/com/example/androidstudio/motionlayoutintegrations/ViewPagerIntegration.kt @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.androidstudio.motionlayoutintegrations + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import androidx.viewpager.widget.ViewPager +import com.example.androidstudio.motionlayoutintegrations.databinding.ActivityViewPagerIntegrationBinding + +/** + * Demonstrate driving an animated header built using MotionLayout from a user swiping in a + * ViewPager + */ +class ViewPagerIntegration : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val binding = ActivityViewPagerIntegrationBinding.inflate(layoutInflater) + setContentView(binding.root) + + // set up view pager to have three tabs + val adapter = ViewPagerAdapter(supportFragmentManager) + + adapter.addPageFragment(Page1(), "List") + adapter.addPageFragment(Page2(), "Item") + adapter.addPageFragment(Page3(), "Launch") + + binding.pager.adapter = adapter + binding.tabs.setupWithViewPager(binding.pager) + + // use a page change listener to transfer swipe progress to MotionLayout + binding.pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + // calculate the swipe progress to a percent between 0f and 1f, where 0f is the + // first tab and 1f is the last tab + val progress = (position + positionOffset) / (adapter.count - 1) + // ask MotionLayout to snap to the current progress + binding.motionLayout.progress = progress + } + + override fun onPageSelected(position: Int) { + // ignore + } + + override fun onPageScrollStateChanged(state: Int) { + // ignore + } + + }) + } +} + +/** + * Adapter needed for ViewPager + */ +class ViewPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter( + fragmentManager, + BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT +) { + + private val fragmentList = ArrayList() + private val fragmentTitleList = ArrayList() + + override fun getItem(position: Int): Fragment { + return fragmentList[position] + } + + override fun getCount(): Int { + return fragmentList.size + } + + fun addPageFragment(fragment: Fragment, title: String) { + fragmentList.add(fragment) + fragmentTitleList.add(title) + } + + override fun getPageTitle(position: Int): CharSequence? { + return fragmentTitleList[position] + } +} + +/** + * Fragments for ViewPager + */ +class Page1 : Fragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.page_1, container, false) + } +} + +/** + * Fragments for ViewPager + */ +class Page2 : Fragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.page_2, container, false) + } +} + +/** + * Fragments for ViewPager + */ +class Page3 : Fragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.page_3, container, false) + } +} \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-v24/ic_launcher_foreground.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..134813eb --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-xxxhdpi/rocket_background.jpg b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-xxxhdpi/rocket_background.jpg new file mode 100644 index 00000000..e81518a5 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-xxxhdpi/rocket_background.jpg differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-xxxhdpi/star_parallax.jpg b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-xxxhdpi/star_parallax.jpg new file mode 100644 index 00000000..4eb5cf76 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable-xxxhdpi/star_parallax.jpg differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/circle_glow.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/circle_glow.png new file mode 100644 index 00000000..10ad9baa Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/circle_glow.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/circle_shape.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/circle_shape.xml new file mode 100644 index 00000000..b42fbf5c --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/circle_shape.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/collapsing.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/collapsing.png new file mode 100644 index 00000000..003a43d0 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/collapsing.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/entrance.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/entrance.png new file mode 100644 index 00000000..91e04c78 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/entrance.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/ic_launcher_background.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..8b04b417 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/inner_glow.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/inner_glow.png new file mode 100644 index 00000000..86776786 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/inner_glow.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/pager.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/pager.png new file mode 100644 index 00000000..f9147462 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/drawable/pager.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_collapsing_toolbar.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_collapsing_toolbar.xml new file mode 100644 index 00000000..39ce8dd5 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_collapsing_toolbar.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_entrance.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_entrance.xml new file mode 100644 index 00000000..12990e6b --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_entrance.xml @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_main.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..7b6ce725 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_main.xml @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_view_pager_integration.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_view_pager_integration.xml new file mode 100644 index 00000000..35646de0 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/activity_view_pager_integration.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/lots_of_cards.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/lots_of_cards.xml new file mode 100644 index 00000000..afad7d53 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/lots_of_cards.xml @@ -0,0 +1,853 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_1.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_1.xml new file mode 100644 index 00000000..71b1498b --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_1.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_2.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_2.xml new file mode 100644 index 00000000..99b61189 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_2.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_3.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_3.xml new file mode 100644 index 00000000..f45b1c84 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/layout/page_3.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..353d6b11 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..353d6b11 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-hdpi/ic_launcher.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..a571e600 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-hdpi/ic_launcher_round.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..61da551c Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-mdpi/ic_launcher.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..c41dd285 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-mdpi/ic_launcher_round.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..db5080a7 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xhdpi/ic_launcher.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..6dba46da Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..da31a871 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..15ac6817 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b216f2d3 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..f25a4197 Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e96783cc Binary files /dev/null and b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/attrs.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/attrs.xml new file mode 100644 index 00000000..459217df --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/attrs.xml @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/colors.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/colors.xml new file mode 100644 index 00000000..d999b6d0 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/colors.xml @@ -0,0 +1,23 @@ + + + + + #6200EE + #3700B3 + #03DAC5 + #FFFFFFFF + diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/strings.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/strings.xml new file mode 100644 index 00000000..776314c1 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/strings.xml @@ -0,0 +1,43 @@ + + + + MotionLayoutIntegrations + View Pager + Entrance + Toolbar + Display a complex entrance animation when entering a screen + View + Display a complex collapsing toolbar with insets + Star background + launch + Ringed Planet + Added in 2019 in Unicode 12.0 + 🪐 + Spacemoji + Quick access to space themed emoji + 🚀 + Rocket + Added in 2010 in Unicode 6.0 + 👾 + Space Monster + View Pager + Display a dynamic header driven by a ViewPager + View pager sample preview + Entrace sample preview + Collapsing toolbar screen preview + star background + diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/styles.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/styles.xml new file mode 100644 index 00000000..49b79924 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/values/styles.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_collapsing_toolbar_scene.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_collapsing_toolbar_scene.xml new file mode 100644 index 00000000..1b0307e6 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_collapsing_toolbar_scene.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_entrance_scene.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_entrance_scene.xml new file mode 100644 index 00000000..a4340c68 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_entrance_scene.xml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_view_pager_integration_scene.xml b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_view_pager_integration_scene.xml new file mode 100644 index 00000000..ca1dd80f --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/main/res/xml/activity_view_pager_integration_scene.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConstraintLayoutExamples/motionlayoutintegrations/src/test/java/com/example/androidstudio/motionlayoutintegrations/ExampleUnitTest.kt b/ConstraintLayoutExamples/motionlayoutintegrations/src/test/java/com/example/androidstudio/motionlayoutintegrations/ExampleUnitTest.kt new file mode 100644 index 00000000..07e2cf47 --- /dev/null +++ b/ConstraintLayoutExamples/motionlayoutintegrations/src/test/java/com/example/androidstudio/motionlayoutintegrations/ExampleUnitTest.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.androidstudio.motionlayoutintegrations + +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/ConstraintLayoutExamples/settings.gradle b/ConstraintLayoutExamples/settings.gradle index 28851b1f..5d5bf89b 100644 --- a/ConstraintLayoutExamples/settings.gradle +++ b/ConstraintLayoutExamples/settings.gradle @@ -1 +1,18 @@ +/* + * Copyright (C) 2020 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. + */ + include ':constraintlayout', 'motionlayout' +include ':motionlayoutintegrations' diff --git a/DataBindingDataBoundList/app/build.gradle b/DataBindingDataBoundList/app/build.gradle index 8286a3ef..ccd07eb2 100644 --- a/DataBindingDataBoundList/app/build.gradle +++ b/DataBindingDataBoundList/app/build.gradle @@ -17,13 +17,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '25.0.0' - dataBinding.enabled = true + compileSdkVersion 30 + buildToolsVersion '30.0.2' + buildFeatures.dataBinding = true defaultConfig { applicationId "com.example.android.databoundlist" minSdkVersion 14 - targetSdkVersion 25 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -36,7 +36,6 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:25.1.1' + testImplementation 'junit:junit:4.12' + implementation 'com.android.support:appcompat-v7:28.0.0' } diff --git a/DataBindingDataBoundList/build.gradle b/DataBindingDataBoundList/build.gradle index 2ce56aa4..11fd500c 100644 --- a/DataBindingDataBoundList/build.gradle +++ b/DataBindingDataBoundList/build.gradle @@ -18,10 +18,11 @@ buildscript { repositories { - jcenter() + google() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:4.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -30,7 +31,8 @@ buildscript { allprojects { repositories { - jcenter() + google() + mavenCentral() } } diff --git a/DataBindingDataBoundList/gradle.properties b/DataBindingDataBoundList/gradle.properties index 9e1313bc..246a1ed5 100644 --- a/DataBindingDataBoundList/gradle.properties +++ b/DataBindingDataBoundList/gradle.properties @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: diff --git a/DataBindingDataBoundList/gradle/wrapper/gradle-wrapper.properties b/DataBindingDataBoundList/gradle/wrapper/gradle-wrapper.properties index 315e2c5a..e074e3e2 100644 --- a/DataBindingDataBoundList/gradle/wrapper/gradle-wrapper.properties +++ b/DataBindingDataBoundList/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/DataBindingDataBoundRecyclerView/build.gradle b/DataBindingDataBoundRecyclerView/build.gradle index 14f08171..a393d459 100644 --- a/DataBindingDataBoundRecyclerView/build.gradle +++ b/DataBindingDataBoundRecyclerView/build.gradle @@ -19,10 +19,10 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -32,6 +32,6 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/DataBindingDataBoundRecyclerView/gradle/wrapper/gradle-wrapper.properties b/DataBindingDataBoundRecyclerView/gradle/wrapper/gradle-wrapper.properties index 243ff268..837eec98 100644 --- a/DataBindingDataBoundRecyclerView/gradle/wrapper/gradle-wrapper.properties +++ b/DataBindingDataBoundRecyclerView/gradle/wrapper/gradle-wrapper.properties @@ -13,10 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# +#Mon Jun 07 09:36:42 PDT 2021 -#Mon Dec 28 10:00:20 PST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip diff --git a/README.md b/README.md index d0a8f05a..de0f9597 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +> **Warning** +> We are in the process of migrating these samples into the new [platform-samples repository](https://github.com/android/platform-samples). +> +> You can find the list of migrated samples [here](https://github.com/android/platform-samples/tree/main/samples/user-interface) + + Android Views and Widgets Samples Repository ============================================ diff --git a/RecyclerViewKotlin/.google/packaging.yaml b/RecyclerViewKotlin/.google/packaging.yaml index 202420c9..8b752bd1 100644 --- a/RecyclerViewKotlin/.google/packaging.yaml +++ b/RecyclerViewKotlin/.google/packaging.yaml @@ -13,8 +13,7 @@ github: android/views-widgets level: INTERMEDIATE icon: screenshots/icon-web.png apiRefs: - - android:android.support.v7.widget.RecyclerView - - android:android.support.v7.widget.LinearLayoutManager - - android:android.support.v7.widget.GridLayoutManager - - android:android.support.v7.widget.RecyclerView.ViewHolder + - android:androidx.recyclerview.widget.RecyclerView + - android:androidx.recyclerview.widget.RecyclerView.LayoutManager + - android:androidx.recyclerview.widget.RecyclerView.ViewHolder license: apache2 diff --git a/RecyclerViewKotlin/README.md b/RecyclerViewKotlin/README.md index 0c503eb1..b95fe375 100644 --- a/RecyclerViewKotlin/README.md +++ b/RecyclerViewKotlin/README.md @@ -1,31 +1,27 @@ - Android RecyclerView Sample (Kotlin) ==================================== -Sample demonstrating the use of RecyclerView to layout elements with a -LinearLayoutManager and with a GridLayoutManager. It also demonstrates -how to handle touch events on elements. +This application implements a RecyclerView in Kotlin with ListAdapter, onClickListener +and Headers. If you are looking for a simpler sample, look at the RecyclerViewSimple sample +in the directory. Introduction ------------ Sample demonstrating the use of [RecyclerView][1] to layout elements with a -[LinearLayoutManager][2] or with a [GridLayoutManager][3]. +[LinearLayoutManager][2]. [RecyclerView][1] can display large datasets that can be scrolled -efficiently by recycling a limited number of views. Click listeners can be -defined when [ViewHolder][4] views are instantiated. [RecyclerView][1] is -available in the v7 Support Library, thus compatible with API level 7 and above. +efficiently by recycling a limited number of views. [ListAdapter][3] is used to +efficiently compute diffs when items are added/removed from the list. Click listeners can be +defined when [ViewHolder][4] views are instantiated. -Tap "Show Log" menu item to display log of elements as they are laid out and -tapped. Use radio buttons to toggle between [LinearLayoutManager][2] and -[GridLayoutManager][3]. -[1]: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html -[2]: https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html -[3]: https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html -[4]: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html +[1]: https://developer.android.com/reference/kotlin/androidx/recyclerview/widget/RecyclerView +[2]: https://developer.android.com/reference/androidx/recyclerview/widget/LinearLayoutManager +[3]: https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter +[4]: https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.ViewHolder Pre-requisites -------------- @@ -37,13 +33,12 @@ Pre-requisites Screenshots ------------- -Screenshot Screenshot +![image](https://user-images.githubusercontent.com/46006059/98028846-8b6df700-1dc3-11eb-9f0b-ad93569be189.png) Getting Started --------------- -This sample uses the Gradle build system. To build this project, use the -"gradlew build" command or use "Import Project" in Android Studio. +To build this project, use "Import Project" in Android Studio. Support ------- @@ -54,4 +49,4 @@ If you've found an error in this sample, please file an issue: https://github.com/android/views-widgets Patches are encouraged, and may be submitted by forking this project and -submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. +submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. \ No newline at end of file diff --git a/RecyclerViewKotlin/app/.gitignore b/RecyclerViewKotlin/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/RecyclerViewKotlin/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/RecyclerViewKotlin/app/build.gradle b/RecyclerViewKotlin/app/build.gradle index 5a2cdfc7..c11c7b6f 100644 --- a/RecyclerViewKotlin/app/build.gradle +++ b/RecyclerViewKotlin/app/build.gradle @@ -1,34 +1,66 @@ -apply plugin: 'com.android.application' +/* + * Copyright (C) 2020 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. + */ +apply plugin: 'com.android.application' apply plugin: 'kotlin-android' - apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 28 + compileSdkVersion 30 + defaultConfig { - applicationId "com.example.android.recyclerview" - minSdkVersion 14 - targetSdkVersion 28 + applicationId "com.example.recyclersample" + minSdkVersion 21 + targetSdkVersion 30 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - lintOptions { - abortOnError false + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + } dependencies { - implementation "com.android.support:appcompat-v7:28.0.0" - implementation "com.android.support:recyclerview-v7:28.0.0" - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion" + implementation "androidx.core:core-ktx:$rootProject.coreKtxVersion" + implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion" + implementation "androidx.activity:activity-ktx:$rootProject.activityVersion" + + // RecyclerView + implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerViewVersion" + + // Material design + implementation "com.google.android.material:material:$rootProject.materialVersion" + + // LiveData + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.liveDataVersion" } diff --git a/RecyclerViewKotlin/app/src/main/AndroidManifest.xml b/RecyclerViewKotlin/app/src/main/AndroidManifest.xml index d21f57c2..2337d8fe 100644 --- a/RecyclerViewKotlin/app/src/main/AndroidManifest.xml +++ b/RecyclerViewKotlin/app/src/main/AndroidManifest.xml @@ -1,20 +1,39 @@ + + + package="com.example.recyclersample"> - + + + \ No newline at end of file diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/activities/SampleActivityBase.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/activities/SampleActivityBase.kt deleted file mode 100644 index 0d7003ec..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/activities/SampleActivityBase.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* -* Copyright 2017 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. -*/ - -package com.example.android.common.activities - -import android.os.Bundle -import android.support.v4.app.FragmentActivity - -import com.example.android.common.logger.Log -import com.example.android.common.logger.LogWrapper - -/** - * Base launcher activity, to handle most of the common plumbing for samples. - */ -open class SampleActivityBase : FragmentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } - - override fun onStart() { - super.onStart() - initializeLogging() - } - - /** Set up targets to receive log data */ - open fun initializeLogging() { - // Using Log, front-end to the logging chain, emulates android.util.log method signatures. - // Wraps Android's native log framework - val logWrapper = LogWrapper() - Log.logNode = logWrapper - - Log.i(TAG, "Ready") - } - - companion object { - val TAG = "SampleActivityBase" - } -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/Log.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/Log.kt deleted file mode 100644 index 7cbf5ebc..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/Log.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ -package com.example.android.common.logger - -/** - * Helper class for a list (or tree) of LoggerNodes. - * - * - * When this is set as the head of the list, - * an instance of it can function as a drop-in replacement for [android.util.Log]. - * Most of the methods in this class server only to map a method call in Log to its equivalent - * in LogNode. - */ -object Log { - // Grabbing the native values from Android's native logging facilities, - // to make for easy migration and interop. - val NONE = -1 - val VERBOSE = android.util.Log.VERBOSE - val DEBUG = android.util.Log.DEBUG - val INFO = android.util.Log.INFO - val WARN = android.util.Log.WARN - val ERROR = android.util.Log.ERROR - val ASSERT = android.util.Log.ASSERT - - // Stores the beginning of the LogNode topology. - var logNode: LogNode? = null - - /** - * Instructs the LogNode to print the log data provided. Other LogNodes can - * be chained to the end of the LogNode as desired. - * - * @param priority Log level of the data being logged. Verbose, Error, etc. - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun println(priority: Int, tag: String, msg: String?, tr: Throwable? = null) { - - logNode?.println(priority, tag, msg, tr) - - } - - /** - * Prints a message at VERBOSE priority. - * - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun v(tag: String, msg: String? = null, tr: Throwable? = null) { - println(VERBOSE, tag, msg, tr) - } - - - /** - * Prints a message at DEBUG priority. - * - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun d(tag: String, msg: String? = null, tr: Throwable? = null) { - println(DEBUG, tag, msg, tr) - } - - /** - * Prints a message at INFO priority. - * - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun i(tag: String, msg: String, tr: Throwable? = null) { - println(INFO, tag, msg, tr) - } - - /** - * Prints a message at WARN priority. - * - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun w(tag: String, msg: String? = null, tr: Throwable? = null) { - println(WARN, tag, msg, tr) - } - - - - /** - * Prints a message at ERROR priority. - * - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun e(tag: String, msg: String, tr: Throwable? = null) { - println(ERROR, tag, msg, tr) - } - - /** - * Prints a message at ASSERT priority. - * - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun wtf(tag: String, msg: String? = null, tr: Throwable? = null) { - println(ASSERT, tag, msg, tr) - } - - -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogFragment.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogFragment.kt deleted file mode 100644 index 49555bfd..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogFragment.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* -* Copyright 2017 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. -*/ - -package com.example.android.common.logger - -import android.content.Context -import android.graphics.Typeface -import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v4.widget.TextViewCompat -import android.text.Editable -import android.text.TextWatcher -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ScrollView - -/** - * Simple fragment which contains a LogView and uses is to output log data it receives - * through the LogNode interface. - */ -class LogFragment : Fragment() { - - lateinit var logView: LogView - private set - - private lateinit var scrollView: ScrollView - - private fun inflateViews(): View { - scrollView = ScrollView(activity) - val scrollParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT) - scrollView.layoutParams = scrollParams - - logView = LogView(activity as Context) - val logParams = ViewGroup.LayoutParams(scrollParams) - logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT - - with(logView) { - layoutParams = logParams - isClickable = true - isFocusable = true - typeface = Typeface.MONOSPACE - } - - // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! - val paddingDips = 16 - val scale = resources.displayMetrics.density.toDouble() - val paddingPixels = (paddingDips * scale + .5).toInt() - logView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels) - logView.compoundDrawablePadding = paddingPixels - - logView.gravity = Gravity.BOTTOM - TextViewCompat.setTextAppearance(logView, android.R.style.TextAppearance_Holo_Medium) - - scrollView.addView(logView) - return scrollView - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { - - val result = inflateViews() - - logView.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} - - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} - - override fun afterTextChanged(s: Editable) { - scrollView.fullScroll(ScrollView.FOCUS_DOWN) - } - }) - return result - } -} \ No newline at end of file diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogNode.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogNode.kt deleted file mode 100644 index 6259f02c..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogNode.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ -package com.example.android.common.logger - -/** - * Basic interface for a logging system that can output to one or more targets. - * Note that in addition to classes that will output these logs in some format, - * one can also implement this interface over a filter and insert that in the chain, - * such that no targets further down see certain data, or see manipulated forms of the data. - * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data - * it received to HTML and sent it along to the next node in the chain, without printing it - * anywhere. - */ -interface LogNode { - - /** - * Instructs first LogNode in the list to print the log data provided. - * @param priority Log level of the data being logged. Verbose, Error, etc. - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) - -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogView.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogView.kt deleted file mode 100644 index ecb5ed5a..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogView.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ -package com.example.android.common.logger - -import android.app.Activity -import android.content.Context -import android.util.* -import android.widget.TextView - -/** Simple TextView which is used to output log data received through the LogNode interface. - */ -class LogView : TextView, LogNode { - - // The next LogNode in the chain. - private var next: LogNode? = null - - @JvmOverloads - constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : - super(context, attrs, defStyle) - - /** - * Formats the log data and prints it out to the LogView. - * @param priority Log level of the data being logged. Verbose, Error, etc. - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - override fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) { - - // For the purposes of this View, we want to print the priority as readable text. - val priorityStr = when (priority) { - android.util.Log.VERBOSE -> "VERBOSE" - android.util.Log.DEBUG -> "DEBUG" - android.util.Log.INFO -> "INFO" - android.util.Log.WARN -> "WARN" - android.util.Log.ERROR -> "ERROR" - android.util.Log.ASSERT -> "ASSERT" - else -> null - } - - // Handily, the Log class has a facility for converting a stack trace into a usable string. - val exceptionStr = tr?.let{ android.util.Log.getStackTraceString(it) } - - // Take the priority, tag, message, and exception, and concatenate as necessary - // into one usable line of text. - val outputBuilder = StringBuilder() - - val delimiter = "\t" - appendIfNotNull(outputBuilder, priorityStr, delimiter) - appendIfNotNull(outputBuilder, tag, delimiter) - appendIfNotNull(outputBuilder, msg, delimiter) - appendIfNotNull(outputBuilder, exceptionStr, delimiter) - - // In case this was originally called from an AsyncTask or some other off-UI thread, - // make sure the update occurs within the UI thread. - (context as Activity).runOnUiThread( { - // Display the text we just generated within the LogView. - appendToLog(outputBuilder.toString()) - }) - - - next?.println(priority, tag, msg, tr) - - } - - /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since - * the logger takes so many arguments that might be null, this method helps cut out some of the - * agonizing tedium of writing the same 3 lines over and over. - * @param source StringBuilder containing the text to append to. - * @param addStr The String to append - * @param delimiter The String to separate the source and appended strings. A tab or comma, - * for instance. - * @return The fully concatenated String as a StringBuilder - */ - private fun appendIfNotNull(source: StringBuilder, addStr: String?, delimiter: String): StringBuilder { - - if (addStr != null && !addStr.isEmpty()) { - return source.append(addStr).append(delimiter) - } - - return source - - } - - /** Outputs the string as a new line of log data in the LogView. */ - private fun appendToLog(s: String) { - append("\n" + s) - } - - -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogWrapper.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogWrapper.kt deleted file mode 100644 index 381b57a2..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/LogWrapper.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ -package com.example.android.common.logger - -import android.util.Log - -/** - * Helper class which wraps Android's native Log utility in the Logger interface. This way - * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. - */ -class LogWrapper : LogNode { - - // For piping: The next node to receive Log data after this one has done its work. - var next: LogNode? = null - - /** - * Prints data out to the console using Android's native log mechanism. - * @param priority Log level of the data being logged. Verbose, Error, etc. - * @param tag Tag for for the log data. Can be used to organize log statements. - * @param msg The actual message to be logged. The actual message to be logged. - * @param tr If an exception was thrown, this can be sent along for the logging facilities - * to extract and print useful information. - */ - override fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) { - var msg = msg - // There actually are log methods that don't take a msg parameter. For now, - // if that's the case, just convert null to the empty string and move on. - var useMsg: String? = msg - if (useMsg == null) { - useMsg = "" - } - - // If an exception was provided, convert that exception to a usable string and attach - // it to the end of the msg method. - if (tr != null) { - msg += "\n$Log.getStackTraceString(tr)" - } - - // This is functionally identical to Log.x(tag, useMsg); - // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) - Log.println(priority, tag, useMsg) - - // If this isn't the last node in the chain, move things along. - next?.println(priority, tag, msg, tr) - - } -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.kt deleted file mode 100644 index 5ec926fe..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ -package com.example.android.common.logger - -/** - * Simple [LogNode] filter, removes everything except the message. - * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, - * just easy-to-read message updates as they're happening. - */ -class MessageOnlyLogFilter : LogNode { - - /** - * Returns the next LogNode in the chain. - */ - var next: LogNode? = null - - override fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) { - next?.println(Log.NONE, null, msg, null) - } - -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/CustomAdapter.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/CustomAdapter.kt deleted file mode 100644 index 866e4eb2..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/CustomAdapter.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (C) 2014 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. -*/ - -package com.example.android.recyclerview - -import android.support.v7.widget.RecyclerView -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView - -import com.example.android.common.logger.Log - -/** - * Provide views to RecyclerView with data from dataSet. - * - * Initialize the dataset of the Adapter. - * - * @param dataSet String[] containing the data to populate views to be used by RecyclerView. - */ -class CustomAdapter(private val dataSet: Array) : - RecyclerView.Adapter() { - - /** - * Provide a reference to the type of views that you are using (custom ViewHolder) - */ - class ViewHolder(v: View) : RecyclerView.ViewHolder(v) { - val textView: TextView - - init { - // Define click listener for the ViewHolder's View. - v.setOnClickListener { Log.d(TAG, "Element $adapterPosition clicked.") } - textView = v.findViewById(R.id.textView) - } - } - - // Create new views (invoked by the layout manager) - override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { - // Create a new view. - val v = LayoutInflater.from(viewGroup.context) - .inflate(R.layout.text_row_item, viewGroup, false) - - return ViewHolder(v) - } - - // Replace the contents of a view (invoked by the layout manager) - override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { - Log.d(TAG, "Element $position set.") - - // Get element from your dataset at this position and replace the contents of the view - // with that element - viewHolder.textView.text = dataSet[position] - } - - // Return the size of your dataset (invoked by the layout manager) - override fun getItemCount() = dataSet.size - - companion object { - private val TAG = "CustomAdapter" - } -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/MainActivity.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/MainActivity.kt deleted file mode 100644 index c1097fac..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/MainActivity.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* -* Copyright 2017 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. -*/ - - -package com.example.android.recyclerview - -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.widget.ViewAnimator - -import com.example.android.common.activities.SampleActivityBase -import com.example.android.common.logger.Log -import com.example.android.common.logger.LogFragment -import com.example.android.common.logger.LogWrapper -import com.example.android.common.logger.MessageOnlyLogFilter - -/** - * A simple launcher activity containing a summary sample description, sample log and a custom - * [android.support.v4.app.Fragment] which can display a view. - * - * - * For devices with displays with a width of 720dp or greater, the sample log is always visible, - * on other devices it's visibility is controlled by an item on the Action Bar. - */ -class MainActivity : SampleActivityBase() { - - // Whether the Log Fragment is currently shown - private var logShown = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - - if (savedInstanceState == null) { - supportFragmentManager.beginTransaction().run { - replace(R.id.sample_content_fragment, RecyclerViewFragment()) - commit() - } - } - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.main, menu) - return true - } - - override fun onPrepareOptionsMenu(menu: Menu): Boolean { - menu.findItem(R.id.menu_toggle_log).run { - isVisible = findViewById(R.id.sample_output) is ViewAnimator - setTitle(if (logShown) R.string.sample_hide_log else R.string.sample_show_log) - } - - return super.onPrepareOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { - R.id.menu_toggle_log -> { - logShown = !logShown - val output = findViewById(R.id.sample_output) as ViewAnimator - - output.displayedChild = if (logShown) 1 else 0 - - invalidateOptionsMenu() - true - } - else -> super.onOptionsItemSelected(item) - } - - - - /** Create a chain of targets that will receive log data */ - override fun initializeLogging() { - // Wraps Android's native log framework. - val logWrapper = LogWrapper() - - // Using Log, front-end to the logging chain, emulates android.util.log method signatures. - Log.logNode = logWrapper - - // Filter strips out everything except the message text. - val msgFilter = MessageOnlyLogFilter() - logWrapper.next = msgFilter - - // On screen logging via a fragment with a TextView. - val logFragment = supportFragmentManager.findFragmentById(R.id.log_fragment) as LogFragment - msgFilter.next = logFragment.logView - - Log.i(TAG, "Ready") - } - - companion object { - val TAG = "MainActivity" - } -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.kt b/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.kt deleted file mode 100644 index 9ad0ede4..00000000 --- a/RecyclerViewKotlin/app/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.kt +++ /dev/null @@ -1,139 +0,0 @@ -/* -* Copyright (C) 2017 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. -*/ - -package com.example.android.recyclerview - -import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v7.widget.GridLayoutManager -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.RadioButton - -/** - * Demonstrates the use of [RecyclerView] with a [LinearLayoutManager] and a - * [GridLayoutManager]. - */ -class RecyclerViewFragment : Fragment() { - - private lateinit var currentLayoutManagerType: LayoutManagerType - private lateinit var recyclerView: RecyclerView - private lateinit var layoutManager: RecyclerView.LayoutManager - private lateinit var dataset: Array - - enum class LayoutManagerType { GRID_LAYOUT_MANAGER, LINEAR_LAYOUT_MANAGER } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - // Initialize dataset, this data would usually come from a local content provider or - // remote server. - initDataset() - } - - override fun onCreateView(inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?): View? { - val rootView = inflater.inflate(R.layout.recycler_view_frag, - container, false).apply { tag = TAG} - - recyclerView = rootView.findViewById(R.id.recyclerView) - - // LinearLayoutManager is used here, this will layout the elements in a similar fashion - // to the way ListView would layout elements. The RecyclerView.LayoutManager defines how - // elements are laid out. - layoutManager = LinearLayoutManager(activity) - - currentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER - - if (savedInstanceState != null) { - // Restore saved layout manager type. - currentLayoutManagerType = savedInstanceState - .getSerializable(KEY_LAYOUT_MANAGER) as LayoutManagerType - } - setRecyclerViewLayoutManager(currentLayoutManagerType) - - // Set CustomAdapter as the adapter for RecyclerView. - recyclerView.adapter = CustomAdapter(dataset) - - rootView.findViewById(R.id.linear_layout_rb).setOnClickListener{ - setRecyclerViewLayoutManager(LayoutManagerType.LINEAR_LAYOUT_MANAGER) - } - - rootView.findViewById(R.id.grid_layout_rb).setOnClickListener{ - setRecyclerViewLayoutManager(LayoutManagerType.GRID_LAYOUT_MANAGER) - } - - return rootView - } - - /** - * Set RecyclerView's LayoutManager to the one given. - * - * @param layoutManagerType Type of layout manager to switch to. - */ - private fun setRecyclerViewLayoutManager(layoutManagerType: LayoutManagerType) { - var scrollPosition = 0 - - // If a layout manager has already been set, get current scroll position. - if (recyclerView.layoutManager != null) { - scrollPosition = (recyclerView.layoutManager as LinearLayoutManager) - .findFirstCompletelyVisibleItemPosition() - } - - when (layoutManagerType) { - RecyclerViewFragment.LayoutManagerType.GRID_LAYOUT_MANAGER -> { - layoutManager = GridLayoutManager(activity, SPAN_COUNT) - currentLayoutManagerType = LayoutManagerType.GRID_LAYOUT_MANAGER - } - RecyclerViewFragment.LayoutManagerType.LINEAR_LAYOUT_MANAGER -> { - layoutManager = LinearLayoutManager(activity) - currentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER - } - } - - with(recyclerView) { - layoutManager = this@RecyclerViewFragment.layoutManager - scrollToPosition(scrollPosition) - } - - } - - override fun onSaveInstanceState(savedInstanceState: Bundle) { - - // Save currently selected layout manager. - savedInstanceState.putSerializable(KEY_LAYOUT_MANAGER, currentLayoutManagerType) - super.onSaveInstanceState(savedInstanceState) - } - - /** - * Generates Strings for RecyclerView's adapter. This data would usually come - * from a local content provider or remote server. - */ - private fun initDataset() { - dataset = Array(DATASET_COUNT, {i -> "This is element # $i"}) - } - - companion object { - private val TAG = "RecyclerViewFragment" - private val KEY_LAYOUT_MANAGER = "layoutManager" - private val SPAN_COUNT = 2 - private val DATASET_COUNT = 60 - } -} diff --git a/RecyclerViewKotlin/app/src/main/java/com/example/recyclersample/addFlower/AddFlowerActivity.kt b/RecyclerViewKotlin/app/src/main/java/com/example/recyclersample/addFlower/AddFlowerActivity.kt new file mode 100644 index 00000000..2d67d294 --- /dev/null +++ b/RecyclerViewKotlin/app/src/main/java/com/example/recyclersample/addFlower/AddFlowerActivity.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.example.recyclersample.addFlower + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.widget.Button +import androidx.appcompat.app.AppCompatActivity +import com.example.recyclersample.R +import com.google.android.material.textfield.TextInputEditText + +const val FLOWER_NAME = "name" +const val FLOWER_DESCRIPTION = "description" + +class AddFlowerActivity : AppCompatActivity() { + private lateinit var addFlowerName: TextInputEditText + private lateinit var addFlowerDescription: TextInputEditText + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.add_flower_layout) + + findViewById + + \ No newline at end of file diff --git a/WebView/app/src/main/assets/main.js b/WebView/app/src/main/assets/main.js new file mode 100644 index 00000000..a79938f2 --- /dev/null +++ b/WebView/app/src/main/assets/main.js @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 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. + */ +function sendAndroidMessage() { + /* In this implementation, only the single-arg version of postMessage is supported. As noted + * in the WebViewCompat reference doc, the second parameter, MessagePorts, is optional. + * Also note that onmessage, addEventListener and removeEventListener are not supported. + */ + jsObject.postMessage("The weather in " + `${document.getElementById("title").innerText}` + " today is " + + `${document.getElementById("shortDescription").innerText} `); +} + + +function getData() { + // This JSON files is hosted over the web + fetch("https://raw.githubusercontent.com/android/views-widgets-samples/main/WebView/sampleData/weather.json").then(function(resp) { + return resp.json(); + }).then(function(data) { + var form = document.getElementById("location"); + var currentLocation = form.options[form.selectedIndex].value; + document.getElementById("title").innerText = form.options[form.selectedIndex].text; + document.getElementById("currentTemp").innerText = `${data[currentLocation].currentTemp}`+ "\xB0 F"; + document.getElementById("shortDescription").innerText = data[currentLocation].description; + document.getElementById("longDescription").innerText = "Today in " + `${form.options[form.selectedIndex].text}` + + " there is a " + `${data[currentLocation].chancePrecip}` + "% chance of precipitation and the humidity is " + + `${data[currentLocation].humidity}` + "%."; + document.getElementById("icon").src = getIcon(data[currentLocation].description); + }) +} + +/* These icons are hosted locally, in the res/drawable folder. However, we can call them using + * http(s):// URLs because we have configured AssetLoader in MainActivity. It is desirable to + * access the files in this way because it is compatible with the Same-Origin policy. + */ +function getIcon(description){ + switch(description) { + case "Rainy": + return "https://raw.githubusercontent.com/views-widgets-samples/res/drawable/rain.png"; + case "Clear Sky": + return "https://raw.githubusercontent.com/views-widgets-samples/res/drawable/sunny.png"; + default: + return "https://raw.githubusercontent.com/views-widgets-samples/res/drawable/partly_cloudy.png"; + } +} \ No newline at end of file diff --git a/WebView/app/src/main/assets/style.css b/WebView/app/src/main/assets/style.css new file mode 100644 index 00000000..026ddaea --- /dev/null +++ b/WebView/app/src/main/assets/style.css @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 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. + */ +body { + background-color: white; +} +h1, h2 { + text-align: center; + color: black; + text-align: center; +} +p { + font-family: verdana; + font-size: 20px; +} +label { + font-family: verdana; + font-size: 20px; +} +img { + border-radius: 4px; + padding: 5px; +} +.button { + color: black; + background-color:#03DAC6; + font-family: verdana; + border-radius:8px; + border:1px solid #03DAC6; + display:inline-block; + cursor:pointer; + font-size:18px; + padding:16px 31px; + text-decoration:none; + text-shadow:0px 1px 0px #2f6627; + margin-left: 27%; + margin-top: 5%; +} +.button:active { + position:relative; + top:1px; +} +.day{ + margin-top: 50px; +} +.center { + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; +} +.share { + position: fixed; + bottom: 0; + right: 0; +} +.icon { + float: left; + width: 40%; + margin-left: 10%; +} +.currentTemp { + float: right; + margin-right: 10%; + width: 30%; +} +.shortDescription { + position: relative; + margin-top: 10%; +} +.longDescription { + text-align: left; + padding-top: 20%; + padding-left: 5%; + padding-right: 5%; +} +@media (prefers-color-scheme: dark) { + body { + background: #383838; + } + h1, h2 { + color: white; + } + select { + color: white; + background-color: #1f1f1f; + border-color: #121212; + } +} \ No newline at end of file diff --git a/WebView/app/src/main/java/com/android/samples/webviewdemo/JsObject.kt b/WebView/app/src/main/java/com/android/samples/webviewdemo/JsObject.kt new file mode 100644 index 00000000..c337812b --- /dev/null +++ b/WebView/app/src/main/java/com/android/samples/webviewdemo/JsObject.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.samples.webviewdemo + +import android.os.Handler +import android.os.Looper +import android.webkit.JavascriptInterface +import android.webkit.WebView +import androidx.webkit.WebViewCompat +import androidx.webkit.WebViewFeature + +// Create a handler that runs on the UI thread +private val handler: Handler = Handler(Looper.getMainLooper()) + +/** + * Injects a JavaScript object which supports a {@code postMessage()} method. + * A feature check is used to determine if the preferred API, WebMessageListener, is supported. + * If it is, then WebMessageListener will be used to create a JavaScript object. The object will be + * injected into all of the frames that have an origin matching those in {@code allowedOriginRules}. + *

+ * If WebMessageListener is not supported then the method will defer to using JavascriptInterface + * to create the JavaScript object. + *

+ * The {@code postMessage()} methods in the Javascript objects created by WebMessageListener and + * JavascriptInterface both make calls to the same callback, {@code onMessageReceived()}. + * In this case, the callback invokes native Android sharing. + *

+ * The WebMessageListener invokes callbacks on the UI thread by default. However, + * JavascriptInterface invokes callbacks on a background thread by default. In order to + * guarantee thread safety and that the caller always gets consistent behavior the the callback + * should always be called on the UI thread. To change the default behavior of JavascriptInterface, + * the callback is wrapped in a handler which will tell it to run on the UI thread instead of the default + * background thread it would otherwise be invoked on. + *

+ * @param webview the component that WebMessageListener or JavascriptInterface will be added to + * @param jsObjName the name that will be given to the Javascript objects created by either + * WebMessageListener or JavascriptInterface + * @param allowedOriginRules a set of origins used only by WebMessageListener, if a frame matches an + * origin in this set then it will have the JS object injected into it + * @param onMessageReceived invoked on UI thread with message passed in from JavaScript postMessage() call + */ +fun createJsObject( + webview: WebView, + jsObjName: String, + allowedOriginRules: Set, + onMessageReceived: (message: String) -> Unit +) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { + WebViewCompat.addWebMessageListener( + webview, jsObjName, allowedOriginRules + ) { _, message, _, _, _ -> onMessageReceived(message.data!!) } + } else { + webview.addJavascriptInterface(object { + @JavascriptInterface + fun postMessage(message: String) { + // Use the handler to invoke method on UI thread + handler.post { onMessageReceived(message) } + } + }, jsObjName) + } +} \ No newline at end of file diff --git a/WebView/app/src/main/java/com/android/samples/webviewdemo/MainActivity.kt b/WebView/app/src/main/java/com/android/samples/webviewdemo/MainActivity.kt new file mode 100644 index 00000000..8540a295 --- /dev/null +++ b/WebView/app/src/main/java/com/android/samples/webviewdemo/MainActivity.kt @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.samples.webviewdemo + +import android.annotation.SuppressLint +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.res.Configuration +import android.os.Bundle +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse +import android.webkit.WebView +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat.startActivity +import androidx.webkit.WebSettingsCompat +import androidx.webkit.WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING +import androidx.webkit.WebViewAssetLoader +import androidx.webkit.WebViewClientCompat +import androidx.webkit.WebViewFeature +import com.android.samples.webviewdemo.databinding.ActivityMainBinding + +class MainActivity : AppCompatActivity() { + // Creating the custom WebView Client Class + private class MyWebViewClient(private val assetLoader: WebViewAssetLoader) : + WebViewClientCompat() { + override fun shouldInterceptRequest( + view: WebView, + request: WebResourceRequest + ): WebResourceResponse? { + return assetLoader.shouldInterceptRequest(request.url) + } + } + + // Invokes native android sharing + private fun invokeShareIntent(message: String) { + val sendIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, message) + type = "text/plain" + } + val shareIntent = Intent.createChooser(sendIntent, null) + startActivity(this@MainActivity, shareIntent, null) + } + + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + val jsObjName = "jsObject" + val allowedOriginRules = setOf("https://raw.githubusercontent.com") + + // Configuring Dark Theme + // *NOTE* : The force dark setting is not persistent. You must call the static + // method every time your app process is started. + // *NOTE* : The change from day<->night mode is a + // configuration change so by default the activity will be restarted + // (and pickup the new values to apply the theme). Take care when overriding this + // default behavior to ensure this method is still called when changes are made. + val nightModeFlag = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + // Check if the system is set to light or dark mode + if (nightModeFlag == Configuration.UI_MODE_NIGHT_YES) { + // Switch WebView to dark mode; uses default dark theme + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + WebSettingsCompat.setForceDark( + binding.webview.settings, + WebSettingsCompat.FORCE_DARK_ON + ) + } + + /* Set how WebView content should be darkened. There are three options for how to darken + * a WebView. + * PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING- checks for the "color-scheme" tag. + * If present, it uses media queries. If absent, it applies user-agent (automatic) + * darkening DARK_STRATEGY_WEB_THEME_DARKENING_ONLY - uses media queries always, even + * if there's no "color-scheme" tag present. + * DARK_STRATEGY_USER_AGENT_DARKENING_ONLY - it ignores web page theme and always + * applies user-agent (automatic) darkening. + * More information about Force Dark Strategy can be found here: + * https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setForceDarkStrategy(android.webkit.WebSettings,%20int) + */ + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { + WebSettingsCompat.setForceDarkStrategy( + binding.webview.settings, + DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING + ) + } + } + + // Configure asset loader with custom domain + // *NOTE* : + // The assets path handler is set with the sub path /views-widgets-samples/ here because we + // are tyring to ensure that the address loaded with + // loadUrl("https://raw.githubusercontent.com/views-widgets-samples/assets/index.html") does + // not conflict with a real web address. In this case, if the path were only /assests/ we + // would need to load "https://raw.githubusercontent.com/assets/index.html" in order to + // access our local index.html file. + // However we cannot guarantee "https://raw.githubusercontent.com/assets/index.html" is not + // a valid web address. Therefore we must let the AssetLoader know to expect the + // /views-widgets-samples/ sub path as well as the /assets/. + val assetLoader = WebViewAssetLoader.Builder() + .setDomain("raw.githubusercontent.com") + .addPathHandler( + "/views-widgets-samples/assets/", + WebViewAssetLoader.AssetsPathHandler(this) + ) + .addPathHandler( + "/views-widgets-samples/res/", + WebViewAssetLoader.ResourcesPathHandler(this) + ) + .build() + + // Set clients + binding.webview.webViewClient = MyWebViewClient(assetLoader) + + // Set Title + title = getString(R.string.app_name) + + // Setup debugging; See https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews for reference + if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) { + WebView.setWebContentsDebuggingEnabled(true) + } + + // Enable Javascript + binding.webview.settings.javaScriptEnabled = true + + // Create a JS object to be injected into frames; Determines if WebMessageListener + // or WebAppInterface should be used + createJsObject( + binding.webview, + jsObjName, + allowedOriginRules + ) { message -> invokeShareIntent(message) } + + // Load the content + binding.webview.loadUrl("https://raw.githubusercontent.com/views-widgets-samples/assets/index.html") + } +} \ No newline at end of file diff --git a/WebView/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/WebView/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..134813eb --- /dev/null +++ b/WebView/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/WebView/app/src/main/res/drawable-v24/partly_cloudy.png b/WebView/app/src/main/res/drawable-v24/partly_cloudy.png new file mode 100644 index 00000000..c5774828 Binary files /dev/null and b/WebView/app/src/main/res/drawable-v24/partly_cloudy.png differ diff --git a/WebView/app/src/main/res/drawable-v24/rain.png b/WebView/app/src/main/res/drawable-v24/rain.png new file mode 100644 index 00000000..a38b1969 Binary files /dev/null and b/WebView/app/src/main/res/drawable-v24/rain.png differ diff --git a/WebView/app/src/main/res/drawable-v24/sunny.png b/WebView/app/src/main/res/drawable-v24/sunny.png new file mode 100644 index 00000000..1d154049 Binary files /dev/null and b/WebView/app/src/main/res/drawable-v24/sunny.png differ diff --git a/WebView/app/src/main/res/drawable/ic_launcher_background.xml b/WebView/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..8b04b417 --- /dev/null +++ b/WebView/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebView/app/src/main/res/layout/activity_main.xml b/WebView/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..51b9fbe4 --- /dev/null +++ b/WebView/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file diff --git a/WebView/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/WebView/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..353d6b11 --- /dev/null +++ b/WebView/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/WebView/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/WebView/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..353d6b11 --- /dev/null +++ b/WebView/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/WebView/app/src/main/res/mipmap-hdpi/ic_launcher.png b/WebView/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..a571e600 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/WebView/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/WebView/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..61da551c Binary files /dev/null and b/WebView/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/WebView/app/src/main/res/mipmap-mdpi/ic_launcher.png b/WebView/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..c41dd285 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/WebView/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/WebView/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..db5080a7 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/WebView/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/WebView/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..6dba46da Binary files /dev/null and b/WebView/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/WebView/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/WebView/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..da31a871 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/WebView/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/WebView/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..15ac6817 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/WebView/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/WebView/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b216f2d3 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/WebView/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/WebView/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..f25a4197 Binary files /dev/null and b/WebView/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/WebView/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/WebView/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e96783cc Binary files /dev/null and b/WebView/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/WebView/app/src/main/res/values-night/colors.xml b/WebView/app/src/main/res/values-night/colors.xml new file mode 100644 index 00000000..5c06301b --- /dev/null +++ b/WebView/app/src/main/res/values-night/colors.xml @@ -0,0 +1,22 @@ + + + + + #3700B3 + #BB86FC + #03DAC5 + \ No newline at end of file diff --git a/WebView/app/src/main/res/values/colors.xml b/WebView/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..7e4936f4 --- /dev/null +++ b/WebView/app/src/main/res/values/colors.xml @@ -0,0 +1,22 @@ + + + + + #6200EE + #3700B3 + #03DAC5 + diff --git a/WebView/app/src/main/res/values/strings.xml b/WebView/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..6e4563d5 --- /dev/null +++ b/WebView/app/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + WebView Weather + diff --git a/WebView/app/src/main/res/values/styles.xml b/WebView/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..278ded4e --- /dev/null +++ b/WebView/app/src/main/res/values/styles.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/WebView/app/src/test/java/com/android/samples/webviewdemo/ExampleUnitTest.kt b/WebView/app/src/test/java/com/android/samples/webviewdemo/ExampleUnitTest.kt new file mode 100644 index 00000000..c72b979b --- /dev/null +++ b/WebView/app/src/test/java/com/android/samples/webviewdemo/ExampleUnitTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.samples.webviewdemo + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/WebView/build.gradle b/WebView/build.gradle new file mode 100644 index 00000000..ffdb54e5 --- /dev/null +++ b/WebView/build.gradle @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 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. + */ + +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + appcompat_version = '1.1.0' + constraintlayout_version = '1.1.3' + core_ktx_version = '1.3.1' + fragment_ktx_version = '1.2.5' + kotlin_version = '1.3.72' + material_components_version = '1.1.0' + webkit_version = '1.3.0-rc01' + } + repositories { + google() + jcenter() + + } + dependencies { + classpath 'com.android.tools.build:gradle:4.0.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/WebView/gradle.properties b/WebView/gradle.properties new file mode 100644 index 00000000..8e926f09 --- /dev/null +++ b/WebView/gradle.properties @@ -0,0 +1,37 @@ +# +# Copyright (C) 2020 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. +# + +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official diff --git a/WebView/gradle/wrapper/gradle-wrapper.jar b/WebView/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..f6b961fd Binary files /dev/null and b/WebView/gradle/wrapper/gradle-wrapper.jar differ diff --git a/WebView/gradle/wrapper/gradle-wrapper.properties b/WebView/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..bb7705aa --- /dev/null +++ b/WebView/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,22 @@ +# +# Copyright (C) 2020 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. +# + +#Mon Aug 03 11:43:59 PDT 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/WebView/gradlew b/WebView/gradlew new file mode 100755 index 00000000..cccdd3d5 --- /dev/null +++ b/WebView/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/WebView/gradlew.bat b/WebView/gradlew.bat new file mode 100644 index 00000000..e95643d6 --- /dev/null +++ b/WebView/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/WebView/sampleData/weather.json b/WebView/sampleData/weather.json new file mode 100644 index 00000000..868d5468 --- /dev/null +++ b/WebView/sampleData/weather.json @@ -0,0 +1,26 @@ +{ + "newYork":{ + "currentTemp":75, + "highTemp":83, + "lowTemp":64, + "chancePrecip":90, + "humidity":23, + "description":"Rainy" + }, + "sanFrancisco":{ + "currentTemp":70, + "highTemp":75, + "lowTemp":61, + "chancePrecip":0, + "humidity":2, + "description":"Clear Sky" + }, + "london":{ + "currentTemp":88, + "highTemp":89, + "lowTemp":67, + "chancePrecip":15, + "humidity":36, + "description":"Partly Cloudy" + } +} \ No newline at end of file diff --git a/WebView/settings.gradle b/WebView/settings.gradle new file mode 100644 index 00000000..e292fcf3 --- /dev/null +++ b/WebView/settings.gradle @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 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. + */ + +rootProject.name='WebView Demo' +include ':app'