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:
parent
6c240ad185
commit
1b78cc0904
|
@ -9,7 +9,7 @@
|
|||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/library" />
|
||||
<option value="$PROJECT_DIR$/floatwindow" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<modules>
|
||||
<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$/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>
|
||||
</component>
|
||||
</project>
|
|
@ -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.(ñ¥—²ýÿÿÿÿ
|
||||
Ksquid: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>
|
||||
Ssquid: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.(³¿á•
|
||||
Psquid: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(½²»|
|
||||
Lsquid: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
|
||||
Bsquid:S2387"."mState" is the name of a field in "Fragment".(½²»|
|
||||
Jsquid: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.(½²»|
|
|
@ -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>ÀÆ’
|
||||
ssquid: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.(üêÝ/
|
||||
Asquid: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.(ø¶Âßÿÿÿÿÿ
|
||||
qsquid: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>ýÿÿÿÿ
|
||||
ysquid: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.(ù ®Íúÿÿÿÿ
|
|
@ -1,3 +1,13 @@
|
|||
|
||||
<
|
||||
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
|
|
@ -7,10 +7,11 @@ android {
|
|||
useLibrary 'org.apache.http.legacy'
|
||||
defaultConfig {
|
||||
applicationId "com.example.administrator.myapplication"
|
||||
minSdkVersion 17
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 26
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
|
@ -40,8 +41,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile project(':my_library')
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
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.github.clans:fab:1.6.1'
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.github.yhaolpz:FloatWindow:1.0.9'
|
||||
apt 'com.jakewharton:butterknife-compiler:8.2.1'
|
||||
compile project(':floatwindow')
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
android:versionCode="1"
|
||||
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.INTERNET"/>
|
||||
<!-- 获取GSM(2g)、WCDMA(联通3g)等网络状态的信息 -->
|
||||
|
@ -28,7 +30,8 @@
|
|||
android:icon="@mipmap/app_icon"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
android:theme="@style/AppTheme"
|
||||
android:name="com.example.administrator.myapplication.app.BaseApplication">
|
||||
<activity
|
||||
android:name=".ui.WelcomeActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
|
|
|
@ -2,7 +2,14 @@ package com.example.administrator.myapplication.app;
|
|||
|
||||
import android.app.Application;
|
||||
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.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
|
||||
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.assist.QueueProcessingType;
|
||||
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 cn.bmob.v3.Bmob;
|
||||
|
||||
/**
|
||||
* Created by htq on 2016/9/5.
|
||||
*/
|
||||
|
||||
public class BaseApplication extends Application {
|
||||
|
||||
|
||||
private static final String TAG = "FloatWindow";
|
||||
private String ApplicationId="82cacaa4470ab6b8d61d3f0ce6d6201d";
|
||||
static public String avatarPath= BmobConstants.MyAvatarDir+"avatarIcon.png";
|
||||
@Override
|
||||
public void 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);
|
||||
Bmob.initialize(this, ApplicationId);
|
||||
// android 7.0系统解决拍照的问题
|
||||
|
@ -55,4 +92,53 @@ public class BaseApplication extends Application {
|
|||
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");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ import android.support.v4.app.FragmentManager;
|
|||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
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.app.AppCompatActivity;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
@ -81,7 +81,9 @@ public class MainActivity extends AppCompatActivity
|
|||
private void initUi()
|
||||
{
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
//toolbar.setTitle("hehehe");
|
||||
setSupportActionBar(toolbar);
|
||||
//toolbar.setTitle("hehehe");
|
||||
fab = (FloatingActionButton) findViewById(R.id.fab);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
|
|
@ -338,20 +338,20 @@ public void getServerData()
|
|||
inflater.inflate(R.menu.main, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (id == R.id.action_settings) {
|
||||
new SystemUtils(getActivity()).setBoolean("isTran",true);
|
||||
mGrid.setAlpha(0.55f);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
// @Override
|
||||
// public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// // Handle action bar item clicks here. The action bar will
|
||||
// // automatically handle clicks on the Home/Up button, so long
|
||||
// // as you specify a parent activity in AndroidManifest.xml.
|
||||
// int id = item.getItemId();
|
||||
//
|
||||
// //noinspection SimplifiableIfStatement
|
||||
// if (id == R.id.action_settings) {
|
||||
// new SystemUtils(getActivity()).setBoolean("isTran",true);
|
||||
// mGrid.setAlpha(0.55f);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return super.onOptionsItemSelected(item);
|
||||
// }
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 171 KiB |
|
@ -7,6 +7,122 @@
|
|||
android:fitsSystemWindows="true"
|
||||
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">-->
|
||||
|
||||
<!--<!–<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"/>-->
|
||||
<!--–>-->
|
||||
<!--<RelativeLayout-->
|
||||
<!--android:layout_width="match_parent"-->
|
||||
<!--android:layout_height="40dp"-->
|
||||
<!-->-->
|
||||
|
||||
<!--<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" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
|
@ -20,48 +136,4 @@
|
|||
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">
|
||||
|
||||
<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>
|
||||
|
|
|
@ -2,8 +2,16 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<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:orderInCategory="100"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="never" />
|
||||
app:showAsAction="never" /-->
|
||||
</menu>
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<color name="orange">#FFA500</color><!--橙色 -->
|
||||
<color name="lightsalmon">#FFA07A</color><!--亮肉色 -->
|
||||
<color name="darkorange">#FF8C00</color><!--暗桔黄色 -->
|
||||
<color name="coral">#FF7F50</color><!--珊瑚色 -->
|
||||
<color name="coral">#ff7f50</color><!--珊瑚色 -->
|
||||
<color name="hotpink">#FF69B4</color><!--热粉红色 -->
|
||||
<color name="tomato">#FF6347</color><!--西红柿色 -->
|
||||
<color name="orangered">#FF4500</color><!--红橙色 -->
|
||||
|
@ -53,7 +53,7 @@
|
|||
<color name="oldlace">#FDF5E6</color><!--老花色 -->
|
||||
<color name="lightgoldenrodyellow">#FAFAD2</color><!--亮金黄色 -->
|
||||
<color name="linen">#FAF0E6</color><!--亚麻色 -->
|
||||
<color name="antiquewhite">#FAEBD7</color><!--古董白 -->
|
||||
<color name="antiquewhite">#faebd7</color><!--古董白 -->
|
||||
<color name="salmon">#FA8072</color><!--鲜肉色 -->
|
||||
<color name="ghostwhite">#F8F8FF</color><!--幽灵白 -->
|
||||
<color name="mintcream">#F5FFFA</color><!--薄荷色 -->
|
||||
|
|
|
@ -7,6 +7,8 @@ buildscript {
|
|||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
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
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
@ -16,6 +18,7 @@ allprojects {
|
|||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://raw.github.com/bmob/bmob-android-sdk/master" }
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -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'
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.yhao.floatwindow;
|
||||
|
||||
/**
|
||||
* Created by yhao on 2017/12/30.
|
||||
* https://github.com/yhaolpz
|
||||
*/
|
||||
|
||||
interface ResumedListener {
|
||||
void onResumed();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">FFWindow</string>
|
||||
</resources>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
include ':app', ':my_library'
|
||||
project(':my_library').projectDir = new File('library')
|
||||
include ':app', ':floatwindow'
|
||||
|
|
Loading…
Reference in New Issue