src\MyApplication\.idea\codeStyleSettings.xml

src\MyApplication\.idea\compiler.xml
src\MyApplication\.idea\encodings.xml
src\MyApplication\.idea\gradle.xml
src\MyApplication\.idea\misc.xml
src\MyApplication\.idea\modules.xml
src\MyApplication\.idea\runConfigurations.xml
src\MyApplication\.idea\sonarlint\issuestore\index.pb
src\MyApplication\app\build.gradle
src\MyApplication\app\src\main\AndroidManifest.xml
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\adapter\BgPicGridAdapter.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\adapter\NotebookAdapter.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\app\BaseApplication.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\db\DatabaseHelper.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\db\NoteDatabase.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\entity\BgPicEntity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\entity\NotebookData.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\entity\OnResponseListener.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\entity\Response.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\entity\UpdataEvent.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\entity\User.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\AboutAppFragment.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\AlarmAlertActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\ChangeBgFragment.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\DateTimePicker.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\DateTimePickerDialog.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\LoginActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\MainActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\NoteBookFragment.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\NoteEditActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\NoteEditFragment.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\RegisterActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\SetLockActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\SettingFragment.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\UnLockActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\UserInfoActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\ui\WelcomeActivity.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\AccountUtils.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\BmobConstants.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\CommonUtils.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\Constants.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\DialogHelp.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\HTQAnimations.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\ImageLoadOptions.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\MD5Util.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\PhotoUtil.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\ResourceParser.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\SPUtils.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\StringUtils.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\SystemUtils.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\utils\TimeZoneUtil.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\CircleImageView.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\HTQDragGridView.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\NoteItemCircleView.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\ToggleButton.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\patternlock\LockPatternView.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\patternlock\Point.java
src\MyApplication\app\src\main\java\com\example\administrator\myapplication\widget\patternlock\RotateDegrees.java
src\MyApplication\app\src\main\res\anim\grow_from_bottom.xml
src\MyApplication\app\src\main\res\anim\shrink_from_top.xml
src\MyApplication\app\src\main\res\drawable-v21\btn_dark_blue_background.xml
src\MyApplication\app\src\main\res\drawable-v21\btn_orange_background.xml
src\MyApplication\app\src\main\res\drawable-v21\ic_menu_camera.xml
src\MyApplication\app\src\main\res\drawable-v21\ic_menu_gallery.xml
src\MyApplication\app\src\main\res\drawable-v21\ic_menu_manage.xml
src\MyApplication\app\src\main\res\drawable-v21\ic_menu_send.xml
src\MyApplication\app\src\main\res\drawable-v21\ic_menu_share.xml
src\MyApplication\app\src\main\res\drawable-v21\ic_menu_slideshow.xml
src\MyApplication\app\src\main\res\drawable-v21\login_divider_line.xml
src\MyApplication\app\src\main\res\drawable-v21\login_et_background.xml
src\MyApplication\app\src\main\res\drawable-v21\login_ll_background.xml
src\MyApplication\app\src\main\res\drawable\btn_login_selector.xml
src\MyApplication\app\src\main\res\drawable\ic_info_black_24dp.xml
src\MyApplication\app\src\main\res\drawable\ic_notifications_black_24dp.xml
src\MyApplication\app\src\main\res\drawable\ic_sync_black_24dp.xml
src\MyApplication\app\src\main\res\drawable\side_nav_bar.xml
src\MyApplication\app\src\main\res\drawable\skin_img_item_background.xml
src\MyApplication\app\src\main\res\layout\about_me_fragment.xml
src\MyApplication\app\src\main\res\layout\activity_login.xml
src\MyApplication\app\src\main\res\layout\activity_main.xml
src\MyApplication\app\src\main\res\layout\activity_note_edit.xml
src\MyApplication\app\src\main\res\layout\activity_register.xml
src\MyApplication\app\src\main\res\layout\activity_set_lock.xml
src\MyApplication\app\src\main\res\layout\activity_unlock.xml
src\MyApplication\app\src\main\res\layout\activity_user_info.xml
src\MyApplication\app\src\main\res\layout\activity_welcome.xml
src\MyApplication\app\src\main\res\layout\app_bar_main.xml
src\MyApplication\app\src\main\res\layout\bg_pic_grid_item.xml
src\MyApplication\app\src\main\res\layout\change_info_dialog_layout.xml
src\MyApplication\app\src\main\res\layout\content_main.xml
src\MyApplication\app\src\main\res\layout\datetime_picker.xml
src\MyApplication\app\src\main\res\layout\fragment_change_background.xml
src\MyApplication\app\src\main\res\layout\fragment_note.xml
src\MyApplication\app\src\main\res\layout\fragment_setting.xml
src\MyApplication\app\src\main\res\layout\item_notebook.xml
src\MyApplication\app\src\main\res\layout\layout_note_detail_menu.xml
src\MyApplication\app\src\main\res\layout\main_fragment.xml
src\MyApplication\app\src\main\res\layout\nav_header_main.xml
src\MyApplication\app\src\main\res\layout\note_edit_activity_fraglayout.xml
src\MyApplication\app\src\main\res\layout\note_edit_fraglayout.xml
src\MyApplication\app\src\main\res\layout\pop_showavator.xml
src\MyApplication\app\src\main\res\layout\popupwindow_choose_layout.xml
src\MyApplication\app\src\main\res\layout\widget_lock_view.xml
src\MyApplication\app\src\main\res\menu\activity_main_drawer.xml
src\MyApplication\app\src\main\res\menu\main.xml
src\MyApplication\app\src\main\res\menu\notebook_edit_menu.xml
src\MyApplication\app\src\main\res\values-v21\attrs.xml
src\MyApplication\app\src\main\res\values-v21\styles.xml
src\MyApplication\app\src\main\res\values-w820dp\dimens.xml
src\MyApplication\app\src\main\res\values\attrs.xml
src\MyApplication\app\src\main\res\values\colors.xml
src\MyApplication\app\src\main\res\values\dimens.xml
src\MyApplication\app\src\main\res\values\drawables.xml
src\MyApplication\app\src\main\res\values\strings.xml
src\MyApplication\app\src\main\res\values\styles.xml
src\MyApplication\build.gradle
src\MyApplication\gradlew
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\.idea\compiler.xml
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\.idea\encodings.xml
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\.idea\gradle.xml
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\.idea\misc.xml
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\.idea\modules.xml
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\.idea\runConfigurations.xml
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\app\src\main\java\cn\bmob\sdkdemo\BmobApplication.java
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\gradle\wrapper\gradle-wrapper.properties
src\MyApplication\libs\BmobSDKDemo_v3.6.0\BmobDemo\gradlew
src\MyApplication\libs\BmobSDKDemo_v3.6.0\更新日志.txt
src\MyApplication\settings.gradle
src\MyApplication\.idea\sonarlint\issuestore\0\5\05efc8b1657769a27696d478ded1e95f38737233
src\MyApplication\.idea\sonarlint\issuestore\0\7\0712df971a99ac4d2fccb8e0fb19f377f3374cca
src\MyApplication\.idea\sonarlint\issuestore\2\a\2afbb999f001938c88fa43fc2ef52abf0f8213e4
src\MyApplication\.idea\sonarlint\issuestore\3\0\30a54a60f14d64645eed00c5f82475af0b8df642
src\MyApplication\.idea\sonarlint\issuestore\6\7\67dcf9378cf673b1d3b665701ca8ab112314a41a
src\MyApplication\app\src\main\res\drawable\icon.png
src\MyApplication\floatwindow\.gitignore
src\MyApplication\floatwindow\build.gradle
src\MyApplication\floatwindow\proguard-rules.pro
src\MyApplication\floatwindow\src\androidTest\java\com\example\fixedfloatwindow\ExampleInstrumentedTest.java
src\MyApplication\floatwindow\src\main\AndroidManifest.xml
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\FloatActivity.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\FloatLifecycle.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\FloatPhone.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\FloatToast.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\FloatView.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\FloatWindow.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\IFloatWindow.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\IFloatWindowImpl.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\LifecycleListener.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\LogUtil.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\Miui.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\MoveType.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\PermissionListener.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\PermissionUtil.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\ResumedListener.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\Rom.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\Screen.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\Util.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\ViewStateListener.java
src\MyApplication\floatwindow\src\main\java\com\yhao\floatwindow\ViewStateListenerAdapter.java
src\MyApplication\floatwindow\src\main\res\values\strings.xml
src\MyApplication\floatwindow\src\main\res\values\style.xml
src\MyApplication\floatwindow\src\test\java\com\example\fixedfloatwindow\ExampleUnitTest.java
This commit is contained in:
Mr_Worldwide 2018-05-21 08:16:55 +08:00
parent 6c240ad185
commit 1b78cc0904
47 changed files with 2052 additions and 80 deletions

