Skip to content
This repository was archived by the owner on Feb 3, 2020. It is now read-only.

Commit f5ad373

Browse files
Merge pull request #90 from recruit-lifestyle/feature/support_p
Support Android P
2 parents 4b0e352 + 909a531 commit f5ad373

File tree

11 files changed

+268
-83
lines changed

11 files changed

+268
-83
lines changed

README.md

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# FloatingView
22
The Android project is View to display information such as chat in front.
3-
To API Level 14 or later are supported
3+
To API Level 14 or higher are supported
44

55
## Screenshots
66
![](./screenshot/animation.gif)
@@ -12,7 +12,7 @@ To API Level 14 or later are supported
1212
[SimpleFloating](http://youtu.be/nb8M2p0agF4)
1313

1414
## Requirements
15-
Target Sdk Version : 27
15+
Target Sdk Version : 28
1616
Min Sdk Version : 14
1717

1818
## How to use
@@ -66,6 +66,7 @@ Describe the process (`onFinishFloatingView`) that is called when you exit the F
6666
5) Add the permission to AndroidManifest
6767
```xml
6868
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
69+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
6970
```
7071

7172
6) Define the Service to AndroidManifest
@@ -83,11 +84,27 @@ example)
8384
```
8485

8586
7) Describe the process to start the Service (run on foreground)
87+
88+
89+
example)
90+
91+
- FloatingViewControlFragment.java
92+
8693
```java
8794
final Intent intent = new Intent(activity, ChatHeadService.class);
8895
ContextCompat.startForegroundService(activity, intent);
8996
```
9097

98+
- ChatHeadService.java
99+
100+
```java
101+
public int onStartCommand(Intent intent, int flags, int startId) {
102+
...
103+
startForeground(NOTIFICATION_ID, createNotification(this));
104+
...
105+
}
106+
```
107+
91108
8) Create notification channel (targetSdkVersion >= 26)
92109

93110
example)
@@ -104,6 +121,37 @@ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
104121

105122
```
106123

124+
9) Add DisplayCutout process(API Level >= 28)
125+
126+
Note: `DisplayCutout` is obtained from `Fragment` or `Activity` (You can not get `DisplayCutout` from `Service`)
127+
Note: You must set the `DisplayCutout` obtained on portrait orientation.
128+
Note: You must not set `windowLayoutInDisplayCutoutMode` to `never` when getting a `DisplayCutout`.
129+
130+
example)
131+
132+
- FloatingViewControlFragment.java
133+
134+
```java
135+
final Rect safeInsetRect = new Rect();
136+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
137+
final DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
138+
if (displayCutout != null) {
139+
safeInsetRect.set(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(), displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());
140+
}
141+
}
142+
143+
final Intent intent = new Intent(activity, ChatHeadService.class);
144+
intent.putExtra(ChatHeadService.EXTRA_CUTOUT_SAFE_AREA, safeInsetRect);
145+
ContextCompat.startForegroundService(activity, intent);
146+
```
147+
148+
- ChatHeadService.java
149+
150+
```java
151+
mFloatingViewManager.setSafeInsetRect((Rect) intent.getParcelableExtra(EXTRA_CUTOUT_SAFE_AREA));
152+
```
153+
154+
107155
## Static Options
108156
It can be set only when displaying for the first time
109157

build.gradle

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
google()
77
}
88
dependencies {
9-
classpath 'com.android.tools.build:gradle:3.1.2'
9+
classpath 'com.android.tools.build:gradle:3.3.0-alpha10'
1010
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
1111
// NOTE: Do not place your application dependencies here; they belong
1212
// in the individual module build.gradle files
@@ -19,11 +19,4 @@ allprojects {
1919
jcenter()
2020
google()
2121
}
22-
}
23-
24-
ext {
25-
compileSdkVersion = 27
26-
buildToolsVersion = '27.0.3'
27-
targetSdkVersion = 27
28-
minSdkVersion = 14
29-
}
22+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Mon May 07 16:30:08 JST 2018
1+
#Fri Sep 14 15:32:46 JST 2018
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip

library/build.gradle

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
apply plugin: 'com.android.library'
22

