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

Commit

Permalink
Merge pull request #92 from recruit-lifestyle/feature/2.4.0-beta01
Browse files Browse the repository at this point in the history
Ver 2.4.0 beta01
  • Loading branch information
YoshihideSogawa authored Sep 28, 2018
2 parents 3fcb929 + 857ef6c commit b95b5d5
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 60 deletions.
16 changes: 4 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,25 +123,17 @@ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

9) Add DisplayCutout process(API Level >= 28)

Note: `DisplayCutout` is obtained from `Fragment` or `Activity` (You can not get `DisplayCutout` from `Service`)
Note: You must set the `DisplayCutout` obtained on portrait orientation.
Note: You must not set `windowLayoutInDisplayCutoutMode` to `never` when getting a `DisplayCutout`.
Call `FloatingViewManager.findCutoutSafeArea(activity)`.
Note: Activity must be portrait oriented.
Note: You must not set `windowLayoutInDisplayCutoutMode` to `never`.

example)

- FloatingViewControlFragment.java

```java
final Rect safeInsetRect = new Rect();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
final DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
safeInsetRect.set(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(), displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());
}
}

final Intent intent = new Intent(activity, ChatHeadService.class);
intent.putExtra(ChatHeadService.EXTRA_CUTOUT_SAFE_AREA, safeInsetRect);
intent.putExtra(ChatHeadService.EXTRA_CUTOUT_SAFE_AREA, FloatingViewManager.findCutoutSafeArea(activity));
ContextCompat.startForegroundService(activity, intent);
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0-alpha11'
classpath 'com.android.tools.build:gradle:3.2.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand Down
10 changes: 4 additions & 6 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ apply plugin: 'com.android.library'

android {
compileSdkVersion 28
buildToolsVersion '28.0.2'

defaultConfig {
minSdkVersion 14
targetSdkVersion 28
Expand All @@ -13,9 +11,9 @@ android {
}

dependencies {
implementation 'com.android.support:support-annotations:28.0.0-rc02'
implementation 'com.android.support:support-compat:28.0.0-rc02'
implementation 'com.android.support:support-dynamic-animation:28.0.0-rc02'
implementation 'com.android.support:support-annotations:28.0.0'
implementation 'com.android.support:support-compat:28.0.0'
implementation 'com.android.support:support-dynamic-animation:28.0.0'
}

// build a jar with source files
Expand All @@ -25,7 +23,7 @@ task sourcesJar(type: Jar) {
}

task javadoc(type: Javadoc) {
failOnError false
failOnError false
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,15 @@ class FloatingView extends FrameLayout implements ViewTreeObserver.OnPreDrawList
/**
* status bar's height(landscape)
*/
private int mBaseStatusBarRotatedHeight;
private final int mBaseStatusBarRotatedHeight;

/**
* Current status bar's height
*/
private int mStatusBarHeight;

/**
* Navigation bar's height(portlait)
* Navigation bar's height(portrait)
*/
private final int mBaseNavigationBarHeight;

Expand Down Expand Up @@ -568,17 +568,17 @@ public boolean onPreDraw() {
* @param isHideStatusBar If true, the status bar is hidden
* @param isHideNavigationBar If true, the navigation bar is hidden
* @param isPortrait If true, the device orientation is portrait
* @param windowLeftOffset Left side offset of device display
* @param windowRect {@link Rect} of system window
*/
void onUpdateSystemLayout(boolean isHideStatusBar, boolean isHideNavigationBar, boolean isPortrait, int windowLeftOffset) {
void onUpdateSystemLayout(boolean isHideStatusBar, boolean isHideNavigationBar, boolean isPortrait, Rect windowRect) {
// status bar
updateStatusBarHeight(isHideStatusBar, isPortrait);
// touch X offset(support Cutout)
updateTouchXOffset(isHideNavigationBar, windowLeftOffset);
updateTouchXOffset(isHideNavigationBar, windowRect.left);
// touch Y offset(support Cutout)
mTouchYOffset = isPortrait ? mSafeInsetRect.top : 0;
// navigation bar
updateNavigationBarOffset(isHideNavigationBar, isPortrait);
updateNavigationBarOffset(isHideNavigationBar, isPortrait, windowRect);
refreshLimitRect();
}

Expand Down Expand Up @@ -636,17 +636,54 @@ private void updateTouchXOffset(boolean isHideNavigationBar, int windowLeftOffse
*
* @param isHideNavigationBar If true, the navigation bar is hidden
* @param isPortrait If true, the device orientation is portrait
*/
private void updateNavigationBarOffset(boolean isHideNavigationBar, boolean isPortrait) {
* @param windowRect {@link Rect} of system window
*/
private void updateNavigationBarOffset(boolean isHideNavigationBar, boolean isPortrait, Rect windowRect) {
int currentNavigationBarHeight = 0;
int currentNavigationBarWidth = 0;
int navigationBarVerticalDiff = 0;
final boolean hasSoftNavigationBar = hasSoftNavigationBar();
// auto hide navigation bar(Galaxy S8, S9 and so on.)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
final DisplayMetrics realDisplayMetrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getRealMetrics(realDisplayMetrics);
currentNavigationBarHeight = realDisplayMetrics.heightPixels - windowRect.bottom;
currentNavigationBarWidth = realDisplayMetrics.widthPixels - mMetrics.widthPixels;
navigationBarVerticalDiff = mBaseNavigationBarHeight - currentNavigationBarHeight;
}

if (!isHideNavigationBar) {
mNavigationBarVerticalOffset = 0;
// auto hide navigation bar
// 他デバイスとの矛盾をもとに推測する
// 1.デバイスに組み込まれたナビゲーションバー(mBaseNavigationBarHeight == 0)はシステムの状態によって高さに差が発生しない
// 2.デバイスに組み込まれたナビゲーションバー(!hasSoftNavigationBar)は意図的にBaseを0にしているので、矛盾している
if (navigationBarVerticalDiff != 0 && mBaseNavigationBarHeight == 0 ||
!hasSoftNavigationBar && mBaseNavigationBarHeight != 0) {
if (hasSoftNavigationBar) {
// 1.auto hide mode -> show mode
// 2.show mode -> auto hide mode -> home
mNavigationBarVerticalOffset = 0;
} else {
// show mode -> home
mNavigationBarVerticalOffset = -currentNavigationBarHeight;
}
} else {
// normal device
mNavigationBarVerticalOffset = 0;
}

mNavigationBarHorizontalOffset = 0;
return;
}

// If the portrait, is displayed at the bottom of the screen
if (isPortrait) {
mNavigationBarVerticalOffset = mBaseNavigationBarHeight;
// auto hide navigation bar
if (!hasSoftNavigationBar && mBaseNavigationBarHeight != 0) {
mNavigationBarVerticalOffset = 0;
} else {
mNavigationBarVerticalOffset = mBaseNavigationBarHeight;
}
mNavigationBarHorizontalOffset = 0;
return;
}
Expand All @@ -658,7 +695,17 @@ private void updateNavigationBarOffset(boolean isHideNavigationBar, boolean isPo
mNavigationBarHorizontalOffset = 0;
} else {
mNavigationBarVerticalOffset = 0;
mNavigationBarHorizontalOffset = mBaseNavigationBarRotatedHeight;
// auto hide navigation bar
// 他デバイスとの矛盾をもとに推測する
// 1.デバイスに組み込まれたナビゲーションバー(!hasSoftNavigationBar)は、意図的にBaseを0にしているので、矛盾している
if (!hasSoftNavigationBar && mBaseNavigationBarRotatedHeight != 0) {
mNavigationBarHorizontalOffset = 0;
} else if (hasSoftNavigationBar && mBaseNavigationBarRotatedHeight == 0) {
// 2.ソフトナビゲーションバーの場合、Baseが設定されるため矛盾している
mNavigationBarHorizontalOffset = currentNavigationBarWidth;
} else {
mNavigationBarHorizontalOffset = mBaseNavigationBarRotatedHeight;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package jp.co.recruit_lifestyle.android.floatingview;

import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
Expand All @@ -24,7 +25,9 @@
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
Expand Down Expand Up @@ -244,15 +247,20 @@ public void onScreenChanged(Rect windowRect, int visibility) {
final boolean isHideNavigationBar;
if (visibility == FullscreenObserverView.NO_LAST_VISIBILITY) {
// At the first it can not get the correct value, so do special processing
mWindowManager.getDefaultDisplay().getMetrics(mDisplayMetrics);
isHideNavigationBar = windowRect.width() - mDisplayMetrics.widthPixels > 0 || windowRect.height() - mDisplayMetrics.heightPixels > 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
mWindowManager.getDefaultDisplay().getRealMetrics(mDisplayMetrics);
isHideNavigationBar = windowRect.width() - mDisplayMetrics.widthPixels == 0 && windowRect.bottom - mDisplayMetrics.heightPixels == 0;
} else {
mWindowManager.getDefaultDisplay().getMetrics(mDisplayMetrics);
isHideNavigationBar = windowRect.width() - mDisplayMetrics.widthPixels > 0 || windowRect.height() - mDisplayMetrics.heightPixels > 0;
}
} else {
isHideNavigationBar = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
final boolean isPortrait = mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;

final boolean isPortrait = mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
// update FloatingView layout
mTargetFloatingView.onUpdateSystemLayout(isHideStatusBar, isHideNavigationBar, isPortrait, windowRect.left);
mTargetFloatingView.onUpdateSystemLayout(isHideStatusBar, isHideNavigationBar, isPortrait, windowRect);

// フルスクリーンでの非表示モードでない場合は何もしない
if (mDisplayMode != DISPLAY_MODE_HIDE_FULLSCREEN) {
Expand Down Expand Up @@ -439,13 +447,13 @@ public void setDisplayMode(@DisplayMode int displayMode) {
mDisplayMode = displayMode;
// 常に表示/フルスクリーン時に非表示にするモードの場合
if (mDisplayMode == DISPLAY_MODE_SHOW_ALWAYS || mDisplayMode == DISPLAY_MODE_HIDE_FULLSCREEN) {
for (FloatingView floatingView: mFloatingViewList) {
for (FloatingView floatingView : mFloatingViewList) {
floatingView.setVisibility(View.VISIBLE);
}
}
// 常に非表示にするモードの場合
else if (mDisplayMode == DISPLAY_MODE_HIDE_ALWAYS) {
for (FloatingView floatingView: mFloatingViewList) {
for (FloatingView floatingView : mFloatingViewList) {
floatingView.setVisibility(View.GONE);
}
mTrashView.dismiss();
Expand Down Expand Up @@ -579,6 +587,29 @@ public void removeAllViewToWindow() {
mFloatingViewList.clear();
}

/**
* Find the safe area of DisplayCutout.
*
* @param activity {@link Activity} (Portrait and `windowLayoutInDisplayCutoutMode` != never)
* @return Safe cutout insets.
*/
public static Rect findCutoutSafeArea(@NonNull Activity activity) {
final Rect safeInsetRect = new Rect();
// TODO:Rewrite with android-x
// TODO:Consider alternatives
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
return safeInsetRect;
}

// set safeInsetRect
final DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
safeInsetRect.set(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(), displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());
}

return safeInsetRect;
}

/**
* FloatingViewを貼り付ける際のオプションを表すクラスです。
*/
Expand Down
4 changes: 1 addition & 3 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ apply plugin: 'com.android.application'

android {
compileSdkVersion 28
buildToolsVersion '28.0.2'

defaultConfig {
applicationId "jp.co.recruit.floatingview"
minSdkVersion 14
Expand All @@ -21,6 +19,6 @@ android {

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:preference-v14:28.0.0-rc02'
implementation 'com.android.support:preference-v14:28.0.0'
implementation project(':library')
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
Expand All @@ -15,13 +14,13 @@
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.view.DisplayCutout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import jp.co.recruit.floatingview.R;
import jp.co.recruit_lifestyle.android.floatingview.FloatingViewManager;
import jp.co.recruit_lifestyle.sample.service.ChatHeadService;
import jp.co.recruit_lifestyle.sample.service.CustomFloatingViewService;

Expand Down Expand Up @@ -143,35 +142,26 @@ private void showFloatingView(Context context, boolean isShowOverlayPermission,
* @param isCustomFloatingView If true, it launches CustomFloatingViewService.
*/
private static void startFloatingViewService(Activity activity, boolean isCustomFloatingView) {
// set safe inset area
final Rect safeInsetRect = new Rect();
// TODO:Rewrite with android-x
// TODO:Consider alternatives
// *** You must follow these rules when obtain the cutout(FloatingViewManager.findCutoutSafeArea) ***
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
final DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
safeInsetRect.set(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(), displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());

// *** You must follow these rules when obtain the cutout ***
// 1. 'windowLayoutInDisplayCutoutMode' do not be set to 'never'
if (activity.getWindow().getAttributes().layoutInDisplayCutoutMode == WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
throw new RuntimeException("'windowLayoutInDisplayCutoutMode' do not be set to 'never'");
}
// 2. Do not set Activity to landscape
if(activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
throw new RuntimeException("Do not set Activity to landscape");
}
// 1. 'windowLayoutInDisplayCutoutMode' do not be set to 'never'
if (activity.getWindow().getAttributes().layoutInDisplayCutoutMode == WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
throw new RuntimeException("'windowLayoutInDisplayCutoutMode' do not be set to 'never'");
}
// 2. Do not set Activity to landscape
if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
throw new RuntimeException("Do not set Activity to landscape");
}
}

// launch service
if (isCustomFloatingView) {
final Intent intent = new Intent(activity, CustomFloatingViewService.class);
intent.putExtra(CustomFloatingViewService.EXTRA_CUTOUT_SAFE_AREA, safeInsetRect);
intent.putExtra(CustomFloatingViewService.EXTRA_CUTOUT_SAFE_AREA, FloatingViewManager.findCutoutSafeArea(activity));
ContextCompat.startForegroundService(activity, intent);
} else {
final Intent intent = new Intent(activity, ChatHeadService.class);
intent.putExtra(ChatHeadService.EXTRA_CUTOUT_SAFE_AREA, safeInsetRect);
intent.putExtra(ChatHeadService.EXTRA_CUTOUT_SAFE_AREA, FloatingViewManager.findCutoutSafeArea(activity));
ContextCompat.startForegroundService(activity, intent);
}
}
Expand Down

0 comments on commit b95b5d5

Please sign in to comment.