View File

@ -9,7 +9,7 @@
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/library" /> <option value="$PROJECT_DIR$/floatwindow" />
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />

View File

@ -4,7 +4,7 @@
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/MyApplication.iml" filepath="$PROJECT_DIR$/MyApplication.iml" /> <module fileurl="file://$PROJECT_DIR$/MyApplication.iml" filepath="$PROJECT_DIR$/MyApplication.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/library/my_library.iml" filepath="$PROJECT_DIR$/library/my_library.iml" /> <module fileurl="file://$PROJECT_DIR$/floatwindow/floatwindow.iml" filepath="$PROJECT_DIR$/floatwindow/floatwindow.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -0,0 +1,27 @@
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(éóÈàûÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(¢ææòýÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(™Õüþÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(ñ¥—²ýÿÿÿÿ
K squid:S2696"6Make the enclosing method "static" or remove this set.(ƒÌï<C38C>
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(ù¤¾¤
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(Ù÷žñùÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(¹ÿÁ<C3BF>ûÿÿÿÿ
@ squid:S1172"+Remove this unused method parameter "view".(É£<E2809A>
S squid:S1155">Use isEmpty() to check whether the collection is empty or not.(ö‡Òí
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(¶¾õÕ
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(³¿á•
P squid:S2696"6Make the enclosing method "static" or remove this set.(Ý…ÿÛüÿÿÿÿ
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(Œö܉
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(¼õØ€ùÿÿÿÿ
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(¾Äºú
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(û<>¤™ûÿÿÿÿ
@ squid:S1444",Make this "public static mState" field final(½²»|
L squid:S2589"7Remove this expression which always evaluates to "true"(â¿ß“
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(Œö܉
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(›¢¼Äüÿÿÿÿ
 squid:S1186"€Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.(ò<C3B2>
_squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(À<>ÎC
B squid:S2387"."mState" is the name of a field in "Fragment".(½²»|
J squid:S2696"6Make the enclosing method "static" or remove this set.(ºë1
}"squid:ClassVariableVisibilityCheck"RMake mState a static final constant or non-public and provide accessors if needed.(½²»|

View File

@ -0,0 +1,18 @@
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(”“ɉúÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(¡…•æùÿÿÿÿ
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(<28>ÀÆ
s squid:S1450"YRemove the "isFirstUse" field and declare it as a local variable in the relevant methods.(ÃÑ<C383><C391>ûÿÿÿÿ
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(<28>ÀÆ
`squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(ô侄
bsquid:CallToDeprecatedMethod"=Remove this use of "setBackgroundDrawable"; it is deprecated.(”õV
_squid:HiddenFieldCheck":Rename "drawer" which hides the field declared at line 41.(ÐÍè¨þÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(Û¿<C2BF>ýÿÿÿÿ
_squid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(üêÝ/
A squid:S1905",Remove this unnecessary cast to "ImageView".(ÆïË”
_squid:HiddenFieldCheck":Rename "drawer" which hides the field declared at line 41.(ÐÍè¨þÿÿÿÿ
dsquid:CallToDeprecatedMethod"9Remove this use of "setDrawerListener"; it is deprecated.(ø¶Âßÿÿÿÿÿ
q squid:S1450"WRemove the "baseView" field and declare it as a local variable in the relevant methods.(‘‚¼²þÿÿÿÿ
esquid:CommentedOutCodeLine"<This block of commented-out lines of code should be removed.(“Å<E2809C>ýÿÿÿÿ
y squid:S1450"_Remove the "noteBookFragment" field and declare it as a local variable in the relevant methods.(­Óé«ùÿÿÿÿ
isquid:MaximumInheritanceDepth"=This class has 10 parents which is greater than 5 authorized.(ù ®Íúÿÿÿÿ

View File

@ -1,3 +1,13 @@
< <
build.gradle,f\0\f07866736216be0ee2aba49e392191aeae700a35 build.gradle,f\0\f07866736216be0ee2aba49e392191aeae700a35
?
settings.gradle,0\5\05efc8b1657769a27696d478ded1e95f38737233
A
gradle.properties,2\a\2afbb999f001938c88fa43fc2ef52abf0f8213e4
@
local.properties,0\7\0712df971a99ac4d2fccb8e0fb19f377f3374cca

Rapp\src\main\java\com\example\administrator\myapplication\ui\NoteBookFragment.java,3\0\30a54a60f14d64645eed00c5f82475af0b8df642
~
Napp\src\main\java\com\example\administrator\myapplication\ui\MainActivity.java,6\7\67dcf9378cf673b1d3b665701ca8ab112314a41a

View File

@ -7,10 +7,11 @@ android {
useLibrary 'org.apache.http.legacy' useLibrary 'org.apache.http.legacy'
defaultConfig { defaultConfig {
applicationId "com.example.administrator.myapplication" applicationId "com.example.administrator.myapplication"
minSdkVersion 17 minSdkVersion 19
targetSdkVersion 26 targetSdkVersion 26
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
} }
@ -40,8 +41,7 @@ android {
} }
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(include: ['*.jar'], dir: 'libs')
compile project(':my_library')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
}) })
@ -58,5 +58,7 @@ dependencies {
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.2' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.2'
compile 'com.github.clans:fab:1.6.1' compile 'com.github.clans:fab:1.6.1'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.github.yhaolpz:FloatWindow:1.0.9'
apt 'com.jakewharton:butterknife-compiler:8.2.1' apt 'com.jakewharton:butterknife-compiler:8.2.1'
compile project(':floatwindow')
} }

View File

@ -4,6 +4,8 @@
android:versionCode="1" android:versionCode="1"
android:versionName="2.1.0"> android:versionName="2.1.0">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 获取悬浮窗的权限 -->
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<!-- 获取GSM2g、WCDMA联通3g等网络状态的信息 --> <!-- 获取GSM2g、WCDMA联通3g等网络状态的信息 -->
@ -28,7 +30,8 @@
android:icon="@mipmap/app_icon" android:icon="@mipmap/app_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
android:name="com.example.administrator.myapplication.app.BaseApplication">
<activity <activity
android:name=".ui.WelcomeActivity" android:name=".ui.WelcomeActivity"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">

View File

@ -2,7 +2,14 @@ package com.example.administrator.myapplication.app;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import com.example.administrator.myapplication.R;
import com.example.administrator.myapplication.ui.MainActivity;
import com.example.administrator.myapplication.utils.BmobConstants; import com.example.administrator.myapplication.utils.BmobConstants;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
@ -11,22 +18,52 @@ import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.utils.StorageUtils; import com.nostra13.universalimageloader.utils.StorageUtils;
import com.yhao.floatwindow.FloatWindow;
import com.yhao.floatwindow.MoveType;
import com.yhao.floatwindow.PermissionListener;
import com.yhao.floatwindow.Screen;
import com.yhao.floatwindow.ViewStateListener;
import java.io.File; import java.io.File;
import cn.bmob.v3.Bmob; import cn.bmob.v3.Bmob;
/**
* Created by htq on 2016/9/5.
*/
public class BaseApplication extends Application { public class BaseApplication extends Application {
private static final String TAG = "FloatWindow";
private String ApplicationId="82cacaa4470ab6b8d61d3f0ce6d6201d"; private String ApplicationId="82cacaa4470ab6b8d61d3f0ce6d6201d";
static public String avatarPath= BmobConstants.MyAvatarDir+"avatarIcon.png"; static public String avatarPath= BmobConstants.MyAvatarDir+"avatarIcon.png";
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
ImageView imageView = new ImageView(getApplicationContext());
imageView.setImageResource(R.drawable.icon);
FloatWindow
.with(getApplicationContext())
.setView(imageView)
.setWidth(Screen.width, 0.2f) //设置悬浮控件宽高
.setHeight(Screen.width, 0.2f)
.setX(Screen.width, 0.8f)
.setY(Screen.height, 0.3f)
.setMoveType(MoveType.slide,100,-100)
.setMoveStyle(500, new BounceInterpolator())
.setFilter(true, MainActivity.class)
.setViewStateListener(mViewStateListener)
.setPermissionListener(mPermissionListener)
.setDesktopShow(true)
.build();
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(BaseApplication.this, "嗖藏成功~", Toast.LENGTH_SHORT).show();
}
});
//悬浮窗口部分
initImageLoader(this); initImageLoader(this);
Bmob.initialize(this, ApplicationId); Bmob.initialize(this, ApplicationId);
// android 7.0系统解决拍照的问题 // android 7.0系统解决拍照的问题
@ -55,4 +92,53 @@ public class BaseApplication extends Application {
ImageLoader.getInstance().init(config);// 全局初始化此配置 ImageLoader.getInstance().init(config);// 全局初始化此配置
} }
/** 悬浮窗日志 */
private PermissionListener mPermissionListener = new PermissionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "onSuccess");
}
@Override
public void onFail() {
Log.d(TAG, "onFail");
}
};
private ViewStateListener mViewStateListener = new ViewStateListener() {
@Override
public void onPositionUpdate(int x, int y) {
Log.d(TAG, "onPositionUpdate: x=" + x + " y=" + y);
}
@Override
public void onShow() {
Log.d(TAG, "onShow");
}
@Override
public void onHide() {
Log.d(TAG, "onHide");
}
@Override
public void onDismiss() {
Log.d(TAG, "onDismiss");
}
@Override
public void onMoveAnimStart() {
Log.d(TAG, "onMoveAnimStart");
}
@Override
public void onMoveAnimEnd() {
Log.d(TAG, "onMoveAnimEnd");
}
@Override
public void onBackToDesktop() {
Log.d(TAG, "onBackToDesktop");
}
};
} }

View File

@ -13,9 +13,9 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat; import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
@ -81,7 +81,9 @@ public class MainActivity extends AppCompatActivity
private void initUi() private void initUi()
{ {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//toolbar.setTitle("hehehe");
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
//toolbar.setTitle("hehehe");
fab = (FloatingActionButton) findViewById(R.id.fab); fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() { fab.setOnClickListener(new View.OnClickListener() {
@Override @Override

View File

@ -338,20 +338,20 @@ public void getServerData()
inflater.inflate(R.menu.main, menu); inflater.inflate(R.menu.main, menu);
} }
@Override // @Override
public boolean onOptionsItemSelected(MenuItem item) { // public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will // // Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long // // automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml. // // as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); // int id = item.getItemId();
//
//noinspection SimplifiableIfStatement // //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) { // if (id == R.id.action_settings) {
new SystemUtils(getActivity()).setBoolean("isTran",true); // new SystemUtils(getActivity()).setBoolean("isTran",true);
mGrid.setAlpha(0.55f); // mGrid.setAlpha(0.55f);
return true; // return true;
} // }
//
return super.onOptionsItemSelected(item); // return super.onOptionsItemSelected(item);
} // }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -7,6 +7,122 @@
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="com.example.administrator.myapplication.ui.MainActivity"> tools:context="com.example.administrator.myapplication.ui.MainActivity">
<!--<android.support.design.widget.FloatingActionButton-->
<!--android:id="@+id/fab"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_gravity="bottom|end"-->
<!--android:layout_margin="@dimen/fab_margin"-->
<!--app:borderWidth="0dp"-->
<!--app:elevation="4dp"-->
<!--app:rippleColor="@android:color/transparent"-->
<!--android:src="@drawable/actionbar_icon_add" />-->
<!--<android.support.design.widget.AppBarLayout-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:theme="@style/AppTheme.AppBarOverlay">-->
<!--&lt;!&ndash;<LinearLayout-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:background="@color/black"-->
<!--&gt;-->
<!--<ImageButton-->
<!--android:id="@+id/app_bar_menubt"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:src="@drawable/app_bar_menu"-->
<!--/>-->
<!--<android.support.design.widget.TabLayout-->
<!--android:id="@+id/app_bar_tablayout"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="30dp"-->
<!--&gt;-->
<!--</android.support.design.widget.TabLayout>-->
<!--<ImageButton-->
<!--android:id="@+id/app_bar_menu"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_marginEnd="1dp"-->
<!--android:src="@drawable/app_bar_search"/>-->
<!--</LinearLayout>&ndash;&gt;-->
<!--&lt;!&ndash;<android.support.v7.widget.Toolbar-->
<!--android:id="@+id/toolbar"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="?attr/actionBarSize"-->
<!--android:background="?attr/colorPrimary"-->
<!--app:popupTheme="@style/AppTheme.PopupOverlay"/>-->
<!--&ndash;&gt;-->
<!--<RelativeLayout-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="40dp"-->
<!--&gt;-->
<!--<ImageButton-->
<!--android:id="@+id/app_bar_menu"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--app:srcCompat="@drawable/app_bar_menu"/>-->
<!--<android.support.design.widget.TabLayout-->
<!--android:id="@+id/app_bar_tablayout"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--app:tabGravity="center"-->
<!--app:tabSelectedTextColor="@color/black"-->
<!--android:layout_alignParentTop="true"-->
<!--android:layout_centerHorizontal="true">-->
<!--<android.support.design.widget.TabItem-->
<!--android:id="@+id/app_bar_item1"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="文章"/>-->
<!--<android.support.design.widget.TabItem-->
<!--android:id="@+id/app_bar_item2"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="图片"/>-->
<!--</android.support.design.widget.TabLayout>-->
<!--<ImageButton-->
<!--android:id="@+id/app_bar_search"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--app:srcCompat="?android:attr/actionModeWebSearchDrawable"-->
<!--android:layout_alignParentTop="true"-->
<!--android:layout_alignParentEnd="true"/>-->
<!--</RelativeLayout>-->
<!--</android.support.design.widget.AppBarLayout>-->
<!--<include layout="@layout/content_main"/>-->
<!--</android.support.design.widget.CoordinatorLayout>-->
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" /> <include layout="@layout/content_main" />
<android.support.design.widget.FloatingActionButton <android.support.design.widget.FloatingActionButton
@ -20,48 +136,4 @@
app:rippleColor="@android:color/transparent" app:rippleColor="@android:color/transparent"
android:src="@drawable/actionbar_icon_add" /> android:src="@drawable/actionbar_icon_add" />
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black"
>
<ImageButton
android:id="@+id/app_bar_menubt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/app_bar_menu"
/>
<android.support.design.widget.TabLayout
android:id="@+id/app_bar_tablayout"
android:layout_width="wrap_content"
android:layout_height="30dp"
>
</android.support.design.widget.TabLayout>
<ImageButton
android:id="@+id/app_bar_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="1dp"
android:src="@drawable/app_bar_search"/>
</LinearLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

View File

@ -2,8 +2,16 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_search"
android:icon="@drawable/ic_search_black_48dp"
android:orderInCategory="80"
android:title="search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom" />
<!--分享菜单-->
<!--item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:orderInCategory="100" android:orderInCategory="100"
android:title="@string/action_settings" android:title="@string/action_settings"
app:showAsAction="never" /> app:showAsAction="never" /-->
</menu> </menu>

View File

@ -43,7 +43,7 @@
<color name="orange">#FFA500</color><!--橙色 --> <color name="orange">#FFA500</color><!--橙色 -->
<color name="lightsalmon">#FFA07A</color><!--亮肉色 --> <color name="lightsalmon">#FFA07A</color><!--亮肉色 -->
<color name="darkorange">#FF8C00</color><!--暗桔黄色 --> <color name="darkorange">#FF8C00</color><!--暗桔黄色 -->
<color name="coral">#FF7F50</color><!--珊瑚色 --> <color name="coral">#ff7f50</color><!--珊瑚色 -->
<color name="hotpink">#FF69B4</color><!--热粉红色 --> <color name="hotpink">#FF69B4</color><!--热粉红色 -->
<color name="tomato">#FF6347</color><!--西红柿色 --> <color name="tomato">#FF6347</color><!--西红柿色 -->
<color name="orangered">#FF4500</color><!--红橙色 --> <color name="orangered">#FF4500</color><!--红橙色 -->
@ -53,7 +53,7 @@
<color name="oldlace">#FDF5E6</color><!--老花色 --> <color name="oldlace">#FDF5E6</color><!--老花色 -->
<color name="lightgoldenrodyellow">#FAFAD2</color><!--亮金黄色 --> <color name="lightgoldenrodyellow">#FAFAD2</color><!--亮金黄色 -->
<color name="linen">#FAF0E6</color><!--亚麻色 --> <color name="linen">#FAF0E6</color><!--亚麻色 -->
<color name="antiquewhite">#FAEBD7</color><!--古董白 --> <color name="antiquewhite">#faebd7</color><!--古董白 -->
<color name="salmon">#FA8072</color><!--鲜肉色 --> <color name="salmon">#FA8072</color><!--鲜肉色 -->
<color name="ghostwhite">#F8F8FF</color><!--幽灵白 --> <color name="ghostwhite">#F8F8FF</color><!--幽灵白 -->
<color name="mintcream">#F5FFFA</color><!--薄荷色 --> <color name="mintcream">#F5FFFA</color><!--薄荷色 -->

View File

@ -7,6 +7,8 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }
@ -16,6 +18,7 @@ allprojects {
repositories { repositories {
jcenter() jcenter()
maven { url "https://raw.github.com/bmob/bmob-android-sdk/master" } maven { url "https://raw.github.com/bmob/bmob-android-sdk/master" }
maven { url 'https://jitpack.io' }
} }
} }

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,38 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
buildToolsVersion "26.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
testCompile 'junit:junit:4.12'
}
// JitPack Maven
apply plugin: 'com.github.dcendents.android-maven'
// Your Group
group='com.github.yhaolpz'

View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,26 @@
package com.example.fixedfloatwindow;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.example.fixedfloatwindow.test", appContext.getPackageName());
}
}

View File

@ -0,0 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.fixedfloatwindow">
<application>
<activity
android:name="com.yhao.floatwindow.FloatActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="standard"
android:theme="@style/permission_PermissionActivity"
android:windowSoftInputMode="stateHidden|stateAlwaysHidden"/>
</application>
</manifest>

View File

@ -0,0 +1,87 @@
package com.yhao.floatwindow;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import java.util.ArrayList;
import java.util.List;
/**
* 用于在内部自动申请权限
* https://github.com/yhaolpz
*/
public class FloatActivity extends Activity {
private static List<PermissionListener> mPermissionListenerList;
private static PermissionListener mPermissionListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestAlertWindowPermission();
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void requestAlertWindowPermission() {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 756232212);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 756232212) {
if (PermissionUtil.hasPermissionOnActivityResult(this)) {
mPermissionListener.onSuccess();
} else {
mPermissionListener.onFail();
}
}
finish();
}
static synchronized void request(Context context, PermissionListener permissionListener) {
if (PermissionUtil.hasPermission(context)) {
permissionListener.onSuccess();
return;
}
if (mPermissionListenerList == null) {
mPermissionListenerList = new ArrayList<>();
mPermissionListener = new PermissionListener() {
@Override
public void onSuccess() {
for (PermissionListener listener : mPermissionListenerList) {
listener.onSuccess();
}
mPermissionListenerList.clear();
}
@Override
public void onFail() {
for (PermissionListener listener : mPermissionListenerList) {
listener.onFail();
}
mPermissionListenerList.clear();
}
};
Intent intent = new Intent(context, FloatActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
mPermissionListenerList.add(permissionListener);
}
}

View File

@ -0,0 +1,143 @@
package com.yhao.floatwindow;
import android.app.Activity;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Toast;
/**
* Created by yhao on 17-12-1.
* 用于控制悬浮窗显示周期
* 使用了三种方法针对返回桌面时隐藏悬浮按钮
* 1.startCount计数针对back到桌面可以及时隐藏
* 2.监听home键从而及时隐藏
* 3.resumeCount计时针对一些只执行onPause不执行onStop的奇葩情况
*/
class FloatLifecycle extends BroadcastReceiver implements Application.ActivityLifecycleCallbacks {
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
private static final long delay = 300;
private Handler mHandler;
private Class[] activities;
private boolean showFlag;
private int startCount;
private int resumeCount;
private boolean appBackground;
private LifecycleListener mLifecycleListener;
private static ResumedListener sResumedListener;
private static int num = 0;
FloatLifecycle(Context applicationContext, boolean showFlag, Class[] activities, LifecycleListener lifecycleListener) {
this.showFlag = showFlag;
this.activities = activities;
num++;
mLifecycleListener = lifecycleListener;
mHandler = new Handler();
((Application) applicationContext).registerActivityLifecycleCallbacks(this);
applicationContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
public static void setResumedListener(ResumedListener resumedListener) {
sResumedListener = resumedListener;
}
private boolean needShow(Activity activity) {
if (activities == null) {
return true;
}
for (Class a : activities) {
if (a.isInstance(activity)) {
return showFlag;
}
}
return !showFlag;
}
@Override
public void onActivityResumed(Activity activity) {
if (sResumedListener != null) {
num--;
if (num == 0) {
sResumedListener.onResumed();
sResumedListener = null;
}
}
resumeCount++;
if (needShow(activity)) {
mLifecycleListener.onShow();
} else {
mLifecycleListener.onHide();
}
if (appBackground) {
appBackground = false;
}
}
@Override
public void onActivityPaused(final Activity activity) {
resumeCount--;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (resumeCount == 0) {
appBackground = true;
mLifecycleListener.onBackToDesktop();
}
}
}, delay);
}
@Override
public void onActivityStarted(Activity activity) {
startCount++;
}
@Override
public void onActivityStopped(Activity activity) {
startCount--;
if (startCount == 0) {
mLifecycleListener.onBackToDesktop();
}
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
mLifecycleListener.onBackToDesktop();
}
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}

View File

@ -0,0 +1,157 @@
package com.yhao.floatwindow;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.view.View;
import android.view.WindowManager;
/**
* Created by yhao on 17-11-14.
* https://github.com/yhaolpz
*/
class FloatPhone extends FloatView {
private final Context mContext;
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mLayoutParams;
private View mView;
private int mX, mY;
private boolean isRemove = false;
private PermissionListener mPermissionListener;
FloatPhone(Context applicationContext, PermissionListener permissionListener) {
mContext = applicationContext;
mPermissionListener = permissionListener;
mWindowManager = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE);
mLayoutParams = new WindowManager.LayoutParams();
mLayoutParams.format = PixelFormat.RGBA_8888;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
mLayoutParams.windowAnimations = 0;
}
@Override
public void setSize(int width, int height) {
mLayoutParams.width = width;
mLayoutParams.height = height;
}
@Override
public void setView(View view) {
mView = view;
}
@Override
public void setGravity(int gravity, int xOffset, int yOffset) {
mLayoutParams.gravity = gravity;
mLayoutParams.x = mX = xOffset;
mLayoutParams.y = mY = yOffset;
}
@Override
public void init() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
req();
} else if (Miui.rom()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
req();
} else {
mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
Miui.req(mContext, new PermissionListener() {
@Override
public void onSuccess() {
mWindowManager.addView(mView, mLayoutParams);
if (mPermissionListener != null) {
mPermissionListener.onSuccess();
}
}
@Override
public void onFail() {
if (mPermissionListener != null) {
mPermissionListener.onFail();
}
}
});
}
} else {
try {
mLayoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;
mWindowManager.addView(mView, mLayoutParams);
} catch (Exception e) {
mWindowManager.removeView(mView);
LogUtil.e("TYPE_TOAST 失败");
req();
}
}
}
private void req() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
FloatActivity.request(mContext, new PermissionListener() {
@Override
public void onSuccess() {
mWindowManager.addView(mView, mLayoutParams);
if (mPermissionListener != null) {
mPermissionListener.onSuccess();
}
}
@Override
public void onFail() {
if (mPermissionListener != null) {
mPermissionListener.onFail();
}
}
});
}
@Override
public void dismiss() {
isRemove = true;
mWindowManager.removeView(mView);
}
@Override
public void updateXY(int x, int y) {
if (isRemove) return;
mLayoutParams.x = mX = x;
mLayoutParams.y = mY = y;
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
@Override
void updateX(int x) {
if (isRemove) return;
mLayoutParams.x = mX = x;
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
@Override
void updateY(int y) {
if (isRemove) return;
mLayoutParams.y = mY = y;
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
@Override
int getX() {
return mX;
}
@Override
int getY() {
return mY;
}
}

View File

@ -0,0 +1,95 @@
package com.yhao.floatwindow;
import android.content.Context;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 自定义 toast 方式无需申请权限
* 当前版本暂时用 TYPE_TOAST 代替后续版本可能会再融入此方式
*/
class FloatToast extends FloatView {
private Toast toast;
private Object mTN;
private Method show;
private Method hide;
private int mWidth;
private int mHeight;
FloatToast(Context applicationContext) {
toast = new Toast(applicationContext);
}
@Override
public void setSize(int width, int height) {
mWidth = width;
mHeight = height;
}
@Override
public void setView(View view) {
toast.setView(view);
initTN();
}
@Override
public void setGravity(int gravity, int xOffset, int yOffset) {
toast.setGravity(gravity, xOffset, yOffset);
}
@Override
public void init() {
try {
show.invoke(mTN);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void dismiss() {
try {
hide.invoke(mTN);
} catch (Exception e) {
e.printStackTrace();
}
}
private void initTN() {
try {
Field tnField = toast.getClass().getDeclaredField("mTN");
tnField.setAccessible(true);
mTN = tnField.get(toast);
show = mTN.getClass().getMethod("show");
hide = mTN.getClass().getMethod("hide");
Field tnParamsField = mTN.getClass().getDeclaredField("mParams");
tnParamsField.setAccessible(true);
WindowManager.LayoutParams params = (WindowManager.LayoutParams) tnParamsField.get(mTN);
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
params.width = mWidth;
params.height = mHeight;
params.windowAnimations = 0;
Field tnNextViewField = mTN.getClass().getDeclaredField("mNextView");
tnNextViewField.setAccessible(true);
tnNextViewField.set(mTN, toast.getView());
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,38 @@
package com.yhao.floatwindow;
import android.view.View;
/**
* Created by yhao on 17-11-14.
* https://github.com/yhaolpz
*/
abstract class FloatView {
abstract void setSize(int width, int height);
abstract void setView(View view);
abstract void setGravity(int gravity, int xOffset, int yOffset);
abstract void init();
abstract void dismiss();
void updateXY(int x, int y) {
}
void updateX(int x) {
}
void updateY(int y) {
}
int getX() {
return 0;
}
int getY() {
return 0;
}
}

View File

@ -0,0 +1,222 @@
package com.yhao.floatwindow;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import java.util.HashMap;
import java.util.Map;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class FloatWindow {
private FloatWindow() {
}
private static final String mDefaultTag = "default_float_window_tag";
private static Map<String, IFloatWindow> mFloatWindowMap;
public static IFloatWindow get() {
return get(mDefaultTag);
}
public static IFloatWindow get(@NonNull String tag) {
return mFloatWindowMap == null ? null : mFloatWindowMap.get(tag);
}
private static B mBuilder = null;
@MainThread
public static B with(@NonNull Context applicationContext) {
return mBuilder = new B(applicationContext);
}
public static void destroy() {
destroy(mDefaultTag);
}
public static void destroy(String tag) {
if (mFloatWindowMap == null || !mFloatWindowMap.containsKey(tag)) {
return;
}
mFloatWindowMap.get(tag).dismiss();
mFloatWindowMap.remove(tag);
}
public static class B {
Context mApplicationContext;
View mView;
private int mLayoutId;
int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
int gravity = Gravity.TOP | Gravity.START;
int xOffset;
int yOffset;
boolean mShow = true;
Class[] mActivities;
int mMoveType = MoveType.slide;
int mSlideLeftMargin;
int mSlideRightMargin;
long mDuration = 300;
TimeInterpolator mInterpolator;
private String mTag = mDefaultTag;
boolean mDesktopShow;
PermissionListener mPermissionListener;
ViewStateListener mViewStateListener;
private B() {
}
B(Context applicationContext) {
mApplicationContext = applicationContext;
}
public B setView(@NonNull View view) {
mView = view;
return this;
}
public B setView(@LayoutRes int layoutId) {
mLayoutId = layoutId;
return this;
}
public B setWidth(int width) {
mWidth = width;
return this;
}
public B setHeight(int height) {
mHeight = height;
return this;
}
public B setWidth(@Screen.screenType int screenType, float ratio) {
mWidth = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
public B setHeight(@Screen.screenType int screenType, float ratio) {
mHeight = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
public B setX(int x) {
xOffset = x;
return this;
}
public B setY(int y) {
yOffset = y;
return this;
}
public B setX(@Screen.screenType int screenType, float ratio) {
xOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
public B setY(@Screen.screenType int screenType, float ratio) {
yOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
/**
* 设置 Activity 过滤器用于指定在哪些界面显示悬浮窗默认全部界面都显示
*
* @param show  过滤类型,子类类型也会生效
* @param activities  过滤界面
*/
public B setFilter(boolean show, @NonNull Class... activities) {
mShow = show;
mActivities = activities;
return this;
}
public B setMoveType(@MoveType.MOVE_TYPE int moveType) {
return setMoveType(moveType, 0, 0);
}
/**
* 设置带边距的贴边动画只有 moveType MoveType.slide设置边距才有意义这个方法不标准后面调整
*
* @param moveType 贴边动画 MoveType.slide
* @param slideLeftMargin 贴边动画左边距默认为 0
* @param slideRightMargin 贴边动画右边距默认为 0
*/
public B setMoveType(@MoveType.MOVE_TYPE int moveType, int slideLeftMargin, int slideRightMargin) {
mMoveType = moveType;
mSlideLeftMargin = slideLeftMargin;
mSlideRightMargin = slideRightMargin;
return this;
}
public B setMoveStyle(long duration, @Nullable TimeInterpolator interpolator) {
mDuration = duration;
mInterpolator = interpolator;
return this;
}
public B setTag(@NonNull String tag) {
mTag = tag;
return this;
}
public B setDesktopShow(boolean show) {
mDesktopShow = show;
return this;
}
public B setPermissionListener(PermissionListener listener) {
mPermissionListener = listener;
return this;
}
public B setViewStateListener(ViewStateListener listener) {
mViewStateListener = listener;
return this;
}
public void build() {
if (mFloatWindowMap == null) {
mFloatWindowMap = new HashMap<>();
}
if (mFloatWindowMap.containsKey(mTag)) {
throw new IllegalArgumentException("FloatWindow of this tag has been added, Please set a new tag for the new FloatWindow");
}
if (mView == null && mLayoutId == 0) {
throw new IllegalArgumentException("View has not been set!");
}
if (mView == null) {
mView = Util.inflate(mApplicationContext, mLayoutId);
}
IFloatWindow floatWindowImpl = new IFloatWindowImpl(this);
mFloatWindowMap.put(mTag, floatWindowImpl);
}
}
}

View File

@ -0,0 +1,32 @@
package com.yhao.floatwindow;
import android.view.View;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public abstract class IFloatWindow {
public abstract void show();
public abstract void hide();
public abstract boolean isShowing();
public abstract int getX();
public abstract int getY();
public abstract void updateX(int x);
public abstract void updateX(@Screen.screenType int screenType,float ratio);
public abstract void updateY(int y);
public abstract void updateY(@Screen.screenType int screenType,float ratio);
public abstract View getView();
abstract void dismiss();
}

View File

@ -0,0 +1,302 @@
package com.yhao.floatwindow;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.os.Build;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class IFloatWindowImpl extends IFloatWindow {
private FloatWindow.B mB;
private FloatView mFloatView;
private FloatLifecycle mFloatLifecycle;
private boolean isShow;
private boolean once = true;
private ValueAnimator mAnimator;
private TimeInterpolator mDecelerateInterpolator;
private float downX;
private float downY;
private float upX;
private float upY;
private boolean mClick = false;
private int mSlop;
private IFloatWindowImpl() {
}
IFloatWindowImpl(FloatWindow.B b) {
mB = b;
if (mB.mMoveType == MoveType.fixed) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
mFloatView = new FloatPhone(b.mApplicationContext, mB.mPermissionListener);
} else {
mFloatView = new FloatToast(b.mApplicationContext);
}
} else {
mFloatView = new FloatPhone(b.mApplicationContext, mB.mPermissionListener);
initTouchEvent();
}
mFloatView.setSize(mB.mWidth, mB.mHeight);
mFloatView.setGravity(mB.gravity, mB.xOffset, mB.yOffset);
mFloatView.setView(mB.mView);
mFloatLifecycle = new FloatLifecycle(mB.mApplicationContext, mB.mShow, mB.mActivities, new LifecycleListener() {
@Override
public void onShow() {
show();
}
@Override
public void onHide() {
hide();
}
@Override
public void onBackToDesktop() {
if (!mB.mDesktopShow) {
hide();
}
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onBackToDesktop();
}
}
});
}
@Override
public void show() {
if (once) {
mFloatView.init();
once = false;
isShow = true;
} else {
if (isShow) {
return;
}
getView().setVisibility(View.VISIBLE);
isShow = true;
}
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onShow();
}
}
@Override
public void hide() {
if (once || !isShow) {
return;
}
getView().setVisibility(View.INVISIBLE);
isShow = false;
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onHide();
}
}
@Override
public boolean isShowing() {
return isShow;
}
@Override
void dismiss() {
mFloatView.dismiss();
isShow = false;
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onDismiss();
}
}
@Override
public void updateX(int x) {
checkMoveType();
mB.xOffset = x;
mFloatView.updateX(x);
}
@Override
public void updateY(int y) {
checkMoveType();
mB.yOffset = y;
mFloatView.updateY(y);
}
@Override
public void updateX(int screenType, float ratio) {
checkMoveType();
mB.xOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mB.mApplicationContext) :
Util.getScreenHeight(mB.mApplicationContext)) * ratio);
mFloatView.updateX(mB.xOffset);
}
@Override
public void updateY(int screenType, float ratio) {
checkMoveType();
mB.yOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mB.mApplicationContext) :
Util.getScreenHeight(mB.mApplicationContext)) * ratio);
mFloatView.updateY(mB.yOffset);
}
@Override
public int getX() {
return mFloatView.getX();
}
@Override
public int getY() {
return mFloatView.getY();
}
@Override
public View getView() {
mSlop = ViewConfiguration.get(mB.mApplicationContext).getScaledTouchSlop();
return mB.mView;
}
private void checkMoveType() {
if (mB.mMoveType == MoveType.fixed) {
throw new IllegalArgumentException("FloatWindow of this tag is not allowed to move!");
}
}
private void initTouchEvent() {
switch (mB.mMoveType) {
case MoveType.inactive:
break;
default:
getView().setOnTouchListener(new View.OnTouchListener() {
float lastX, lastY, changeX, changeY;
int newX, newY;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getRawX();
downY = event.getRawY();
lastX = event.getRawX();
lastY = event.getRawY();
cancelAnimator();
break;
case MotionEvent.ACTION_MOVE:
changeX = event.getRawX() - lastX;
changeY = event.getRawY() - lastY;
newX = (int) (mFloatView.getX() + changeX);
newY = (int) (mFloatView.getY() + changeY);
mFloatView.updateXY(newX, newY);
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onPositionUpdate(newX, newY);
}
lastX = event.getRawX();
lastY = event.getRawY();
break;
case MotionEvent.ACTION_UP:
upX = event.getRawX();
upY = event.getRawY();
mClick = (Math.abs(upX - downX) > mSlop) || (Math.abs(upY - downY) > mSlop);
switch (mB.mMoveType) {
case MoveType.slide:
int startX = mFloatView.getX();
int endX = (startX * 2 + v.getWidth() > Util.getScreenWidth(mB.mApplicationContext)) ?
Util.getScreenWidth(mB.mApplicationContext) - v.getWidth() - mB.mSlideRightMargin :
mB.mSlideLeftMargin;
mAnimator = ObjectAnimator.ofInt(startX, endX);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int x = (int) animation.getAnimatedValue();
mFloatView.updateX(x);
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onPositionUpdate(x, (int) upY);
}
}
});
startAnimator();
break;
case MoveType.back:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("x", mFloatView.getX(), mB.xOffset);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("y", mFloatView.getY(), mB.yOffset);
mAnimator = ObjectAnimator.ofPropertyValuesHolder(pvhX, pvhY);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int x = (int) animation.getAnimatedValue("x");
int y = (int) animation.getAnimatedValue("y");
mFloatView.updateXY(x, y);
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onPositionUpdate(x, y);
}
}
});
startAnimator();
break;
default:
break;
}
break;
default:
break;
}
return mClick;
}
});
}
}
private void startAnimator() {
if (mB.mInterpolator == null) {
if (mDecelerateInterpolator == null) {
mDecelerateInterpolator = new DecelerateInterpolator();
}
mB.mInterpolator = mDecelerateInterpolator;
}
mAnimator.setInterpolator(mB.mInterpolator);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mAnimator.removeAllUpdateListeners();
mAnimator.removeAllListeners();
mAnimator = null;
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onMoveAnimEnd();
}
}
});
mAnimator.setDuration(mB.mDuration).start();
if (mB.mViewStateListener != null) {
mB.mViewStateListener.onMoveAnimStart();
}
}
private void cancelAnimator() {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
}
}
}

View File

@ -0,0 +1,15 @@
package com.yhao.floatwindow;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
interface LifecycleListener {
void onShow();
void onHide();
void onBackToDesktop();
}

View File

@ -0,0 +1,28 @@
package com.yhao.floatwindow;
import android.util.Log;
/**
* Created by yhao on 2017/12/29.
* https://github.com/yhaolpz
*/
class LogUtil {
private static final String TAG = "FloatWindow";
static void e(String message) {
Log.e(TAG, message);
}
static void d(String message) {
Log.d(TAG, message);
}
}

View File

@ -0,0 +1,190 @@
package com.yhao.floatwindow;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.view.View;
import android.view.WindowManager;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import static com.yhao.floatwindow.Rom.isIntentAvailable;
/**
* Created by yhao on 2017/12/30.
* https://github.com/yhaolpz
* <p>
* 需要清楚一个MIUI版本对应小米各种机型基于不同的安卓版本但是权限设置页跟MIUI版本有关
* 测试TYPE_TOAST类型
* 7.0
* 小米 5 MIUI8 -------------------- 失败
* 小米 Note2 MIUI9 -------------------- 失败
* 6.0.1
* 小米 5 -------------------- 失败
* 小米 红米note3 -------------------- 失败
* 6.0
* 小米 5 -------------------- 成功
* 小米 红米4A MIUI8 -------------------- 成功
* 小米 红米Pro MIUI7 -------------------- 成功
* 小米 红米Note4 MIUI8 -------------------- 失败
* <p>
* 经过各种横向纵向测试对比得出一个结论就是小米对TYPE_TOAST的处理机制毫无规律可言
* 跟Android版本无关跟MIUI版本无关addView方法也不报错
* 所以最后对小米6.0以上的适配方法是不使用 TYPE_TOAST 类型统一申请权限
*/
class Miui {
private static final String miui = "ro.miui.ui.version.name";
private static final String miui5 = "V5";
private static final String miui6 = "V6";
private static final String miui7 = "V7";
private static final String miui8 = "V8";
private static final String miui9 = "V9";
private static List<PermissionListener> mPermissionListenerList;
private static PermissionListener mPermissionListener;
static boolean rom() {
LogUtil.d(" Miui : " + Miui.getProp());
return Build.MANUFACTURER.equals("Xiaomi");
}
private static String getProp() {
return Rom.getProp(miui);
}
/**
* Android6.0以下申请权限
*/
static void req(final Context context, PermissionListener permissionListener) {
if (PermissionUtil.hasPermission(context)) {
permissionListener.onSuccess();
return;
}
if (mPermissionListenerList == null) {
mPermissionListenerList = new ArrayList<>();
mPermissionListener = new PermissionListener() {
@Override
public void onSuccess() {
for (PermissionListener listener : mPermissionListenerList) {
listener.onSuccess();
}
mPermissionListenerList.clear();
}
@Override
public void onFail() {
for (PermissionListener listener : mPermissionListenerList) {
listener.onFail();
}
mPermissionListenerList.clear();
}
};
req_(context);
}
mPermissionListenerList.add(permissionListener);
}
private static void req_(final Context context) {
switch (getProp()) {
case miui5:
reqForMiui5(context);
break;
case miui6:
case miui7:
reqForMiui67(context);
break;
case miui8:
case miui9:
reqForMiui89(context);
break;
}
FloatLifecycle.setResumedListener(new ResumedListener() {
@Override
public void onResumed() {
if (PermissionUtil.hasPermission(context)) {
mPermissionListener.onSuccess();
} else {
mPermissionListener.onFail();
}
}
});
}
private static void reqForMiui5(Context context) {
String packageName = context.getPackageName();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", packageName, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
LogUtil.e("intent is not available!");
}
}
private static void reqForMiui67(Context context) {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter",
"com.miui.permcenter.permissions.AppPermissionsEditorActivity");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
LogUtil.e("intent is not available!");
}
}
private static void reqForMiui89(Context context) {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setPackage("com.miui.securitycenter");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
LogUtil.e("intent is not available!");
}
}
}
/**
* 有些机型在添加TYPE-TOAST类型时会自动改为TYPE_SYSTEM_ALERT通过此方法可以屏蔽修改
* 但是...即使成功显示出悬浮窗移动的话也会崩溃
*/
private static void addViewToWindow(WindowManager wm, View view, WindowManager.LayoutParams params) {
setMiUI_International(true);
wm.addView(view, params);
setMiUI_International(false);
}
private static void setMiUI_International(boolean flag) {
try {
Class BuildForMi = Class.forName("miui.os.Build");
Field isInternational = BuildForMi.getDeclaredField("IS_INTERNATIONAL_BUILD");
isInternational.setAccessible(true);
isInternational.setBoolean(null, flag);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,24 @@
package com.yhao.floatwindow;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class MoveType {
static final int fixed = 0;
public static final int inactive = 1;
public static final int active = 2;
public static final int slide = 3;
public static final int back = 4;
@IntDef({fixed, inactive, active, slide, back})
@Retention(RetentionPolicy.SOURCE)
@interface MOVE_TYPE {
}
}

View File

@ -0,0 +1,11 @@
package com.yhao.floatwindow;
/**
* Created by yhao on 2017/11/14.
* https://github.com/yhaolpz
*/
public interface PermissionListener {
void onSuccess();
void onFail();
}

View File

@ -0,0 +1,85 @@
package com.yhao.floatwindow;
import android.app.AppOpsManager;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.view.View;
import android.view.WindowManager;
import java.lang.reflect.Method;
/**
* Created by yhao on 2017/12/29.
* https://github.com/yhaolpz
*/
class PermissionUtil {
static boolean hasPermission(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Settings.canDrawOverlays(context);
} else {
return hasPermissionBelowMarshmallow(context);
}
}
static boolean hasPermissionOnActivityResult(Context context) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
return hasPermissionForO(context);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Settings.canDrawOverlays(context);
} else {
return hasPermissionBelowMarshmallow(context);
}
}
/**
* 6.0以下判断是否有权限
* 理论上6.0以上才需处理权限但有的国内rom在6.0以下就添加了权限
* 其实此方式也可以用于判断6.0以上版本只不过有更简单的canDrawOverlays代替
*/
static boolean hasPermissionBelowMarshmallow(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Method dispatchMethod = AppOpsManager.class.getMethod("checkOp", int.class, int.class, String.class);
//AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
return AppOpsManager.MODE_ALLOWED == (Integer) dispatchMethod.invoke(
manager, 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName());
} catch (Exception e) {
return false;
}
}
/**
* 用于判断8.0时是否有权限仅用于OnActivityResult
* 针对8.0官方bug:在用户授予权限后Settings.canDrawOverlays或checkOp方法判断仍然返回false
*/
@RequiresApi(api = Build.VERSION_CODES.M)
private static boolean hasPermissionForO(Context context) {
try {
WindowManager mgr = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (mgr == null) return false;
View viewToAdd = new View(context);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(0, 0,
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
viewToAdd.setLayoutParams(params);
mgr.addView(viewToAdd, params);
mgr.removeView(viewToAdd);
return true;
} catch (Exception e) {
LogUtil.e("hasPermissionForO e:" + e.toString());
}
return false;
}
}

View File

@ -0,0 +1,10 @@
package com.yhao.floatwindow;
/**
* Created by yhao on 2017/12/30.
* https://github.com/yhaolpz
*/
interface ResumedListener {
void onResumed();
}

View File

@ -0,0 +1,44 @@
package com.yhao.floatwindow;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created by yhao on 2017/12/30.
* https://github.com/yhaolpz
*/
class Rom {
static boolean isIntentAvailable(Intent intent, Context context) {
return intent != null && context.getPackageManager().queryIntentActivities(
intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
static String getProp(String name) {
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + name);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
String line = input.readLine();
input.close();
return line;
} catch (IOException ex) {
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,21 @@
package com.yhao.floatwindow;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by yhao on 2017/12/23.
* https://github.com/yhaolpz
*/
public class Screen {
public static final int width = 0;
public static final int height = 1;
@IntDef({width, height})
@Retention(RetentionPolicy.SOURCE)
@interface screenType {
}
}

View File

@ -0,0 +1,52 @@
package com.yhao.floatwindow;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import java.lang.reflect.Method;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
class Util {
static View inflate(Context applicationContext, int layoutId) {
LayoutInflater inflate = (LayoutInflater) applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflate.inflate(layoutId, null);
}
private static Point sPoint;
static int getScreenWidth(Context context) {
if (sPoint == null) {
sPoint = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getSize(sPoint);
}
return sPoint.x;
}
static int getScreenHeight(Context context) {
if (sPoint == null) {
sPoint = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getSize(sPoint);
}
return sPoint.y;
}
static boolean isViewVisible(View view) {
return view.getGlobalVisibleRect(new Rect());
}
}

View File

@ -0,0 +1,21 @@
package com.yhao.floatwindow;
/**
* Created by yhao on 2018/5/5
* https://github.com/yhaolpz
*/
public interface ViewStateListener {
void onPositionUpdate(int x, int y);
void onShow();
void onHide();
void onDismiss();
void onMoveAnimStart();
void onMoveAnimEnd();
void onBackToDesktop();
}

View File

@ -0,0 +1,42 @@
package com.yhao.floatwindow;
/**
* Created by yhao on 2018/5/5.
* https://github.com/yhaolpz
*/
public class ViewStateListenerAdapter implements ViewStateListener{
@Override
public void onPositionUpdate(int x, int y) {
}
@Override
public void onShow() {
}
@Override
public void onHide() {
}
@Override
public void onDismiss() {
}
@Override
public void onMoveAnimStart() {
}
@Override
public void onMoveAnimEnd() {
}
@Override
public void onBackToDesktop() {
}
}

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">FFWindow</string>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="permission_PermissionActivity" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="android:statusBarColor" tools:targetApi="lollipop">@android:color/transparent</item>
</style>
</resources>

View File

@ -0,0 +1,17 @@
package com.example.fixedfloatwindow;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View File

@ -1,2 +1 @@
include ':app', ':my_library' include ':app', ':floatwindow'
project(':my_library').projectDir = new File('library')