33
android {
4-
compileSdkVersion rootProject.ext.compileSdkVersion as Integer
5-
buildToolsVersion rootProject.ext.buildToolsVersion as String
4+
compileSdkVersion 28
5+
buildToolsVersion '28.0.2'
66

77
defaultConfig {
8-
minSdkVersion rootProject.ext.minSdkVersion as Integer
9-
targetSdkVersion rootProject.ext.targetSdkVersion as Integer
8+
minSdkVersion 14
9+
targetSdkVersion 28
1010
versionCode 1
1111
versionName "1.0"
1212
}
1313
}
1414

1515
dependencies {
16-
implementation 'com.android.support:support-annotations:27.1.1'
17-
implementation 'com.android.support:support-compat:27.1.1'
18-
implementation 'com.android.support:support-dynamic-animation:27.1.1'
16+
implementation 'com.android.support:support-annotations:28.0.0-rc02'
17+
implementation 'com.android.support:support-compat:28.0.0-rc02'
18+
implementation 'com.android.support:support-dynamic-animation:28.0.0-rc02'
1919
}
2020

2121
// build a jar with source files

library/src/main/java/jp/co/recruit_lifestyle/android/floatingview/FloatingView.java

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,15 @@ class FloatingView extends FrameLayout implements ViewTreeObserver.OnPreDrawList
277277
private boolean mAnimateInitialMove;
278278

279279
/**
280-
* ステータスバーの高さ
280+
* status bar's height
281281
*/
282282
private final int mBaseStatusBarHeight;
283283

284+
/**
285+
* status bar's height(landscape)
286+
*/
287+
private int mBaseStatusBarRotatedHeight;
288+
284289
/**
285290
* Current status bar's height
286291
*/
@@ -313,6 +318,11 @@ class FloatingView extends FrameLayout implements ViewTreeObserver.OnPreDrawList
313318
*/
314319
private int mTouchXOffset;
315320

321+
/**
322+
* Offset of touch Y coordinate
323+
*/
324+
private int mTouchYOffset;
325+
316326
/**
317327
* 左・右端に寄せるアニメーション
318328
*/
@@ -388,6 +398,11 @@ class FloatingView extends FrameLayout implements ViewTreeObserver.OnPreDrawList
388398
*/
389399
private int mRotation;
390400

