模仿360安全卫士项目笔记7


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 发进来短信 2 发出去短信

read 1已读短信 0 未读短信

 

  C:参照源代码Uri路径怎么写

//备份所有的短信,未读的、已读的等待

Uri uri = Uri.parse("content://sms/");

   读取短信代码:

Cursor cursor = resolver.query(uri, new String[]{"address","date","type","body"}, nullnullnull);

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;

}

 

解释为什么要相乘

在左面上创建一个空文件连续写4a一边写一遍看

 

画图进一步分析

 

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 里面的表示系统应用 表示用户应用

 Packages.xml是存放应用的一些权限信息的;

 

系统带应用安装在system/app/目录下

 

 

 

3、用PackageManger得到应用的信息;

 

 A、创建新包com.itheima.mobilesafe.engine 里面创建新类AppInfoProvider

 B、在AppInfoProvider里面创建方法public List<AppInfo> getAppInfos()

 C、创建实体类AppInfo,并实现setget方法

   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 并创建setget方法

 

 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_itemnull);

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_itemnull)

 

运行演示看效果,修改距离左边 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_startll_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启动报错 ,金山屏蔽了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值