SlideShare une entreprise Scribd logo
1  sur  165
Télécharger pour lire hors ligne
the android
support libraries @KellyShuster
quick
history
@KellyShuster
2011
@KellyShuster
2011
@KellyShuster
★ v4 support library
★ v13 support library
2012
@KellyShuster
2012
@KellyShuster
2013
@KellyShuster
2013
@KellyShuster
★ v7 gridlayout
★ v7 appcompat
○ ActionBar
○ ActionBarActivity
★ V8 renderscript
2014
@KellyShuster
2014
@KellyShuster
★ v7 cardview
★ v7 recyclerview
★ v7 palette
★ v17 leanback
★ wear UI
2015
@KellyShuster
2015
@KellyShuster
★ annotations
★ design support
★ custom tabs support
★ percent support
★ app recommendation support (TV)
★ V7 preference support
★ V14 preference support
★ V17 preference support (TV)
2016
@KellyShuster
2016
@KellyShuster
★ vector drawable support
★ v4 library split
○ support-compat
○ support-core-utils
○ support-core-ui
○ support-media-compat
○ support-fragment
★ exifInterface support
2017
@KellyShuster
2017
@KellyShuster
★ dynamic animation
★ emoji compat
@KellyShuster
★ v4 support library
★ v13 support library
★ v7 gridlayout
★ v7 appcompat
★ V8 renderscript
★ v7 cardview
★ v7 recyclerview
★ v7 palette
★ v17 leanback
★ wear UI
★ annotations
★ design support
★ custom tabs support
★ percent support
★ app recommendation support (TV)
★ V7 preference support
★ V14 preference support
★ V17 preference support (TV)
★ vector drawable support
★ v4 library split
○ support-compat
○ support-core-utils
○ support-core-ui
○ support-media-compat
○ support-fragment
★ exifInterface support
★ dynamic animation
★ emoji compat
a few
general
tips @KellyShuster
appcompat-v7:25.1.0
@KellyShuster
appcompat-v7:25.1.0
@KellyShuster
appcompat-v7:25.1.0
@KellyShuster
appcompat-v7:25.1.0
@KellyShuster
nope
dependencies {
compile "com.android.support:appcompat-v7:25.1.0"
compile "com.android.support:recyclerview-v7:25.1.0"
compile "com.android.support:design:25.1.0"
...
}
buildscript {
ext.support_lib_version = '25.1.0'
...
}
dependencies {
compile "com.android.support:appcompat-v7:25.1.0"
compile "com.android.support:recyclerview-v7:25.1.0"
compile "com.android.support:design:25.1.0"
...
}
buildscript {
ext.support_lib_version = '25.1.0'
...
}
dependencies {
compile "com.android.support:appcompat-v7: $support_lib_version "
compile "com.android.support:recyclerview-v7: $support_lib_version "
compile "com.android.support:design: $support_lib_version "
...
}
./gradlew -q dependencies app:dependencies
beware
stubbed
methods! @KellyShuster
TextView textView = (TextView) findViewById(R.id.text);
ViewCompat.setElevation(textView, elevationInPx);
TextView textView = (TextView) findViewById(R.id.text);
ViewCompat.setElevation(textView, elevationInPx);
TextView textView = (TextView) findViewById(R.id.text);
ViewCompat.setElevation(textView, elevationInPx);
★ no lint warning
★ no compile error
★ just doesn’t work on pre-21 :(
popular
components @KellyShuster
appcompat-v7
ViewPager @KellyShuster
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/vpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
layout xml file
public class CustomPagerAdapter extends PagerAdapter {
private ArrayList<String> myData;
@Override
public Object instantiateItem(ViewGroup container, int position) {
FrameLayout flPage = (FrameLayout) LayoutInflater
.from(container.getContext())
.inflate(R.layout.page_layout, null, false);
TextView mytext = flPage.findViewById(R.id.pager_text);
mytext.setText(strings.get(position));
container.addView(flPage);
return flPage;
}
. . .
}
Custom pager adapter
public class CustomPagerAdapter extends PagerAdapter {
. . .
@Override
public int getCount() {
return myData.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object){
ViewPager pager = (ViewPager) container;
FrameLayout flPage = (FrameLayout) object;
pager.removeView(flPage);
}
}
custom pager adapter, cont’d.
PagerAdapter adapter = new CustomPagerAdapter(myData);
ViewPager viewPager = findViewById(R.id.vpager);
viewPager.setAdapter(adapter);
activity java file
design
TabLayout @KellyShuster
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"/>
<android.support.v4.view.ViewPager
android:id="@+id/vpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
layout xml file
public class CustomPagerAdapter extends PagerAdapter {
. . .
@Override
public CharSequence getPageTitle(int position) {
return String.format("Title #%s", position);
}
. . .
}
custom pager adapter
PagerAdapter adapter = new CustomPagerAdapter(myData);
ViewPager viewPager = findViewById(R.id.vpager);
viewPager.setAdapter(adapter);
TabLayout tabLayout = findViewById(R.id.tablayout);
tabLayout.setupWithViewPager(viewPager, true);
activity java file
appcompat-v7
Toolbar @KellyShuster
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<!-- Customize your theme here. -->
</style>
styles xml file
<android.support.v7.widget.Toolbar
android:id="@+id/t_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize">
<LinearLayout>
<ImageView />
<TextView />
</LinearLayout>
</android.support.v7.widget.Toolbar>
layout xml file
Toolbar toolbar = (Toolbar) findViewById(R.id.t_toolbar);
setSupportActionBar(toolbar);
activity java file
design
CoordinatorLayout @KellyShuster
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView>
<LinearLayout/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView>
<LinearLayout/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView>
<LinearLayout/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView>
<LinearLayout/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView>
<LinearLayout/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout
app:layout_scrollFlags="scroll|enterAlways"
app:contentScrim="?attr/colorPrimary">
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout
app:layout_scrollFlags="scroll|enterAlways"
app:contentScrim="?attr/colorPrimary">
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<!-- Toolbar -->
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout
app:layout_scrollFlags="scroll|enterAlways"
app:contentScrim="?attr/colorPrimary">
<include layout="@layout/view_toolbar_image" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Main Content -->
<android.support.v4.widget.NestedScrollView
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
design
FloatingActionButton
Snackbar
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"/>
FloatingActionButton fab =
(FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make( view,
"Yay, I love 360|AnDev!",
Snackbar.LENGTH_SHORT)
.show();
}
});
FloatingActionButton fab =
(FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make( view,
"Yay, I love 360|AnDev!",
Snackbar.LENGTH_SHORT)
.show();
}
});
FloatingActionButton fab =
(FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make( view,
"Yay, I love 360|AnDev!",
Snackbar.LENGTH_SHORT)
.show();
}
});
FloatingActionButton fab =
(FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make( view,
"Yay, I love 360|AnDev!",
Snackbar.LENGTH_SHORT)
.show();
}
});
<android.support.design.widget.CoordinatorLayout>
<LinearLayout>
<TextView />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"/>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.CoordinatorLayout>
<LinearLayout>
<TextView />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"/>
</android.support.design.widget.CoordinatorLayout>
design
TextInputLayout
<android.support.design.widget.TextInputLayout
android:id="@+id/til_first_name"
style="@style/Theme.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorTextAppearance="@style/Theme.TextInputLayoutError">
<TextInputEditText
android:id="@+id/tiet_first_name"
style="@style/Theme.EditText.NewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/common_hint_first_name"
android:imeOptions="actionNext"
android:inputType="textPersonName"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/til_first_name"
style="@style/Theme.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorTextAppearance="@style/Theme.TextInputLayoutError">
<TextInputEditText
android:id="@+id/tiet_first_name"
style="@style/Theme.EditText.NewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/common_hint_first_name"
android:imeOptions="actionNext"
android:inputType="textPersonName"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/til_first_name"
style="@style/Theme.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorTextAppearance="@style/Theme.TextInputLayoutError">
<TextInputEditText
android:id="@+id/tiet_first_name"
style="@style/Theme.EditText.NewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/common_hint_first_name"
android:imeOptions="actionNext"
android:inputType="textPersonName"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/til_first_name"
style="@style/Theme.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorTextAppearance="@style/Theme.TextInputLayoutError">
<TextInputEditText
android:id="@+id/tiet_first_name"
style="@style/Theme.EditText.NewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/common_hint_first_name"
android:imeOptions="actionNext"
android:inputType="textPersonName"/>
</android.support.design.widget.TextInputLayout>
<style name="Theme.TextInputLayout" parent="TextAppearance.AppCompat">
<!-- Static state: Hint color -->
<item name="android:textColorHint">@color/gray_94</item>
<item name="android:textColor">@color/gray_94</item>
<!-- Focused state: Hint style -->
<item name="hintTextAppearance">@style/Theme.Text.Subhead.Reg.94</item>
</style>
styles
<style name="Theme.TextInputLayoutError" parent="TextAppearance.AppCompat">
<item name="android:textColor">@color/darkest_pink</item>
</style>
styles
<style name="Theme.EditText.NewStyle"
parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Static state: Bottom line color -->
<item name="colorControlNormal">@color/gray_cb</item>
<!-- Focused state: Bottom line color -->
<item name="colorControlActivated">@color/gray_cb</item>
<item name="android:textColor">@color/gray_4a</item>
<item name="android:textColorHighlight">@color/gray_cb</item>
. . .
</style>
styles
@Override
public void setFirstNameInputStateValid() {
tilFirstName.setError(null);
tilFirstName.setErrorEnabled(false);
}
@Override
public void setFirstNameInputStateError() {
tilFirstName.setErrorEnabled(true);
tilFirstName.setError(getString(
R.string.common_invalid_first_name));
}
@Override
public void setFirstNameInputStateValid() {
tilFirstName.setError(null);
tilFirstName.setErrorEnabled(false);
}
@Override
public void setFirstNameInputStateError() {
tilFirstName.setErrorEnabled(true);
tilFirstName.setError(getString(
R.string.common_invalid_first_name));
}
@Override
public void setFirstNameInputStateValid() {
tilFirstName.setError(null);
tilFirstName.setErrorEnabled(false);
}
@Override
public void setFirstNameInputStateError() {
tilFirstName.setErrorEnabled(true);
tilFirstName.setError(getString(
R.string.common_invalid_first_name));
}
@Override
public void setFirstNameInputStateValid() {
tilFirstName.setError(null);
tilFirstName.setErrorEnabled(false);
}
@Override
public void setFirstNameInputStateError() {
tilFirstName.setErrorEnabled(true);
tilFirstName.setError(getString(
R.string.common_invalid_first_name));
}
percent
PercentRelativeLayout
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/centered_image_2"
android:layout_gravity="center"
android:contentDescription="Android Robot"
android:src="@mipmap/ic_launcher"
app:layout_heightPercent="30%"
app:layout_widthPercent="50%"/>
</android.support.percent.PercentRelativeLayout>
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/centered_image_2"
android:layout_gravity="center"
android:contentDescription="Android Robot"
android:src="@mipmap/ic_launcher"
app:layout_heightPercent="30%"
app:layout_widthPercent="50%"/>
</android.support.percent.PercentRelativeLayout>
constraint-layout
ConstraintLayout
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Constraint Layout Demo"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
support-vector-drawable
vector
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5
1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67
1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67
2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8
3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5
1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5
-1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2
-0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23
-2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51
0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75
-2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5
1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67
1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67
2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8
3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5
1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5
-1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2
-0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23
-2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51
0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75
-2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
</vector>
android {
defaultConfig {
. . .
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
. . .
compile "com.android.support:support-vector-drawable:26.0.0"
}
android {
defaultConfig {
. . .
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
. . .
compile "com.android.support:support-vector-drawable:26.0.0"
}
android {
defaultConfig {
. . .
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
. . .
compile "com.android.support:support-vector-drawable:26.0.0"
}
<ImageView
android:id="@+id/imageView"
android:layout_width="240dp"
android:layout_height="280dp"
android:layout_centerInParent="true"
app:srcCompat="@drawable/ic_android_black_24dp"/>
<ImageView
android:id="@+id/imageView"
android:layout_width="240dp"
android:layout_height="280dp"
android:layout_centerInParent="true"
app:srcCompat="@drawable/ic_android_black_24dp"/>
ImageView ivBugDroid = (ImageView) findViewById(imageView);
ivBugDroid.setImageDrawable(AppCompatResources.getDrawable(
this, R.drawable.ic_android_black_24dp));
ImageView ivBugDroid = (ImageView) findViewById(imageView);
ivBugDroid.setImageDrawable(AppCompatResources.getDrawable(
this, R.drawable.ic_android_black_24dp));
<ImageView
android:id="@+id/imageView"
android:layout_width="240dp"
android:layout_height="280dp"
android:layout_centerInParent="true"
android:src="@drawable/ic_android_black_24dp"/>
25.0.0
to
25.3.1 @KellyShuster
support-v7
ArraySet
ArraySet
@KellyShuster
★ previously only available in API 23+
ArraySet
@KellyShuster
★ previously only available in API 23+
★ now in v4 lib as of 25.1.0
ArraySet
@KellyShuster
★ previously only available in API 23+
★ now in v4 lib as of 25.1.0
★ more efficient than traditional HashSet
ArraySet
@KellyShuster
★ previously only available in API 23+
★ now in v4 lib as of 25.1.0
★ more efficient than traditional HashSet
★ similar to ArrayMap, but contains only 1 item
per entry
ArraySet
@KellyShuster
★ previously only available in API 23+
★ now in v4 Lib as of 25.1.0
★ more efficient than traditional HashSet
★ similar to ArrayMap, but contains only 1 item
per entry
★ not for large items (slower than HashSet)
○ hundreds of items == OK
ArraySet
@KellyShuster
★ previously only available in API 23+
★ now in v4 Lib as of 25.1.0
★ more efficient than traditional HashSet
★ similar to ArrayMap, but contains only 1 item
per entry
★ not for large items (slower than HashSet)
○ hundreds of items == OK
★ shrinks as items are removed
○ you have no control over shrinking
design
BottomNavigationView
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
app:menu="@menu/bottom_nav_items"/>
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
app:menu="@menu/bottom_nav_items"/>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_search"
android:title="Search (black)"
android:icon="@android:drawable/ic_menu_search" />
<item android:id="@+id/action_camera"
android:title="Camera (blue)"
android:icon="@android:drawable/ic_menu_camera" />
<item android:id="@+id/action_email"
android:title="Email (red)"
android:icon="@android:drawable/ic_dialog_email" />
</menu>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_search"
android:title="Search (black)"
android:icon="@android:drawable/ic_menu_search" />
<item android:id="@+id/action_camera"
android:title="Camera (blue)"
android:icon="@android:drawable/ic_menu_camera" />
<item android:id="@+id/action_email"
android:title="Email (red)"
android:icon="@android:drawable/ic_dialog_email" />
</menu>
BottomNavigationView bottomNav = (BottomNavigationView) findViewById(R.id.bottom_nav);
bottomNav.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
ivBugDroid.setImageDrawable(...);
return true;
case R.id.action_camera:
ivBugDroid.setImageDrawable(...);
return true;
case R.id.action_email:
ivBugDroid.setImageDrawable(...);
return true;
}
return false;
}
});
BottomNavigationView bottomNav = (BottomNavigationView) findViewById(R.id.bottom_nav);
bottomNav.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
ivBugDroid.setImageDrawable(...);
return true;
case R.id.action_camera:
ivBugDroid.setImageDrawable(...);
return true;
case R.id.action_email:
ivBugDroid.setImageDrawable(...);
return true;
}
return false;
}
});
BottomNavigationView bottomNav = (BottomNavigationView) findViewById(R.id.bottom_nav);
bottomNav.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
ivBugDroid.setImageDrawable(...);
return true;
case R.id.action_camera:
ivBugDroid.setImageDrawable(...);
return true;
case R.id.action_email:
ivBugDroid.setImageDrawable(...);
return true;
}
return false;
}
});
what’s
new in
support 26 @KellyShuster
API 14+
maven support @KellyShuster
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
allprojects {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
allprojects {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
allprojects {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
}
fonts @KellyShuster
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button_constraint"
android:layout_margin="10dp"
android:fontFamily="@font/bellefair_regular"
android:text="This is fancy stuff!"
android:textSize="24dp"
android:visibility="visible"/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button_constraint"
android:layout_margin="10dp"
android:fontFamily="@font/bellefair_regular"
android:text="This is fancy stuff!"
android:textSize="24dp"
android:visibility="visible"/>
TextView textView2 = (TextView) findViewById(R.id.text2);
Typeface tfBelleFair = ResourcesCompat.getFont(
this, R.font.bellefair_regular);
textView2.setTypeface(tfBelleFair);
TextView textView2 = (TextView) findViewById(R.id.text2);
Typeface tfBelleFair = ResourcesCompat.getFont(
this, R.font.bellefair_regular);
textView2.setTypeface(tfBelleFair);
font
families @KellyShuster
<font-family
xmlns:app="http://schemas.android.com/apk/res-auto">
<font
app:font="@font/bellefair_regular"
app:fontStyle="normal"
app:fontWeight="400"/>
</font-family>
<style name="customfontstyle" parent="@android:style/TextAppearance.Small">
<item name="android:fontFamily">@font/bellefair_regular</item>
</style>
<TextView
android:id="@+id/text2"
style="@style/customfontstyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text"
android:layout_margin="10dp"
android:text="This is regular stuff"
android:textSize="24dp"
android:visibility="visible"/>
autoscale
TextView @KellyShuster
<TextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Layout Height 100dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="10dp"
android:text="Layout Height 10dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Layout Height 100dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="10dp"
android:text="Layout Height 10dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Layout Height 100dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="10dp"
android:text="Layout Height 10dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Layout Height 100dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="10dp"
android:text="Layout Height 10dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Layout Height 100dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="10dp"
android:text="Layout Height 10dp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform"/>
findViewById @KellyShuster
All instances of the
findViewById() method now return
<T extends View> T
instead of
View
thank
you! @KellyShuster
Resources
● Coordinator Layout
https://medium.com/google-developers/intercepting-everything-with-coordinatorlayout-behaviors-8c6adc140c26
● Huyen Tue Dao “Cool Constraint Layout”https://www.youtube.com/watch?v=Xx4aRI3oQbM
● Bottom Navigation View flow https://material.io/guidelines/components/bottom-navigation.html#
● Google IO What’s New in Support Library 2017https://www.youtube.com/watch?v=V6-roIeNUY0
References
● Royal Gorge Bridge http://royalgorgebridge.com/
● Snackbar gif https://material.io/guidelines/components/snackbars-toasts.html#snackbars-toasts-usage
● TextInputLayout Images
https://stackoverflow.com/questions/35775919/edittext-added-is-not-a-textinputedittext-please-switch-to-us
ing-that-class-ins
● Crying Pikachu gif https://giphy.com/search/sad-pikachu
● Ice Cream Sandwich http://cookdiary.net/ice-cream-sandwich/
● Happy Pokemon gif
http://rebloggy.com/post/gif-pikachu-pokemon-happy-good-yay-aww-yes-jump-shiny-togepi-bulbasaur-jumping-g/
77419268976
● SVG icon http://www.clker.com/clipart-336030.html

Contenu connexe

Similaire à Android Support Libraries

Similaire à Android Support Libraries (20)

Embracing the Lollipop
Embracing the LollipopEmbracing the Lollipop
Embracing the Lollipop
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Recyclerview in action
Recyclerview in action Recyclerview in action
Recyclerview in action
 
Fragments anyone
Fragments anyone Fragments anyone
Fragments anyone
 
Android accessibility for developers and QA
Android accessibility for developers and QAAndroid accessibility for developers and QA
Android accessibility for developers and QA
 
Architecture Components In Real Life Season 2
Architecture Components In Real Life Season 2Architecture Components In Real Life Season 2
Architecture Components In Real Life Season 2
 
Service Oriented Architecture in Magento 2
Service Oriented Architecture in Magento 2Service Oriented Architecture in Magento 2
Service Oriented Architecture in Magento 2
 
Developing Android and iOS Apps With C#, .NET, Xamarin, Mono, and Windows Azure
Developing Android and iOS Apps With C#, .NET, Xamarin, Mono, and Windows AzureDeveloping Android and iOS Apps With C#, .NET, Xamarin, Mono, and Windows Azure
Developing Android and iOS Apps With C#, .NET, Xamarin, Mono, and Windows Azure
 
Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)
 
Red Hat JBoss BRMS and BPMS Workbench and Rich Client Technology
Red Hat JBoss BRMS and BPMS Workbench and Rich Client TechnologyRed Hat JBoss BRMS and BPMS Workbench and Rich Client Technology
Red Hat JBoss BRMS and BPMS Workbench and Rich Client Technology
 
07_UIAndroid.pdf
07_UIAndroid.pdf07_UIAndroid.pdf
07_UIAndroid.pdf
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
 
Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017
Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017
Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
Modern android development
Modern android developmentModern android development
Modern android development
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Binding business data to vaadin components
Binding business data to vaadin componentsBinding business data to vaadin components
Binding business data to vaadin components
 
Dicoding Developer Coaching #30: Android | Mengenal Macam-Macam Software Desi...
Dicoding Developer Coaching #30: Android | Mengenal Macam-Macam Software Desi...Dicoding Developer Coaching #30: Android | Mengenal Macam-Macam Software Desi...
Dicoding Developer Coaching #30: Android | Mengenal Macam-Macam Software Desi...
 
My way to clean android (EN) - Android day salamanca edition
My way to clean android (EN) - Android day salamanca editionMy way to clean android (EN) - Android day salamanca edition
My way to clean android (EN) - Android day salamanca edition
 
Geb Best Practices
Geb Best PracticesGeb Best Practices
Geb Best Practices
 

Plus de Kelly Shuster

Intro to Android (WWC Denver July 2015)
Intro to Android (WWC Denver July 2015)Intro to Android (WWC Denver July 2015)
Intro to Android (WWC Denver July 2015)
Kelly Shuster
 

Plus de Kelly Shuster (8)

Technical speaking 101
Technical speaking 101Technical speaking 101
Technical speaking 101
 
Let's Build Software Everyone Can Use (Denver Startup Week 2016)
Let's Build Software Everyone Can Use (Denver Startup Week 2016)Let's Build Software Everyone Can Use (Denver Startup Week 2016)
Let's Build Software Everyone Can Use (Denver Startup Week 2016)
 
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
 
Lightning Talk on Programming Accessible Software
Lightning Talk on Programming Accessible SoftwareLightning Talk on Programming Accessible Software
Lightning Talk on Programming Accessible Software
 
Android Accessibility - Droidcon London
Android Accessibility - Droidcon LondonAndroid Accessibility - Droidcon London
Android Accessibility - Droidcon London
 
Android Internal Library Management
Android Internal Library ManagementAndroid Internal Library Management
Android Internal Library Management
 
Intro to Android (WWC Denver July 2015)
Intro to Android (WWC Denver July 2015)Intro to Android (WWC Denver July 2015)
Intro to Android (WWC Denver July 2015)
 
Android Accessibility - DroidCon Berlin 2015
Android Accessibility - DroidCon Berlin 2015Android Accessibility - DroidCon Berlin 2015
Android Accessibility - DroidCon Berlin 2015
 

Dernier

CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
anilsa9823
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
anilsa9823
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 

Dernier (20)

Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 

Android Support Libraries