401+
/**
402+
* Cutout safe inset rect(Same as FloatingViewManager's mSafeInsetRect)
403+
*/
404+
private final Rect mSafeInsetRect;
405+
391406
static {
392407
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
393408
OVERLAY_TYPE = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
@@ -427,10 +442,17 @@ class FloatingView extends FrameLayout implements ViewTreeObserver.OnPreDrawList
427442

428443
mMoveLimitRect = new Rect();
429444
mPositionLimitRect = new Rect();
445+
mSafeInsetRect = new Rect();
430446

431447
// ステータスバーの高さを取得
432448
mBaseStatusBarHeight = getSystemUiDimensionPixelSize(resources, "status_bar_height");
433-
mStatusBarHeight = mBaseStatusBarHeight;
449+
// Check landscape resource id
450+
final int statusBarLandscapeResId = resources.getIdentifier("status_bar_height_landscape", "dimen", "android");
451+
if (statusBarLandscapeResId > 0) {
452+
mBaseStatusBarRotatedHeight = getSystemUiDimensionPixelSize(resources, "status_bar_height_landscape");
453+
} else {
454+
mBaseStatusBarRotatedHeight = mBaseStatusBarHeight;
455+
}
434456

435457
// Init physics-based animation properties
436458
updateViewConfiguration();
@@ -546,18 +568,69 @@ public boolean onPreDraw() {
546568
* @param isHideStatusBar If true, the status bar is hidden
547569
* @param isHideNavigationBar If true, the navigation bar is hidden
548570
* @param isPortrait If true, the device orientation is portrait
549-
* @param hasTouchXOffset If true, offset is required for touched X coordinate
571+
* @param windowLeftOffset Left side offset of device display
550572
*/
551-
void onUpdateSystemLayout(boolean isHideStatusBar, boolean isHideNavigationBar, boolean isPortrait, boolean hasTouchXOffset) {
573+
void onUpdateSystemLayout(boolean isHideStatusBar, boolean isHideNavigationBar, boolean isPortrait, int windowLeftOffset) {
552574
// status bar
553-
mStatusBarHeight = isHideStatusBar ? 0 : mBaseStatusBarHeight;
554-
// touch X offset(navigation bar is displayed and it is on the left side of the device)
555-
mTouchXOffset = !isHideNavigationBar && hasTouchXOffset ? mBaseNavigationBarRotatedHeight : 0;
575+
updateStatusBarHeight(isHideStatusBar, isPortrait);
576+
// touch X offset(support Cutout)
577+
updateTouchXOffset(isHideNavigationBar, windowLeftOffset);
578+
// touch Y offset(support Cutout)
579+
mTouchYOffset = isPortrait ? mSafeInsetRect.top : 0;
556580
// navigation bar
557581
updateNavigationBarOffset(isHideNavigationBar, isPortrait);
558582
refreshLimitRect();
559583
}
560584

585+
/**
586+
* Update height of StatusBar.
587+
*
588+
* @param isHideStatusBar If true, the status bar is hidden
589+
* @param isPortrait If true, the device orientation is portrait
590+
*/
591+
private void updateStatusBarHeight(boolean isHideStatusBar, boolean isPortrait) {
592+
if (isHideStatusBar) {
593+
// 1.(No Cutout)No StatusBar(=0)
594+
// 2.(Has Cutout)StatusBar is not included in mMetrics.heightPixels (=0)
595+
mStatusBarHeight = 0;
596+
return;
597+
}
598+
599+
// Has Cutout
600+
final boolean hasTopCutout = mSafeInsetRect.top != 0;
601+
if (hasTopCutout) {
602+
if (isPortrait) {
603+
mStatusBarHeight = 0;
604+
} else {
605+
mStatusBarHeight = mBaseStatusBarRotatedHeight;
606+
}
607+
return;
608+
}
609+
610+
// No cutout
611+
if (isPortrait) {
612+
mStatusBarHeight = mBaseStatusBarHeight;
613+
} else {
614+
mStatusBarHeight = mBaseStatusBarRotatedHeight;
615+
}
616+
}
617+
618+
/**
619+
* Update of touch X coordinate
620+
*
621+
* @param isHideNavigationBar If true, the navigation bar is hidden
622+
* @param windowLeftOffset Left side offset of device display
623+
*/
624+
private void updateTouchXOffset(boolean isHideNavigationBar, int windowLeftOffset) {
625+
final boolean noBottomCutout = mSafeInsetRect.bottom == 0;
626+
if (noBottomCutout) {
627+
// touch X offset(navigation bar is displayed and it is on the left side of the device)
628+
mTouchXOffset = !isHideNavigationBar && windowLeftOffset > 0 ? mBaseNavigationBarRotatedHeight : 0;
629+
} else {
630+
mTouchXOffset = windowLeftOffset;
631+
}
632+
}
633+
561634
/**
562635
* Update offset of NavigationBar.
563636
*
@@ -1327,7 +1400,7 @@ private int getXByTouch() {
13271400
* @return FloatingViewのY座標
13281401
*/
13291402
private int getYByTouch() {
1330-
return (int) (mMetrics.heightPixels + mNavigationBarVerticalOffset - (mScreenTouchY - mLocalTouchY + getHeight()));
1403+
return (int) (mMetrics.heightPixels + mNavigationBarVerticalOffset - (mScreenTouchY - mLocalTouchY + getHeight() - mTouchYOffset));
13311404
}
13321405

13331406
/**
@@ -1362,6 +1435,15 @@ int getState() {
13621435
return mAnimationHandler.getState();
13631436
}
13641437

1438+
/**
1439+
* Set the cutout's safe inset area
1440+
*
1441+
* @param safeInsetRect {@link FloatingViewManager#setSafeInsetRect(Rect)}
1442+
*/
1443+
void setSafeInsetRect(Rect safeInsetRect) {
1444+
mSafeInsetRect.set(safeInsetRect);
1445+
}
1446+
13651447
/**
13661448
* アニメーションの制御を行うハンドラです。
13671449
*/
@@ -1520,7 +1602,7 @@ else if (mState == FloatingView.STATE_INTERSECTING) {
15201602
* アニメーション時間から求められる位置を計算します。
15211603
*
15221604
* @param timeRate 時間比率
1523-
* @return ベースとなる係数(0.0から1.0α)
1605+
* @return ベースとなる係数(0.0から1.0α)
15241606
*/
15251607
private static float calcAnimationPosition(float timeRate) {
15261608
final float position;

0 commit comments

Comments
 (0)