用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - android代码库

使用android sdk 隐藏的类--VolumePreference

2014-04-21 作者: elewen举报

[android]代码库

Android真是可恶,sdk里面有的类但是在使用的时候却被隐藏了……真不知道他为啥要在sdk里面公开出来,
 
你都用不了,你公开有啥用阿……网上找了一下解决办法 ,一种是说通过定制定制android.jar的方法来实现
(传送门:http://luhuajcdd.iteye.com/blog/1242419  ),另一种是说使用反射的办法。但是第一种在
 

用混淆的时候出错了,依然提示该类无法找到。没办法只好使用反射拉,不过如果需要继承这个隐藏的类那又

 

改咋办呢?ok,那就是下载源代码,然后从将 android.preference.VolumePreference 源代码移到我们的项目

 

中去吧,酱紫就可以解决了。 

 

不过导入到项目中也不是意见很简单的事情,要知道他还会引用其他的类呢,搞不好。。。要导入一堆类呢。

 

下面就是已经完成了的  android.preference.VolumePreference 的类,我已经将其改名成 VolumePreferenceEx

 

这样,引用就不会有歧义拉。。

 

 

 


复制代码
package apollo.preference;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.preference.Preference.BaseSavedState;
import android.preference.PreferenceManager.OnActivityStopListener;
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import apollo.profilesetting.view.R;

public class VolumePreferenceEx extends SeekBarPreferenceEx implements
        PreferenceManager.OnActivityStopListener, View.OnKeyListener {

    private int mStreamType;
    private SeekBarVolumizer mSeekBarVolumizer;
    
    public VolumePreferenceEx(Context context, AttributeSet attrs) {
        super(context, attrs);
        Class<?> clazz = null;
        int[] styleable = null;
        Field field = null;
        int stream_type = 0;
        
        try {
            clazz = Class.forName("android.R$styleable");
            field = clazz.getField("VolumePreference");  
            styleable = (int[])field.get(clazz);
            
            field = clazz.getField("VolumePreference");  
            stream_type = (Integer)field.get(clazz);
        } catch (Exception ex) {
            styleable = new int[]{16843273};
        }

        // TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VolumePreference, 0, 0);
        // mStreamType = a.getInt(R.styleable.VolumePreference_streamType, 0);
        // a.recycle();

        //int[] styleable = {16843273};
        
        
        TypedArray a = context.obtainStyledAttributes(attrs, styleable, 0, 0);
        mStreamType = a.getInt(stream_type, 0);
        a.recycle();
    }
    
    public void setStreamType(int streamType) {
        mStreamType = streamType;
    }
    
    private void callActivityStopListener(String name) {
        Method method = null;
        PreferenceManager manager = null;
        Class<?>[] clazzs = null;
        Object[] objs = null;
        
        clazzs = new Class<?>[1];
        clazzs[0] = OnActivityStopListener.class;
        
        objs = new Object[1];
        objs[0] = this;
        
        manager = this.getPreferenceManager();
        try {
            method = PreferenceManager.class.getDeclaredMethod(name, clazzs);
            method.invoke(manager, objs);
        } catch (Exception ex) {
        }
    }
    
    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);       
        final SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);

        callActivityStopListener("registerOnActivityStopListener");

        // grab focus and key events so that pressing the volume buttons in the
        // dialog doesn't also show the normal volume adjust toast.
        view.setOnKeyListener(this);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (mSeekBarVolumizer == null) return true;
        boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_DOWN:
                if (isdown) {
                    mSeekBarVolumizer.changeVolumeBy(-1);
                }
                return true;
            case KeyEvent.KEYCODE_VOLUME_UP:
                if (isdown) {
                    mSeekBarVolumizer.changeVolumeBy(1);
                }
                return true;
            default:
                return false;
        }
    }
    
    @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        
        if (!positiveResult && mSeekBarVolumizer != null) {
            mSeekBarVolumizer.revertVolume();
        }

        cleanup();
    }

    @Override
    public void onActivityStop() {
        cleanup();
    }

    private void cleanup() {
        callActivityStopListener("unregisterOnActivityStopListener");

           if (mSeekBarVolumizer != null) {
               Dialog dialog = getDialog();
               if (dialog != null && dialog.isShowing()) {
                   View view = dialog.getWindow().getDecorView()
                           .findViewById(R.id.seekbar);
                   if (view != null) view.setOnKeyListener(null);
                   // Stopped while dialog was showing, revert changes
                   mSeekBarVolumizer.revertVolume();
               }
               mSeekBarVolumizer.stop();
               mSeekBarVolumizer = null;
           }

        }

        protected void onSampleStarting(SeekBarVolumizer volumizer) {
            if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
                mSeekBarVolumizer.stopSample();
            }
        }

        @Override
        protected Parcelable onSaveInstanceState() {
            final Parcelable superState = super.onSaveInstanceState();
            if (isPersistent()) {
                // No need to save instance state since it's persistent
                return superState;
            }

            final SavedState myState = new SavedState(superState);
            if (mSeekBarVolumizer != null) {
                mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore());
            }
            return myState;
        }

        @Override
        protected void onRestoreInstanceState(Parcelable state) {
            if (state == null || !state.getClass().equals(SavedState.class)) {
                // Didn't save state for us in onSaveInstanceState
                super.onRestoreInstanceState(state);
                return;
            }

            SavedState myState = (SavedState) state;
            super.onRestoreInstanceState(myState.getSuperState());
            if (mSeekBarVolumizer != null) {
                mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore());
            }
        }

        public static class VolumeStore {
            public int volume = -1;
            public int originalVolume = -1;
        }

        private static class SavedState extends BaseSavedState {
            VolumeStore mVolumeStore = new VolumeStore();

            public SavedState(Parcel source) {
                super(source);
                mVolumeStore.volume = source.readInt();
                mVolumeStore.originalVolume = source.readInt();
            }

            @Override
            public void writeToParcel(Parcel dest, int flags) {
                super.writeToParcel(dest, flags);
                dest.writeInt(mVolumeStore.volume);
                dest.writeInt(mVolumeStore.originalVolume);
            }

            VolumeStore getVolumeStore() {
                return mVolumeStore;
            }

            public SavedState(Parcelable superState) {
                super(superState);
            }

            public static final Parcelable.Creator<SavedState> CREATOR =
                    new Parcelable.Creator<SavedState>() {
                public SavedState createFromParcel(Parcel in) {
                    return new SavedState(in);
                }

                public SavedState[] newArray(int size) {
                    return new SavedState[size];
                }
            };
        }

        /**
         * Turns a {@link SeekBar} into a volume control.
         */
        public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable {

            private Context mContext;
            private Handler mHandler = new Handler();
        
            private AudioManager mAudioManager;
            private int mStreamType;
            private int mOriginalStreamVolume; 
            private Ringtone mRingtone;
        
            private int mLastProgress = -1;
            private SeekBar mSeekBar;
            
            private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
                @Override
                public void onChange(boolean selfChange) {
                    super.onChange(selfChange);
                    if (mSeekBar != null) {
                        int volume = System.getInt(mContext.getContentResolver(),
                                System.VOLUME_SETTINGS[mStreamType], -1);
                        // Works around an atomicity problem with volume updates
                        // TODO: Fix the actual issue, probably in AudioService
                        if (volume >= 0) {
                            mSeekBar.setProgress(volume);
                        }
                    }
                }
            };

            public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
                mContext = context;
                mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                mStreamType = streamType;
                mSeekBar = seekBar;
                
                initSeekBar(seekBar);
            }

            private void initSeekBar(SeekBar seekBar) {
                seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
                mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
                seekBar.setProgress(mOriginalStreamVolume);
                seekBar.setOnSeekBarChangeListener(this);
                
                mContext.getContentResolver().registerContentObserver(
                        System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
                        false, mVolumeObserver);
        
                Uri defaultUri = null;
                if (mStreamType == AudioManager.STREAM_RING) {
                    defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
                } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
                    defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
                } else {
                    defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
                }

                mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
                if (mRingtone != null) {
                    mRingtone.setStreamType(mStreamType);
                }
            }
            
            public void stop() {
                stopSample();
                mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
                mSeekBar.setOnSeekBarChangeListener(null);
            }
            
            public void revertVolume() {
                mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
            }
            
            public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromTouch) {
                if (!fromTouch) {
                    return;
                }
        
                postSetVolume(progress);
            }

            void postSetVolume(int progress) {
                // Do the volume changing separately to give responsive UI
                mLastProgress = progress;
                mHandler.removeCallbacks(this);
                mHandler.post(this);
            }
        
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            public void onStopTrackingTouch(SeekBar seekBar) {
                if (mRingtone != null && !mRingtone.isPlaying()) {
                    sample();
                }
            }
            
            public void run() {
                mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
            }
            
            private void sample() {
                onSampleStarting(this);
                mRingtone.play();
            }
        
            public void stopSample() {
                if (mRingtone != null) {
                    mRingtone.stop();
                }
            }

            public SeekBar getSeekBar() {
                return mSeekBar;
            }
            
            public void changeVolumeBy(int amount) {
                mSeekBar.incrementProgressBy(amount);
                if (mRingtone != null && !mRingtone.isPlaying()) {
                    sample();
                }
                postSetVolume(mSeekBar.getProgress());
            }

            public void onSaveInstanceState(VolumeStore volumeStore) {
                if (mLastProgress >= 0) {
                    volumeStore.volume = mLastProgress;
                    volumeStore.originalVolume = mOriginalStreamVolume;
                }
            }

            public void onRestoreInstanceState(VolumeStore volumeStore) {
                if (volumeStore.volume != -1) {
                    mOriginalStreamVolume = volumeStore.originalVolume;
                    mLastProgress = volumeStore.volume;
                    postSetVolume(mLastProgress);
                }
            }
        }
