61_ 短信备份的原理_30
1、查看金山手机卫士的短信备份功能。
短信备份的原理,是用内容提供者读取短信,然后保存。
2、在高级工具AtoolsActivity布局文件里添加短信备份,并处理点击事件smsBackup
3、在com.itheima.mobilesafe.utils工具包目录创建工具类SmsTools用于写短信备份代码
A:短信备份方法backup(Context context,String path)
B:导出短信数据库保存的路径
data/data/com.android.provider.telephony/databases/mmssms.db
address 短信收件人发件人地址
date 短信接收的时间
type 1 发进来短信 2 发出去短信
read 1已读短信 0 未读短信
C:参照源代码Uri路径怎么写
//备份所有的短信,未读的、已读的等待
Uri uri = Uri.parse("content://sms/");
读取短信代码:
Cursor cursor = resolver.query(uri, new String[]{"address","date","type","body"}, null, null, null);
while(cursor.moveToNext()){
String address = cursor.getString(0);
String date = cursor.getString(1);
String type = cursor.getString(2);
String body = cursor.getString(3);
}
把短信生成XML文件,得到xml的序列化器,设置参数
XmlSerializer serializer = Xml.newSerializer();
File file = new File(path);
FileOutputStream os = new FileOutputStream(file);
//设置序列化器的参数
serializer.setOutput(os, "utf-8");
设置文档的开头和结束
serializer.startDocument("utf-8", true);
serializer.endDocument();
设置文档根节点smss开始和结束
serializer.startTag(null, "smss");
serializer.endTag("", "smss");
设置sms里面具体内容,在while循环里面做
serializer.startTag(null, "sms");
serializer.startTag(null, "address");
String address = cursor.getString(0);
serializer.text(address);
serializer.endTag(null, "address");
serializer.endTag(null, "sms");
4、使用写好的短信备份工具
判断sdcard是否存在
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),"smsbackup.xml");
try {
SmsTools.backup(this, file.toString());
Toast.makeText(this, "短信备份成功", 0).show();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(this, "短信备份失败", 0).show();
}
}else{
Toast.makeText(this, "sdcard不可用", 0).show();
return;
}
5、添加读短信的权限
<uses-permission ndroid:name="android.permission.READ_SMS" />
知识拓展 生成excel表 poc
http://blog.youkuaiyun.com/zhy_cheng/article/details/10286563
62_接口和回调_26
1、当前备份短信代码,是写在主线程,如果短信很多的话会出现ANR异常。
2、把短信备份代码移植到子线程;
new Thread(){
public void run() {
try {
SmsTools.backup(AtoolsActivity.this, file.toString());
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
3、模拟短信备份耗时,在没一个While循环里休眠1000毫秒
4、创建一个对话框ProgressDialog用户等待备份时间,和消掉对话框
显示对话框
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setMessage("请稍等,正在备份钟...");
dialog.show();
备份完后在子线程消掉对话框?
dialog.dismiss();
运行演示,看效果;
5、做成是有加载进度的对话框
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
但是我们需要知道总条数和当前备份了多少条;
运行演示看效果
在短信备份方法增加参数ProgressDialog dialog参数
在备份方法里设置短信总条数
//设置总条数
dialog.setMax(cursor.getCount());
定义进度
//当前进度
int progress = 0;
在while循环里跟新进度
progress ++;
dialog.setProgress(progress);
考虑在工作中真实的情况:
备份短信界面 UI 是由A程序员写的;
备份短信的功能工具类 是用B程序员写的;
A程序员被老板叫去需要改成进度条,在布局文件修改
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
在代码里初始化
(ProgressBar) findViewById(R.id.progressBar1);
并找程序员B帮忙吧参数修改成ProgressBar
这时候程序员A又被老板叫去说,还没有原来的好看,改成原来的吧;如果有版本控制工具,可以还原,但同时也还原了B程序员的代码;
这时候老板又突发奇想,说想要对话框同时显示进度条
A程序员就需要把注释的地方打开,然后需要B程序员再增加一个参数ProgressDialog ,B程序员还需要做如下代码:
progressDialog.setMax(cursor.getCount());
在while循环里还得progressDialog.setProgress(progress);
给我暴露一个接口吧
给我提供一个回调
6、接口的定义
B工程师最关心的是备份的过程,并不关心如何更新UI;
但B工程师知道在相应时间更新需要跟新对应UI;
B工程师定义一个接口。暴露一些回调;
// B 工程师就定义一个接口,暴露一些回调方法;
public interface SmsBackupCallBack {
/**
* 当短信备份前调用的方法
* @param total 短信的总条数
*/
public void beforeSmsBackup(int total);
/**
* 当短信备份过程中调用
* @param progress 备份的进度
*/
public void onSmsBackup(int progress);
}
备份方法参数和里面的变化
backup(Context context, String path, SmsBackupCallBack backupCallBack)
当短信备份前调用的方法
backupCallBack.beforeSmsBackup(cursor.getCount());
While循环里面的代码
backupCallBack.onSmsBackup(progress);
7、回调的使用
new SmsBackupCallBack() {
@Override
public void onSmsBackup(int progress) {
dialog.setProgress(progress);
progressBar1.setProgress(progress);
}
@Override
public void beforeSmsBackup(int total) {
dialog.setMax(total);
progressBar1.setMax(total);
}
}
A程序员有接到任务了,把进度掉去掉就行了,这样就很方便了;
63_获取手机存储空间信息_22
1、要开发软件管理这个功能了,启动2.3模拟题,参照金山手机卫士看一下;
2、创建AppManagerActivity并在功能清单文件注册,验证完成跳转逻辑;
3、参照金山手机卫士,写相对布局,用于保存
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/tv_avail_rom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="3dip"
android:text="内存可用:"
android:textColor="#000000"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_avail_sd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="3dip"
android:text="sd卡可用:"
android:textColor="#000000"
android:textSize="16sp" />
</RelativeLayout>
这里说的内存和电脑说的内存是有区别的,这里的内存指的是手机内部存储空间,相当于手机内置了一块硬盘;
4、获取某个路径可用的空间的大小
public long getTotalSpace(String path){
StatFs statfs = new StatFs(path);
//得到有多少个可以使用
int count =statfs.getAvailableBlocks();
//得到每一个的容量
int size = statfs.getBlockSize();
return count*size;
}
解释为什么要相乘
在左面上创建一个空文件连续写4个a一边写一遍看
画图进一步分析
5、修改getTotalSpace()方法直接返回计算好的结构
/**
* 获取某一个路径的可用空间的总大小
* @param path
* @return
*/
public String getTotalSpace(String path){
StatFs statfs = new StatFs(path);
//得到一个可以用的区域的大小
int count =statfs.getAvailableBlocks();
//得到一个可以用的区域的个数
int size = statfs.getBlockSize();
return Formatter.formatFileSize(this, count*size);
}
Formatter的包是: android.text.format
高端手机内存比较大,int类型无法容纳,需要改成long类型
原理:int 最大值2147483647
2147483647/1024 = 2097151.999023438 KB
2097151.999023438/1024 = 2047.999999046326 MB;
2047.999999046326/1024 = 1.999999999068677 GB
支持2G左右的大小数据,多余的就溢出了
public String getTotalSpace(String path){
StatFs statfs = new StatFs(path);
long count =statfs.getAvailableBlocks();
long size = statfs.getBlockSize();
return Formatter.formatFileSize(this, count*size);
}
64_获取手机里面应用程序信息_20
1、Android的应用程序安装在哪里呀?
pc电脑默认安装在C:\Program Files
Android 的应用安装在哪里呢,如果是用户程序,安装在data/app/目录下
安装Android软件 做两件事
A:把APK拷贝到data/app/目录下
B:把安装包信息写到data/system/目录下两个文件packages.list 和 packages
2、安装包信息在data/system/
Packages.list 里面的0 表示系统应用 1 表示用户应用
Packages.xml是存放应用的一些权限信息的;
系统带应用安装在system/app/目录下
3、用PackageManger得到应用的信息;
A、创建新包com.itheima.mobilesafe.engine 里面创建新类AppInfoProvider
B、在AppInfoProvider里面创建方法public List<AppInfo> getAppInfos()
C、创建实体类AppInfo,并实现set和get方法
private Drawable icon;
private String name;
private String packageName;
private boolean isRom;
4、部分代码的实现
PackageManager pm = context.getPackageManager();
List<PackageInfo> infos = pm.getInstalledPackages(0);
for(PackageInfo info : infos){
AppInfo appinfo = new AppInfo();
String packageName = info.packageName;
Drawable icon = info.applicationInfo.loadIcon(pm);
String name = info.applicationInfo.loadLabel(pm).toString();
appinfo.setIcon(icon);
appinfo.setName(name);
appinfo.setPackageName(packageName);
appinfos.add(appinfo);
}
5、写测试代码测试com.ithiema.mobilesafe.test
public class TestAppInfoProvider extends AndroidTestCase {
public void testgetAppInfos(){
List<AppInfo> appinfos = AppInfoProvider.getAppInfos(getContext());
for(int i = 0; i < appinfos.size();i++){
AppInfo info = appinfos.get(i);
System.out.println(info.toString());
}
}
}
6、为看方便打印,重新toString()方法
65_程序管理器的UI显示_43
1、获取应用程序类型,是用户应用还是系统应用
在AppInfo 实体类增加 boolean isUuserApp 并创建set和get方法
info.applicationInfo.flags;
//flags是应用程序的特征标志。可以是任意标志的组合 。
一个int在内存中占4个字节,一个字节占8个二进制位,所以一个int在内存中表示32位。
画图分析理解flags
最多可以移位31位,因为总共有32位;这样设计的目的是什么呢?
看看生活中的案例--机读卡看图片
答题卡 英语答题卡 参照机读卡思路和原理我们开发一个机读系统
举例生活中的例子,老师手工改试卷
如何知道是系统应用还是用户应用的,画图理解
写具体代码了---判断是系统应用还是用户应用
if((flas & ApplicationInfo.FLAG_SYSTEM)==0){
//用户应用
}else{
//系统应用
}
判断是按照在内存里还是外部存储里面
if((flas & ApplicationInfo.FLAG_EXTERNAL_STORAGE)==0){
//手机内存
}else{
//外部存储
}
与运算比if else 判断效率高一些
赋值测试运行;
2、布局文件写上ListView ,并加上加载效果
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="@+id/ll_app_manager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ListView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical" >
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载应用程序..." />
</LinearLayout>
</FrameLayout>
3.初始化ListView和加载效果线性布局并加载数据
A:在onCreate()方法里,子线程加载数据
new Thread(){
public void run() {
infos = AppInfoProvider.getAppInfos(AppManagerActivity.this);
handler.sendEmptyMessage(0);
};
}.start();
刷新界面用handler
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
adapter = new MyAppAdapter();
ll_app_manager.setAdapter(adapter);
};
};
B:自定义Adapter,并把数据传进数据,自定义每条的布局list_app_item.xml;布局文件模仿金山手机卫士部分功能
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dip" >
<ImageView
android:id="@+id/iv_icon"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:src="@drawable/app" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dip"
android:layout_toRightOf="@id/iv_icon"
android:text="程序名称"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dip"
android:layout_toRightOf="@id/iv_icon"
android:layout_below="@id/tv_name"
android:text="安装位置"
android:textColor="#88000000"
android:textSize="14sp" />
</RelativeLayout>
代码实现getView()里:
View view = null;
ViewHolder holder;
if(convertView != null){
view = convertView ;
holder = (ViewHolder) view.getTag();
}else{
view =View.inflate(AppManagerActivity.this, R.layout.list_app_item, null);
holder = new ViewHolder();
holder.iv_icon = (ImageView) view.findViewById(R.id.iv_icon);
holder.tv_name = (TextView) view.findViewById(R.id.tv_name);
holder.tv_location = (TextView) view.findViewById(R.id.tv_location);
view.setTag(holder);
}
AppInfo info = infos.get(position);
holder.iv_icon.setImageDrawable(info.getIcon());
holder.tv_name.setText(info.getName());
if(info.isRom()){
holder.tv_location.setText("手机内存");
}else{
holder.tv_location.setText("外部存储");
}
4、设置指定应用安装在手机内存中还是外部存储卡中
在功能清单根节点处添加
android:installLocation="auto"
auto:自动安装,优先安装在手机内存里面 ,可以切换;
internalOnly:只安装在手机内存里面,不可以切换;
preferExternal:安装在外包存储,可以选切换;
66_复杂的ListView的显示_29
1、把系统应用和用户应用区分开来
定义两个集合
List<AppInfo> userInfos; 、List<AppInfos> systemInfos;
初始化数据,用for区分开来
userInfos = new ArrayList<AppInfo>();
systemInfos = new ArrayList<AppInfo>();
for(AppInfo info : infos){
if(info.isUserApp()){
//用户应用
userInfos.add(info);
}else{
//系统应用
systemInfos.add(info);
}
}
2、 在适配器 getCount()方法里重写成如下;
public int getCount() {
return userInfos.size()+systemInfos.size();
}
在适配器的getView()方法如何修改呢?
画图分析
3、代码实现
AppInfo info = null;
if(position < userInfos.size()){
//加载用户程序
info = userInfos.get(position);
}else{
//加载系统程序
//系统的0
int newposition = position -userInfos.size() ;
info = systemInfos.get(newposition);
}
系统应用和用户应用的区别,系统的没法卸载,用户程序可以卸载
4、修改适配器增加 用户程序 和 系统程序 条目
A:在适配器getCount()方法里修改
public int getCount() {
//多了两个TextView的item 所以 +1 +1
return userInfos.size()+1+systemInfos.size()+1;
}
B:在getView()方法里修改
getView的作用:是控制每个位置显示的内容
添加用户程序的TextView
if(position == 0){//创建一个TextView显示多少个用户程序
TextView view = new TextView(AppManagerActivity.this);
view.setText("用户程序("+userInfos.size()+")");
view.setTextColor(Color.WHITE);
view.setBackgroundColor(Color.GRAY);
return view;
}
添加系统程序的TextView
else if(position == userInfos.size() +1 ){
TextView view = new TextView(AppManagerActivity.this);
view.setText("系统程序("+systemInfos.size()+")");
view.setTextColor(Color.WHITE);
view.setBackgroundColor(Color.GRAY);
return view;
}
特殊情况处理了,需要处理一般情况了,画图分析
用户程序显示
else if(position <= userInfos.size()){
//用户程序
int newposition = position -1;
info = userInfos.get(newposition);
}
系统程序显示
else{
//系统程序
int newposition = position -1- userInfos.size() - 1;
info = systemInfos.get(newposition);
}
运行拖动演示报错,讲解报错的原因
删除应用 ,进入应用管理 ,删除应用 进入应用管理
contverView
重用旧的视图,如果可能的话。注意:您应该检查,这个观点是在使用非空和适当的类型。如果它是不可能将这个视图来显示正确的数据,这种方法可以创建一个新的视图。异构列表可以指定数量的视图类型,以便这一观点总是正确的类型(见getViewTypeCount()和getItemViewType(int))。
5、解决报错问题
if(convertView!=null&&convertView instanceof RelativeLayout){
//.................
}else{
//.............
}
6、回顾处理ListView 中的getCount()和getView()这个过程
67_ListView的状态栏_14
知识拓展,增加快速滚动条
在ListView布局文件加上:
android:fastScrollEnabled="true"
1、在布局文件添加TextView长得和getView里面创建的一样
<TextView
android:textColor="#ffffff"
android:background="#ff888888"
android:text="用户程序(7)"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
2.给ListView设置滚动监听
ll_app_manager.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(systemInfos != null&&userInfos != null){
if(firstVisibleItem > userInfos.size()){
//显示系统应用
tv_status.setText("系统程序("+systemInfos.size()+")");
}else{
//显示用户应用
tv_status.setText("用户程序("+userInfos.size()+")");
}
}
}
});
68_popupwindow的使用_44
1、打开2.3模拟器演示联系人效果
2、创建一个新工程专门学习popupwindow
一个弹出窗口,可以用来显示一个任意视图。弹出窗口是一个浮动的容器,出现在当前活动的顶端。
在按钮中添加点击事件
初识popupWindow
TextView contentView = new TextView(this);
contentView.setText("我是PopupWindow");
contentView.setTextColor(Color.RED);
View parent = findViewById(R.id.rl_root);
PopupWindow window = new PopupWindow(contentView, 200, 100);
window.showAtLocation(parent, Gravity.LEFT + Gravity.TOP, 200, 100);
左上角对齐
通过设置PopupWindow 的背景,了解它有多大
PopupWindow window = new PopupWindow(contentView, 200, 100);
window.setBackgroundDrawable(new ColorDrawable(Color.GREEN));
window.showAtLocation(parent, Gravity.LEFT + Gravity.TOP, 200, 100);
点击返回直接退出Activity
对话框点击退出是消掉,那么PopupWindow是否也可以呢?
PopupWindow window = new PopupWindow(contentView, 200, 100,true);
3、把学习好的PopupWindow 移植到工程中
A:监听每点一条的事件,并打印日志;
Object obj = ll_app_manager.getItemAtPosition(position);
System.out.println("obj=="+obj);
getItemAtPosition(position): 获取数据列表中指定的位置。
B:在适配器中修改如下,运行点击,看日志
public Object getItem(int position) {
return "asbllldkk";
}
解决该问题:
@Override
public Object getItem(int position) {
AppInfo info = null;
if(position == 0){//创建一个TextView显示多少个用户程序
return null;
}else if(position == userInfos.size() +1 ){
return null;
}else if(position <= userInfos.size()){
//用户程序
int newposition = position -1;
info = userInfos.get(newposition);
}else{
//系统程序
int newposition = position -1- userInfos.size() - 1;
info = systemInfos.get(newposition);
}
return info;
}
点击事件做处理,运行看日志
Object obj = ll_app_manager.getItemAtPosition(position);
if(obj != null){
AppInfo info = (AppInfo) obj;
System.out.println("info=="+info.getPackageName());
}
4、在点击事件中添加PopuWindow,运行演示,并点击看效果
TextView contentView = new TextView(AppManagerActivity.this);
contentView.setText(info.getPackageName());
contentView.setTextColor(Color.RED);
PopupWindow popupWindow = new PopupWindow(contentView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int [] location = new int[2];
view.getLocationInWindow(location);
popupWindow.showAtLocation(parent, Gravity.LEFT+Gravity.TOP, 0, location[1]);
5、希望同一时间只能显示一个PopupWindow
把PopWindow定义成类的成员变量
每次点击,隐藏上次创建的,便于重新创建
if(popupWindow != null&&popupWindow.isShowing()){
popupWindow.dismiss();
popupWindow = null;
}
6、滚动时隐藏PopupWindow
把隐藏PopupWindow代码重构成一个方法dimissPopupWindow();
在监听滚动处onScroll()和点击前调用即可;
7、自定义布局文件加载到PopupWindow里;
我们希望,弹出的PopupWindow有三个功能,启动软件 卸载软件 分享软件
自定义线性布局文件popup_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/local_popup_bg"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="卸载"
android:textColor="#000000" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动"
android:textColor="#000000" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="分享"
android:textColor="#000000" />
</LinearLayout>
</LinearLayout>
把布局文件加载到PopupWindow里面
把TextView 注释掉,加载如下代码
View contentView = View.inflate(getApplicationContext(), R.layout.popup_item, null)
运行演示看效果,修改距离左边 60个像数;
解决图片竖直方法不协调文,把图片local_popup_bg移动到drawable-hdpi目录,运行,并解释现象;
当前模拟器屏幕是480*800,当前引用的图片drawable-hdpi目录下图片,最适合他,如果找不到就会到drawbale目录下去找,drawbale是所有屏幕默认使用的图片,它没有对图片做缩放处理;图片是多大就显示多大;drawable-xxhdpi目录下图片是给超大手机屏幕使用的,如果在其他目录没有找到图片,它就到drawable-xxhdpi去找,本身图片就很大,显示的时候做缩小显示。当热缩小也是不会很小。
开发过程中,一般会有两套以上图片
8、给PopupWindow加上两个动画效果
AlphaAnimation aa = new AlphaAnimation(0.5f, 1.0f);
aa.setDuration(500);
ScaleAnimation sa = new ScaleAnimation(0.5f, 1.0f, 0.5f,
1.0f, Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0.5f);
sa.setDuration(500);
AnimationSet set = new AnimationSet(false);
set.addAnimation(sa);
set.addAnimation(aa);
//播放动画
contentView.startAnimation(set);
演示当时间设置5秒也没用效果,原因是PopupWindow没有加背景;
播放动画是要前提:就是窗体必须有背景;为什么呢?
如果没有背景的话,就不知道以怎么样的方式画出来,没有办法去合成背景颜色。
9、要想有动画效果就需要设置背景,透明背景也行
popupWindow = new PopupWindow(contentView,
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
//必须要设置背景
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
注意:需要在构造方法后面这张背景,在
popupWindow.showAtLocation(parent, Gravity.LEFT
+ Gravity.TOP, 60, location[1]);
后面才设置背景同样也是没有效果的。
69_软件管理器的完成_39
1、定义ID处理点击事件ll_uninstall 、ll_start、ll_share
在线性布局加上ID,初始化成类的成员变量。
private LinearLayout ll_uninstall;
private LinearLayout ll_start;
private LinearLayout ll_share;
在Activity设置点击事件
ll_uninstall.setOnClickListener(AppManagerActivity.this);
ll_start.setOnClickListener(AppManagerActivity.this);
ll_share.setOnClickListener(AppManagerActivity.this);
AppInfo 也定义成类的成员变量,并写注释;
private AppInfo info ;
处理点击事件,打日志,点击并把PopupWindow消掉
@Override
public void onClick(View v) {
dimissPopupWindow();
switch (v.getId()) {
case R.id.ll_uninstall:
Log.i(TAG, "卸载:"+info.getName());
break;
case R.id.ll_share:
Log.i(TAG, "分享:"+info.getName());
break;
case R.id.ll_start:
Log.i(TAG, "启动:"+info.getName());
break;
}
}
2、卸载程序
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse("package:"+info.getPackageName()));
startActivity(intent);
卸载后刷新界面
启动Intent 改成
startActivityForResult(intent, 0);
把刷得到数据,并刷新界面的代码重构到fillData()方法里面
在onActivityResult();调用fillData方法,代码如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
fillData();
}
卸载系统应用加上判断
if(info.isUserApp()){
}else{
Toast.makeText(this, "系统应用需要root权限后才能卸载", 0).show();
}
3、软件的分享
进入金山软件主页,按菜单键。点击推荐
金山的包名:com.ijinshan.mguard
QQ的包名:com.tencent.mobileqq
写代码是参照短信应用去写Action
/**
* 分享应用
*/
private void shareApp() {
Intent intent = new Intent();
//<action android:name="android.intent.action.SEND" />
//<category android:name="android.intent.category.DEFAULT" />
// <data android:mimeType="text/plain" />
intent.setAction("android.intent.action.SEND");
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "推荐一款软件名叫:"+info.getName()+",下载地址:ccc"+info.getPackageName());
startActivity(intent) ;
}
https://play.google.com/store/apps/details?id=com.tencent.mobileqq
知识拓展,当前的代码已经支持分享到QQ空间里面了;
详情:
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + clickedAppInfo.getPackname()));
startActivity(intent);
4、软件的启动,打开应用程序的Activity
启动原理,开启Activity ,第一个Activity是通常是启动类;
private void startApp() {
Intent intent = new Intent();
PackageManager pm = getPackageManager();
try {
PackageInfo packInfo = pm.getPackageInfo(info.getPackageName(), 0);
ActivityInfo [] acivityInfos = packInfo.activities;
if(acivityInfos != null&&acivityInfos.length>0){
ActivityInfo activityInfo = acivityInfos[0];
intent.setClassName(info.getPackageName(), activityInfo.name);
startActivity(intent);
}else{
Toast.makeText(this, "这个程序没有界面", 0).show();
}
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(this, "这个应用无法启动", 0).show();
}
}
解决弹出没有界面的问题,分析问题的原因
PackageInfo packInfo = pm.getPackageInfo(info.getPackageName(),PackageManager.GET_ACTIVITIES);
演示启动各个软件,启动联系人 Pico TTS启动报错 ,金山屏蔽了