android settings 소스 코드 분석(2)
적용 대상 fragment는 다음과 같습니다.
<span style="font-size:14px;"> <!-- Application Settings -->
<header
android:fragment="com.android.settings.applications.ManageApplications"
android:icon="@drawable/ic_settings_applications"
android:title="@string/applications_settings"
android:id="@+id/application_settings" /></span>
따라서 ManageApplication이 어떻게 구현되는지 확인해야 합니다.
ManageApplications 경로는 다음과 같습니다.
kikat_4.4_CTS\packages\apps\Settings\src\com\android\settings\applications
Application UI를 통해 알 수 있듯이fragment는 주로tab이고 모든tab에 RAM,SDCARD와 내부 저장 공간의 크기와 관련된 정보를 표시한다.다음은tab이 어떻게 실현되고 이런 저장 정보를 어떻게 얻는지 분석합니다.
ManageApplications의 onCreateView 함수를 보면 다음과 같습니다.
View rootView = mInflater.inflate(R.layout.manage_applications_content,
container, false);
여기서는 매니지먼트를 사용합니다applications_content.xml, xml의 내용을 보려면 다음과 같이 하십시오.
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<android.support.v4.view.PagerTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:textAppearance="@style/TextAppearance.PagerTabs"
android:padding="0dp">
</android.support.v4.view.PagerTabStrip>
</android.support.v4.view.ViewPager>
</LinearLayout>
응용 프로그램 fragment의 레이아웃은 본질적으로 하나의 ViewPager이기 때문에 좌우 슬라이딩을 지원하고 페이지마다 tab의 표시에 대응할 수 있습니다.
MyPagerAdapter adapter = new MyPagerAdapter();
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(adapter);
ViewPager의 컨텐트를 채우기 위해 adapter가 설정됩니다.
class MyPagerAdapter extends PagerAdapter
implements ViewPager.OnPageChangeListener {
int mCurPos = 0;
@Override
public int getCount() {
return mNumTabs;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TabInfo tab = mTabs.get(position);
View root = tab.build(mInflater, mContentContainer, mRootView);
container.addView(root);
root.setTag(R.id.name, tab);
return root;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
//return ((TabInfo)((View)object).getTag(R.id.name)).mListType;
}
@Override
public CharSequence getPageTitle(int position) {
return mTabs.get(position).mLabel;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mCurPos = position;
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
updateCurrentTab(mCurPos);
}
}
}
이 adapter의 instantiateItem 함수는 각 하위 항목, 즉 각 페이지를 초기화합니다.
TabInfo tab = mTabs.get(position);
View root = tab.build(mInflater, mContentContainer, mRootView);
따라서 TabInfo의 build 함수를 확인해야 합니다.
public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
if (mRootView != null) {
return mRootView;
}
mInflater = inflater;
mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING
? R.layout.manage_applications_running
: R.layout.manage_applications_apps, null);
mLoadingContainer = mRootView.findViewById(R.id.loading_container);
mLoadingContainer.setVisibility(View.VISIBLE);
mListContainer = mRootView.findViewById(R.id.list_container);
if (mListContainer != null) {
// Create adapter and list view here
View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
if (emptyView != null) {
lv.setEmptyView(emptyView);
}
lv.setOnItemClickListener(this);
lv.setSaveEnabled(true);
lv.setItemsCanFocus(true);
lv.setTextFilterEnabled(true);
mListView = lv;
mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
mListView.setAdapter(mApplications);
mListView.setRecyclerListener(mApplications);
mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
if (mFilter == FILTER_APPS_SDCARD) {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.sd_card_storage));
} else {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.internal_storage));
}
applyCurrentStorage();
}
mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
R.id.running_processes);
if (mRunningProcessesView != null) {
mRunningProcessesView.doCreate(mSavedInstanceState);
}
return mRootView;
}
이 함수는tab에서listview와tab에서 대응하는storage 표시 정보를 표시하는 데 사용됩니다.
tab에서 listView를 채우는 경우:
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
AppViewHolder holder = AppViewHolder.createOrRecycle(mTab.mInflater, convertView);
convertView = holder.rootView;
// Bind the data efficiently with the holder
ApplicationsState.AppEntry entry = mEntries.get(position);
synchronized (entry) {
holder.entry = entry;
if (entry.label != null) {
holder.appName.setText(entry.label);
}
mState.ensureIcon(entry);
if (entry.icon != null) {
holder.appIcon.setImageDrawable(entry.icon);
}
holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
holder.disabled.setVisibility(View.VISIBLE);
holder.disabled.setText(R.string.not_installed);
} else if (!entry.info.enabled) {
holder.disabled.setVisibility(View.VISIBLE);
holder.disabled.setText(R.string.disabled);
} else {
holder.disabled.setVisibility(View.GONE);
}
if (mFilterMode == FILTER_APPS_SDCARD) {
holder.checkBox.setVisibility(View.VISIBLE);
holder.checkBox.setChecked((entry.info.flags
& ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
} else {
holder.checkBox.setVisibility(View.GONE);
}
}
mActive.remove(convertView);
mActive.add(convertView);
return convertView;
}
storage를 가져오려면 IMedia Container Service를 사용하여 이 서비스를 연결해야 합니다.
getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE);
이 서비스에 연결하면 모든tab에서 이 서비스의 실례를 얻을 수 있으며, 이 실례를 통해storage 관련 정보를 얻을 수 있습니다
private volatile IMediaContainerService mContainerService;
private final ServiceConnection mContainerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mContainerService = IMediaContainerService.Stub.asInterface(service);
for (int i=0; i<mTabs.size(); i++) {
mTabs.get(i).setContainerService(mContainerService);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mContainerService = null;
}
};
다음과 같은 storage 정보 코드를 가져옵니다.
SD 카드 확보:
if (mFilter == FILTER_APPS_SDCARD) {
if (mContainerService != null) {
try {
final long[] stats = mContainerService.getFileSystemStats(
Environment.getExternalStorageDirectory().getPath());
mTotalStorage = stats[0];
mFreeStorage = stats[1];
} catch (RemoteException e) {
Log.w(TAG, "Problem in container service", e);
}
}
if (mApplications != null) {
final int N = mApplications.getCount();
for (int i=0; i<N; i++) {
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
mAppStorage += ae.externalCodeSize + ae.externalDataSize
+ ae.externalCacheSize;
}
}
로컬 스토리지 공간 정보를 보려면 다음과 같이 하십시오.
if (mContainerService != null) {
try {
final long[] stats = mContainerService.getFileSystemStats(
Environment.getDataDirectory().getPath());
mTotalStorage = stats[0];
mFreeStorage = stats[1];
} catch (RemoteException e) {
Log.w(TAG, "Problem in container service", e);
}
}
UI에 마지막으로 표시:
void applyCurrentStorage() {
// If view hierarchy is not yet created, no views to update.
if (mRootView == null) {
return;
}
if (mTotalStorage > 0) {
BidiFormatter bidiFormatter = BidiFormatter.getInstance();
mColorBar.setRatios((mTotalStorage-mFreeStorage-mAppStorage)/(float)mTotalStorage,
mAppStorage/(float)mTotalStorage, mFreeStorage/(float)mTotalStorage);
long usedStorage = mTotalStorage - mFreeStorage;
if (mLastUsedStorage != usedStorage) {
mLastUsedStorage = usedStorage;
String sizeStr = bidiFormatter.unicodeWrap(
Formatter.formatShortFileSize(mOwner.getActivity(), usedStorage));
mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
R.string.service_foreground_processes, sizeStr));
}
if (mLastFreeStorage != mFreeStorage) {
mLastFreeStorage = mFreeStorage;
String sizeStr = bidiFormatter.unicodeWrap(
Formatter.formatShortFileSize(mOwner.getActivity(), mFreeStorage));
mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
R.string.service_background_processes, sizeStr));
}
} else {
mColorBar.setRatios(0, 0, 0);
if (mLastUsedStorage != -1) {
mLastUsedStorage = -1;
mUsedStorageText.setText("");
}
if (mLastFreeStorage != -1) {
mLastFreeStorage = -1;
mFreeStorageText.setText("");
}
}
}
listView 하위 항목을 클릭하면 세부 목록 페이지로 이동합니다.
public void onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position,
long id) {
if (tab.mApplications != null && tab.mApplications.getCount() > position) {
ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position);
mCurrentPkgName = entry.info.packageName;
startApplicationDetailsActivity();
}
}
// utility method used to start sub activity
private void startApplicationDetailsActivity() {
// start new fragment to display extended information
Bundle args = new Bundle();
args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mCurrentPkgName);
PreferenceActivity pa = (PreferenceActivity)getActivity();
pa.startPreferencePanel(InstalledAppDetails.class.getName(), args,
R.string.application_info_label, null, this, INSTALLED_APP_DETAILS);
}
세부 목록의 클래스를 보려면 다음과 같이 하십시오.
public class InstalledAppDetails extends Fragment
implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
ApplicationsState.Callbacks
즉,fragment이기도 하다.
세부 목록 인터페이스 관련 button 작업 코드는 다음과 같습니다.
public void onClick(View v) {
String packageName = mAppEntry.info.packageName;
if(v == mUninstallButton) {
if (mUpdatedSysApp) {
showDialogInner(DLG_FACTORY_RESET, 0);
} else {
if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
if (mAppEntry.info.enabled) {
showDialogInner(DLG_DISABLE, 0);
} else {
new DisableChanger(this, mAppEntry.info,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
.execute((Object)null);
}
} else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
uninstallPkg(packageName, true, false);
} else {
uninstallPkg(packageName, false, false);
}
}
} else if(v == mSpecialDisableButton) {
showDialogInner(DLG_SPECIAL_DISABLE, 0);
} else if(v == mActivitiesButton) {
mPm.clearPackagePreferredActivities(packageName);
try {
mUsbManager.clearDefaults(packageName, UserHandle.myUserId());
} catch (RemoteException e) {
Log.e(TAG, "mUsbManager.clearDefaults", e);
}
mAppWidgetManager.setBindAppWidgetPermission(packageName, false);
TextView autoLaunchTitleView =
(TextView) mRootView.findViewById(R.id.auto_launch_title);
TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
} else if(v == mClearDataButton) {
if (mAppEntry.info.manageSpaceActivityName != null) {
if (!Utils.isMonkeyRunning()) {
Intent intent = new Intent(Intent.ACTION_DEFAULT);
intent.setClassName(mAppEntry.info.packageName,
mAppEntry.info.manageSpaceActivityName);
startActivityForResult(intent, REQUEST_MANAGE_SPACE);
}
} else {
showDialogInner(DLG_CLEAR_DATA, 0);
}
} else if (v == mClearCacheButton) {
// Lazy initialization of observer
if (mClearCacheObserver == null) {
mClearCacheObserver = new ClearCacheObserver();
}
mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
} else if (v == mForceStopButton) {
showDialogInner(DLG_FORCE_STOP, 0);
//forceStopPackage(mAppInfo.packageName);
} else if (v == mMoveAppButton) {
if (mPackageMoveObserver == null) {
mPackageMoveObserver = new PackageMoveObserver();
}
int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
mMoveInProgress = true;
refreshButtons();
mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.