复制代码
 

 
 

但是真个类还引用了另一个隐藏的类 SeekBarPreference 因此,还需要将这个类也导入到项目中

 


复制代码
package apollo.preference;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import apollo.profilesetting.view.R;

public class SeekBarPreferenceEx extends DialogPreference {
    private Drawable mMyIcon;

    public SeekBarPreferenceEx(Context context, AttributeSet attrs) {
        super(context, attrs);

        setDialogLayoutResource(R.layout.seekbar_dialog);
        setPositiveButtonText(android.R.string.ok);
        setNegativeButtonText(android.R.string.cancel);
        
        // Steal the XML dialogIcon attribute's value
        mMyIcon = getDialogIcon();
        setDialogIcon(null);
    }

    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);
        
        final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
        if (mMyIcon != null) {
            iconView.setImageDrawable(mMyIcon);
        } else {
            iconView.setVisibility(View.GONE);
        }
    }

    protected static SeekBar getSeekBar(View dialogView) {
        return (SeekBar) dialogView.findViewById(R.id.seekbar);
    }
复制代码
 

 

ok,酱紫我们就完成了对隐藏类的使用拉。不过在完成这个类的过程还需要使用反射的方法使用一些隐藏的类。

 

比如android.R.styleable,这个没有源代码可以使用,所以只能靠反射了。

 

原来的代码段:

 

 

         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VolumePreference, 0, 0);
         mStreamType = a.getInt(R.styleable.VolumePreference_streamType, 0);
         a.recycle();
 

 

用反射的办法实现该代码段

 

 


复制代码
Class<?> clazz = null;
        int[] styleable = null;
        Field field = null;
        int stream_type = 0;
        
        try {
            clazz = Class.forName("android.R$styleable");
            field = clazz.getField("VolumePreference");  
            styleable = (int[])field.get(clazz);
            
            field = clazz.getField("VolumePreference");  
            stream_type = (Integer)field.get(clazz);
        } catch (Exception ex) {
        }

        
        
        TypedArray a = context.obtainStyledAttributes(attrs, styleable, 0, 0);
        mStreamType = a.getInt(stream_type, 0);
复制代码
 

还有其他的代码是需要反射实现的,看VolumePreference.callActivityStopListener方法就知道拉  ok,这样,我们就完成这个隐藏类的“实现”拉。 


网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

输入口令后可复制整站源码

加载中,请稍后...