diff options
author | Yuichi Araki <yaraki@google.com> | 2014-12-01 21:05:48 +0900 |
---|---|---|
committer | Yuichi Araki <yaraki@google.com> | 2014-12-09 13:16:29 +0900 |
commit | 2b431b5552d50c696bd80e9bf84c45509f727cc2 (patch) | |
tree | fa776d6a6c908dc0bf55dd108a44039c27e121dd | |
parent | bc036ecdf44cd03163c206096172299f3940b057 (diff) | |
download | android-2b431b5552d50c696bd80e9bf84c45509f727cc2.tar.gz |
AppRestrictionSchema, Enforcer: More restrictions
Bug: 18509464
Change-Id: I82e56aa4f79ea1d5c00d807489ddcfa5fd328061
18 files changed, 971 insertions, 187 deletions
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java index 6db54f65..8b0620fb 100644 --- a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java +++ b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java @@ -22,34 +22,34 @@ import android.content.Context; import android.content.RestrictionEntry; import android.content.RestrictionsManager; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Spinner; import android.widget.Switch; -import android.widget.TextView; import android.widget.Toast; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** * This fragment provides UI and functionality to set restrictions on the AppRestrictionSchema * sample. */ -public class AppRestrictionEnforcerFragment extends Fragment implements View.OnClickListener, - CompoundButton.OnCheckedChangeListener { - - /** - * Package name of the AppRestrictionSchema sample. - */ - private static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA - = "com.example.android.apprestrictionschema"; +public class AppRestrictionEnforcerFragment extends Fragment implements + CompoundButton.OnCheckedChangeListener, AdapterView.OnItemSelectedListener { /** * Key for {@link SharedPreferences} @@ -62,15 +62,38 @@ public class AppRestrictionEnforcerFragment extends Fragment implements View.OnC private static final String RESTRICTION_KEY_SAY_HELLO = "can_say_hello"; /** - * Default boolean value for "can_say_hello" restriction. The actual value is loaded in - * {@link #loadRestrictions(android.app.Activity)}. + * Key for the string restriction in AppRestrictionSchema. + */ + private static final String RESTRICTION_KEY_MESSAGE = "message"; + + /** + * Key for the integer restriction in AppRestrictionSchema. + */ + private static final String RESTRICTION_KEY_NUMBER = "number"; + + /** + * Key for the choice restriction in AppRestrictionSchema. + */ + private static final String RESTRICTION_KEY_RANK = "rank"; + + /** + * Key for the multi-select restriction in AppRestrictionSchema. */ - private boolean mDefaultValueRestrictionSayHello; + private static final String RESTRICTION_KEY_APPROVALS = "approvals"; + + private static final String DELIMETER = ","; + + /** + * Current status of the restrictions. + */ + private Bundle mCurrentRestrictions = new Bundle(); // UI Components - private TextView mTextStatus; - private Button mButtonUnhide; private Switch mSwitchSayHello; + private EditText mEditMessage; + private EditText mEditNumber; + private Spinner mSpinnerRank; + private LinearLayout mLayoutApprovals; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -80,152 +103,262 @@ public class AppRestrictionEnforcerFragment extends Fragment implements View.OnC @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - mTextStatus = (TextView) view.findViewById(R.id.status); - mButtonUnhide = (Button) view.findViewById(R.id.unhide); + // Retain references for the UI elements mSwitchSayHello = (Switch) view.findViewById(R.id.say_hello); - mButtonUnhide.setOnClickListener(this); - mSwitchSayHello.setOnCheckedChangeListener(this); + mEditMessage = (EditText) view.findViewById(R.id.message); + mEditNumber = (EditText) view.findViewById(R.id.number); + mSpinnerRank = (Spinner) view.findViewById(R.id.rank); + mLayoutApprovals = (LinearLayout) view.findViewById(R.id.approvals); } @Override public void onResume() { super.onResume(); - updateUi(getActivity()); + loadRestrictions(getActivity()); } @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.unhide: { - unhideApp(getActivity()); + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + switch (compoundButton.getId()) { + case R.id.say_hello: { + saveCanSayHello(getActivity(), checked); + break; + } + case R.id.approval: { + if (checked) { + addApproval(getActivity(), (String) compoundButton.getTag()); + } else { + removeApproval(getActivity(), (String) compoundButton.getTag()); + } break; } } } + private TextWatcher mWatcherMessage = new EasyTextWatcher() { + @Override + public void afterTextChanged(Editable s) { + saveMessage(getActivity(), s.toString()); + } + }; + + private TextWatcher mWatcherNumber = new EasyTextWatcher() { + @Override + public void afterTextChanged(Editable s) { + try { + String string = s.toString(); + if (!TextUtils.isEmpty(string)) { + saveNumber(getActivity(), Integer.parseInt(string)); + } + } catch (NumberFormatException e) { + Toast.makeText(getActivity(), "Not an integer!", Toast.LENGTH_SHORT).show(); + } + } + }; + @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - switch (compoundButton.getId()) { - case R.id.say_hello: { - allowSayHello(getActivity(), checked); + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + switch (parent.getId()) { + case R.id.rank: { + saveRank(getActivity(), (String) parent.getAdapter().getItem(position)); break; } } } + @Override + public void onNothingSelected(AdapterView<?> parent) { + // Nothing to do + } + /** - * Updates the UI components according to the current status of AppRestrictionSchema and its - * restriction. + * Loads the restrictions for the AppRestrictionSchema sample. In this implementation, we just + * read the default value for the "can_say_hello" restriction. * * @param activity The activity */ - private void updateUi(Activity activity) { - PackageManager packageManager = activity.getPackageManager(); - try { - ApplicationInfo info = packageManager.getApplicationInfo( - PACKAGE_NAME_APP_RESTRICTION_SCHEMA, PackageManager.GET_UNINSTALLED_PACKAGES); - DevicePolicyManager devicePolicyManager = - (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); - if (0 < (info.flags & ApplicationInfo.FLAG_INSTALLED)) { - if (!devicePolicyManager.isApplicationHidden( - EnforcerDeviceAdminReceiver.getComponentName(activity), - PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) { - // The app is ready - loadRestrictions(activity); - mTextStatus.setVisibility(View.GONE); - mButtonUnhide.setVisibility(View.GONE); - mSwitchSayHello.setVisibility(View.VISIBLE); - mSwitchSayHello.setOnCheckedChangeListener(null); - mSwitchSayHello.setChecked(canSayHello(activity)); - mSwitchSayHello.setOnCheckedChangeListener(this); - } else { - // The app is installed but hidden in this profile - mTextStatus.setText(R.string.status_not_activated); - mTextStatus.setVisibility(View.VISIBLE); - mButtonUnhide.setVisibility(View.VISIBLE); - mSwitchSayHello.setVisibility(View.GONE); - } - } else { - // Need to reinstall the sample app - mTextStatus.setText(R.string.status_need_reinstall); - mTextStatus.setVisibility(View.VISIBLE); - mButtonUnhide.setVisibility(View.GONE); - mSwitchSayHello.setVisibility(View.GONE); + private void loadRestrictions(Activity activity) { + RestrictionsManager manager = + (RestrictionsManager) activity.getSystemService(Context.RESTRICTIONS_SERVICE); + List<RestrictionEntry> restrictions = + manager.getManifestRestrictions(Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA); + SharedPreferences prefs = activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE); + for (RestrictionEntry restriction : restrictions) { + String key = restriction.getKey(); + if (RESTRICTION_KEY_SAY_HELLO.equals(key)) { + updateCanSayHello(prefs.getBoolean(RESTRICTION_KEY_SAY_HELLO, + restriction.getSelectedState())); + } else if (RESTRICTION_KEY_MESSAGE.equals(key)) { + updateMessage(prefs.getString(RESTRICTION_KEY_MESSAGE, + restriction.getSelectedString())); + } else if (RESTRICTION_KEY_NUMBER.equals(key)) { + updateNumber(prefs.getInt(RESTRICTION_KEY_NUMBER, + restriction.getIntValue())); + } else if (RESTRICTION_KEY_RANK.equals(key)) { + updateRank(activity, restriction.getChoiceValues(), + prefs.getString(RESTRICTION_KEY_RANK, restriction.getSelectedString())); + } else if (RESTRICTION_KEY_APPROVALS.equals(key)) { + updateApprovals(activity, restriction.getChoiceValues(), + TextUtils.split(prefs.getString(RESTRICTION_KEY_APPROVALS, + TextUtils.join(DELIMETER, + restriction.getAllSelectedStrings())), + DELIMETER)); } - } catch (PackageManager.NameNotFoundException e) { - mTextStatus.setText(R.string.status_not_installed); - mTextStatus.setVisibility(View.VISIBLE); - mButtonUnhide.setVisibility(View.GONE); - mSwitchSayHello.setVisibility(View.GONE); + } + } + + private void updateCanSayHello(boolean canSayHello) { + mCurrentRestrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, canSayHello); + mSwitchSayHello.setOnCheckedChangeListener(null); + mSwitchSayHello.setChecked(canSayHello); + mSwitchSayHello.setOnCheckedChangeListener(this); + } + + private void updateMessage(String message) { + mCurrentRestrictions.putString(RESTRICTION_KEY_MESSAGE, message); + mEditMessage.removeTextChangedListener(mWatcherMessage); + mEditMessage.setText(message); + mEditMessage.addTextChangedListener(mWatcherMessage); + } + + private void updateNumber(int number) { + mCurrentRestrictions.putInt(RESTRICTION_KEY_NUMBER, number); + mEditNumber.removeTextChangedListener(mWatcherNumber); + mEditNumber.setText(String.valueOf(number)); + mEditNumber.addTextChangedListener(mWatcherNumber); + } + + private void updateRank(Context context, String[] ranks, String selectedRank) { + mCurrentRestrictions.putString(RESTRICTION_KEY_RANK, selectedRank); + mSpinnerRank.setAdapter(new ArrayAdapter<>(context, + android.R.layout.simple_spinner_dropdown_item, ranks)); + mSpinnerRank.setSelection(search(ranks, selectedRank)); + mSpinnerRank.setOnItemSelectedListener(this); + } + + private void updateApprovals(Context context, String[] approvals, + String[] selectedApprovals) { + mCurrentRestrictions.putStringArray(RESTRICTION_KEY_APPROVALS, selectedApprovals); + mLayoutApprovals.removeAllViews(); + for (String approval : approvals) { + Switch sw = new Switch(context); + sw.setText(approval); + sw.setTag(approval); + sw.setChecked(Arrays.asList(selectedApprovals).contains(approval)); + sw.setOnCheckedChangeListener(this); + sw.setId(R.id.approval); + mLayoutApprovals.addView(sw); } } /** - * Unhides the AppRestrictionSchema sample in case it is hidden in this profile. + * Saves the value for the "cay_say_hello" restriction of AppRestrictionSchema. * * @param activity The activity + * @param allow The value to be set for the restriction. */ - private void unhideApp(Activity activity) { - DevicePolicyManager devicePolicyManager = - (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); - devicePolicyManager.setApplicationHidden( - EnforcerDeviceAdminReceiver.getComponentName(activity), - PACKAGE_NAME_APP_RESTRICTION_SCHEMA, false); - Toast.makeText(activity, "Enabled the app", Toast.LENGTH_SHORT).show(); - updateUi(activity); + private void saveCanSayHello(Activity activity, boolean allow) { + mCurrentRestrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, allow); + saveRestrictions(activity); + // Note that the owner app needs to remember the restrictions on its own. + editPreferences(activity).putBoolean(RESTRICTION_KEY_SAY_HELLO, allow).apply(); } /** - * Loads the restrictions for the AppRestrictionSchema sample. In this implementation, we just - * read the default value for the "can_say_hello" restriction. + * Saves the value for the "message" restriction of AppRestrictionSchema. * * @param activity The activity + * @param message The value to be set for the restriction. */ - private void loadRestrictions(Activity activity) { - RestrictionsManager restrictionsManager = - (RestrictionsManager) activity.getSystemService(Context.RESTRICTIONS_SERVICE); - List<RestrictionEntry> restrictions = - restrictionsManager.getManifestRestrictions(PACKAGE_NAME_APP_RESTRICTION_SCHEMA); - for (RestrictionEntry restriction : restrictions) { - if (RESTRICTION_KEY_SAY_HELLO.equals(restriction.getKey())) { - mDefaultValueRestrictionSayHello = restriction.getSelectedState(); - } - } + private void saveMessage(Activity activity, String message) { + mCurrentRestrictions.putString(RESTRICTION_KEY_MESSAGE, message); + saveRestrictions(activity); + editPreferences(activity).putString(RESTRICTION_KEY_MESSAGE, message).apply(); } /** - * Returns whether the AppRestrictionSchema is currently allowed to say hello to its user. Note - * that a profile/device owner needs to remember each restriction value on its own. + * Saves the value for the "number" restriction of AppRestrictionSchema. * * @param activity The activity - * @return True if the AppRestrictionSchema is allowed to say hello + * @param number The value to be set for the restriction. */ - private boolean canSayHello(Activity activity) { - SharedPreferences prefs = activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE); - return prefs.getBoolean(RESTRICTION_KEY_SAY_HELLO, mDefaultValueRestrictionSayHello); + private void saveNumber(Activity activity, int number) { + mCurrentRestrictions.putInt(RESTRICTION_KEY_NUMBER, number); + saveRestrictions(activity); + editPreferences(activity).putInt(RESTRICTION_KEY_NUMBER, number).apply(); } /** - * Sets the value for the "cay_say_hello" restriction of AppRestrictionSchema. + * Saves the value for the "rank" restriction of AppRestrictionSchema. * * @param activity The activity - * @param allow The value to be set for the restriction. + * @param rank The value to be set for the restriction. */ - private void allowSayHello(Activity activity, boolean allow) { + private void saveRank(Activity activity, String rank) { + mCurrentRestrictions.putString(RESTRICTION_KEY_RANK, rank); + saveRestrictions(activity); + editPreferences(activity).putString(RESTRICTION_KEY_RANK, rank).apply(); + } + + private void addApproval(Activity activity, String approval) { + List<String> approvals = new ArrayList<>(Arrays.asList( + mCurrentRestrictions.getStringArray(RESTRICTION_KEY_APPROVALS))); + if (approvals.contains(approval)) { + return; + } + approvals.add(approval); + saveApprovals(activity, approvals.toArray(new String[approvals.size()])); + } + + private void removeApproval(Activity activity, String approval) { + List<String> approvals = new ArrayList<>(Arrays.asList( + mCurrentRestrictions.getStringArray(RESTRICTION_KEY_APPROVALS))); + if (!approval.contains(approval)) { + return; + } + approvals.remove(approval); + saveApprovals(activity, approvals.toArray(new String[approvals.size()])); + } + + /** + * Saves the value for the "approvals" restriction of AppRestrictionSchema. + * + * @param activity The activity + * @param approvals The value to be set for the restriction. + */ + private void saveApprovals(Activity activity, String[] approvals) { + mCurrentRestrictions.putStringArray(RESTRICTION_KEY_APPROVALS, approvals); + saveRestrictions(activity); + editPreferences(activity).putString(RESTRICTION_KEY_APPROVALS, + TextUtils.join(DELIMETER, approvals)).apply(); + } + + private void saveRestrictions(Activity activity) { DevicePolicyManager devicePolicyManager = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); - Bundle restrictions = new Bundle(); - restrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, allow); devicePolicyManager.setApplicationRestrictions( EnforcerDeviceAdminReceiver.getComponentName(activity), - PACKAGE_NAME_APP_RESTRICTION_SCHEMA, restrictions); - // The profile/device owner needs to remember the current state of restrictions on its own - activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE) - .edit() - .putBoolean(RESTRICTION_KEY_SAY_HELLO, allow) - .apply(); - Toast.makeText(activity, allow ? R.string.allowed : R.string.disallowed, - Toast.LENGTH_SHORT).show(); + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, mCurrentRestrictions); + } + + private SharedPreferences.Editor editPreferences(Activity activity) { + return activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE).edit(); + } + + /** + * Sequential search + * + * @param array The string array + * @param s The string to search for + * @return Index if found. -1 if not found. + */ + private int search(String[] array, String s) { + for (int i = 0; i < array.length; ++i) { + if (s.equals(array[i])) { + return i; + } + } + return -1; } } diff --git a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/Constants.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/Constants.java new file mode 100644 index 00000000..bb4e958c --- /dev/null +++ b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/Constants.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 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. + */ + +package com.example.android.apprestrictionenforcer; + +public interface Constants { + + /** + * Package name of the AppRestrictionSchema sample. + */ + public static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA + = "com.example.android.apprestrictionschema"; + +} diff --git a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EasyTextWatcher.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EasyTextWatcher.java new file mode 100644 index 00000000..8e0abb44 --- /dev/null +++ b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EasyTextWatcher.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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. + */ + +package com.example.android.apprestrictionenforcer; + +import android.text.TextWatcher; + +/** + * This is a wrapper around {@link TextWatcher} that overrides + * {@link TextWatcher#beforeTextChanged(CharSequence, int, int, int)} and + * {@link TextWatcher#onTextChanged(CharSequence, int, int, int)} with empty bodies. + */ +public abstract class EasyTextWatcher implements TextWatcher { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } + +} diff --git a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java index 72224e17..c6b012be 100644 --- a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java +++ b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java @@ -18,24 +18,44 @@ package com.example.android.apprestrictionenforcer; import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.support.v4.app.FragmentActivity; -public class MainActivity extends FragmentActivity { +public class MainActivity extends FragmentActivity implements StatusFragment.StatusUpdatedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_real); if (null == savedInstanceState) { - DevicePolicyManager manager = (DevicePolicyManager) - getSystemService(Context.DEVICE_POLICY_SERVICE); - if (manager.isProfileOwnerApp(getApplicationContext().getPackageName())) { - // If the managed profile is already set up, we show the main screen. - showMainFragment(); - } else { - // If not, we show the set up screen. + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); + PackageManager packageManager = getPackageManager(); + if (!devicePolicyManager.isProfileOwnerApp(getApplicationContext().getPackageName())) { + // If the managed profile is not yet set up, we show the setup screen. showSetupProfile(); + } else { + try { + ApplicationInfo info = packageManager.getApplicationInfo( + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, + PackageManager.GET_UNINSTALLED_PACKAGES); + if (0 == (info.flags & ApplicationInfo.FLAG_INSTALLED)) { + // Need to reinstall the sample app + showStatusProfile(); + } else if (devicePolicyManager.isApplicationHidden( + EnforcerDeviceAdminReceiver.getComponentName(this), + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) { + // The app is installed but hidden in this profile + showStatusProfile(); + } else { + // Everything is clear; show the main screen + showMainFragment(); + } + } catch (PackageManager.NameNotFoundException e) { + showStatusProfile(); + } } } } @@ -46,10 +66,21 @@ public class MainActivity extends FragmentActivity { .commit(); } + private void showStatusProfile() { + getSupportFragmentManager().beginTransaction() + .replace(R.id.container, new StatusFragment()) + .commit(); + } + private void showMainFragment() { getSupportFragmentManager().beginTransaction() .replace(R.id.container, new AppRestrictionEnforcerFragment()) .commit(); } + @Override + public void onStatusUpdated() { + showMainFragment(); + } + } diff --git a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/StatusFragment.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/StatusFragment.java new file mode 100644 index 00000000..f4a4eb79 --- /dev/null +++ b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/StatusFragment.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2014 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. + */ + +package com.example.android.apprestrictionenforcer; + +import android.app.Activity; +import android.app.admin.DevicePolicyManager; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +/** + * Provides UI for enabling the target app in this profile. The status of the app can be + * uninstalled, hidden, or enabled depending on the situations. This fragment shows suitable + * controls for each status. + */ +public class StatusFragment extends Fragment implements View.OnClickListener { + + private TextView mTextStatus; + private Button mButtonUnhide; + private StatusUpdatedListener mListener; + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_status, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + mTextStatus = (TextView) view.findViewById(R.id.status); + mButtonUnhide = (Button) view.findViewById(R.id.unhide); + mButtonUnhide.setOnClickListener(this); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mListener = (StatusUpdatedListener) activity; + } + + @Override + public void onDetach() { + mListener = null; + super.onDetach(); + } + + @Override + public void onResume() { + super.onResume(); + updateUi(getActivity()); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.unhide: { + unhideApp(getActivity()); + break; + } + } + } + + private void updateUi(Activity activity) { + PackageManager packageManager = activity.getPackageManager(); + try { + ApplicationInfo info = packageManager.getApplicationInfo( + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, + PackageManager.GET_UNINSTALLED_PACKAGES); + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); + if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { + if (!devicePolicyManager.isApplicationHidden( + EnforcerDeviceAdminReceiver.getComponentName(activity), + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) { + // The app is ready to enforce restrictions + // This is unlikely to happen in this sample as unhideApp() handles it. + mListener.onStatusUpdated(); + } else { + // The app is installed but hidden in this profile + mTextStatus.setText(R.string.status_not_activated); + mButtonUnhide.setVisibility(View.VISIBLE); + } + } else { + // Need to reinstall the sample app + mTextStatus.setText(R.string.status_need_reinstall); + mButtonUnhide.setVisibility(View.GONE); + } + } catch (PackageManager.NameNotFoundException e) { + // Need to reinstall the sample app + mTextStatus.setText(R.string.status_need_reinstall); + mButtonUnhide.setVisibility(View.GONE); + } + } + + /** + * Unhides the AppRestrictionSchema sample in case it is hidden in this profile. + * + * @param activity The activity + */ + private void unhideApp(Activity activity) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); + devicePolicyManager.setApplicationHidden( + EnforcerDeviceAdminReceiver.getComponentName(activity), + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, false); + Toast.makeText(activity, "Enabled the app", Toast.LENGTH_SHORT).show(); + mListener.onStatusUpdated(); + } + + public interface StatusUpdatedListener { + public void onStatusUpdated(); + } + +} diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml index e6c50a24..01181916 100644 --- a/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml +++ b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml @@ -14,31 +14,111 @@ See the License for the specific language governing permissions and limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingBottom="@dimen/vertical_page_margin" - android:paddingLeft="@dimen/horizontal_page_margin" - android:paddingRight="@dimen/horizontal_page_margin" - android:paddingTop="@dimen/vertical_page_margin"> - - <TextView - android:id="@+id/status" + android:layout_height="match_parent"> + + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/status_not_installed" /> + android:orientation="vertical" + android:paddingBottom="@dimen/vertical_page_margin" + android:paddingLeft="@dimen/horizontal_page_margin" + android:paddingRight="@dimen/horizontal_page_margin" + android:paddingTop="@dimen/vertical_page_margin"> - <Button - android:id="@+id/unhide" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/unhide" /> - <Switch - android:id="@+id/say_hello" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/allow_saying_hello" /> + <Switch + android:id="@+id/say_hello" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/allow_saying_hello"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:labelFor="@id/message" + android:text="@string/message"/> + + <EditText + android:id="@id/message" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:inputType="text" + android:maxLines="1"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:labelFor="@id/number" + android:text="@string/number"/> + + <EditText + android:id="@id/number" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:inputType="number" + android:maxLines="1"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/rank"/> + + <Spinner + android:id="@+id/rank" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/margin_small"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/approvals"/> + + <LinearLayout + android:id="@+id/approvals" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/margin_small" + android:orientation="vertical"/> + + </LinearLayout> + + </LinearLayout> -</LinearLayout> +</ScrollView> diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_status.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_status.xml new file mode 100644 index 00000000..a2d60eb7 --- /dev/null +++ b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_status.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2014 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:paddingBottom="@dimen/vertical_page_margin" + android:paddingLeft="@dimen/horizontal_page_margin" + android:paddingRight="@dimen/horizontal_page_margin" + android:paddingTop="@dimen/vertical_page_margin"> + + <TextView + android:id="@+id/status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/status_not_installed"/> + + <Button + android:id="@+id/unhide" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/unhide"/> + +</LinearLayout> diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/layout/separator.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/separator.xml new file mode 100644 index 00000000..6927d801 --- /dev/null +++ b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/separator.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2014 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. +--> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="@dimen/margin_medium" + android:layout_marginTop="@dimen/margin_medium" + android:background="#9000"/> diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/values/ids.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/values/ids.xml new file mode 100644 index 00000000..04ba4ec2 --- /dev/null +++ b/admin/AppRestrictionEnforcer/Application/src/main/res/values/ids.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2014 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. +--> +<resources> + <item name="message" type="id"/> + <item name="number" type="id"/> + <item name="approval" type="id"/> +</resources> diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml index 3029e046..e35daee3 100644 --- a/admin/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml +++ b/admin/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml @@ -25,4 +25,8 @@ <string name="allowed">Allowed</string> <string name="disallowed">Disallowed</string> <string name="profile_name">AppRestrictionEnforcer </string> + <string name="message">Message: </string> + <string name="number">Number: </string> + <string name="rank">Rank: </string> + <string name="approvals">Approvals: </string> </resources> diff --git a/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties b/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties index 0c71e760..f2e517b2 100644 --- a/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties +++ b/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Mon Dec 01 16:00:44 JST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/admin/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java b/admin/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java index 76f024f3..7b8dba83 100644 --- a/admin/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java +++ b/admin/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java @@ -17,10 +17,12 @@ package com.example.android.apprestrictionschema; import android.content.Context; +import android.content.RestrictionEntry; import android.content.RestrictionsManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -30,6 +32,8 @@ import android.widget.Toast; import com.example.android.common.logger.Log; +import java.util.List; + /** * Pressing the button on this fragment pops up a simple Toast message. The button is enabled or * disabled according to the restrictions set by device/profile owner. You can use the @@ -40,9 +44,21 @@ public class AppRestrictionSchemaFragment extends Fragment implements View.OnCli // Tag for the logger private static final String TAG = "AppRestrictionSchemaFragment"; + private static final String KEY_CAN_SAY_HELLO = "can_say_hello"; + private static final String KEY_MESSAGE = "message"; + private static final String KEY_NUMBER = "number"; + private static final String KEY_RANK = "rank"; + private static final String KEY_APPROVALS = "approvals"; + + // Message to show when the button is clicked (String restriction) + private String mMessage; + // UI Components private TextView mTextSayHello; private Button mButtonSayHello; + private TextView mTextNumber; + private TextView mTextRank; + private TextView mTextApprovals; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -54,48 +70,103 @@ public class AppRestrictionSchemaFragment extends Fragment implements View.OnCli public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { mTextSayHello = (TextView) view.findViewById(R.id.say_hello_explanation); mButtonSayHello = (Button) view.findViewById(R.id.say_hello); + mTextNumber = (TextView) view.findViewById(R.id.your_number); + mTextRank = (TextView) view.findViewById(R.id.your_rank); + mTextApprovals = (TextView) view.findViewById(R.id.approvals_you_have); mButtonSayHello.setOnClickListener(this); } @Override public void onResume() { super.onResume(); - // Update the UI according to the configured restrictions - RestrictionsManager restrictionsManager = + resolveRestrictions(); + } + + private void resolveRestrictions() { + RestrictionsManager manager = (RestrictionsManager) getActivity().getSystemService(Context.RESTRICTIONS_SERVICE); - Bundle restrictions = restrictionsManager.getApplicationRestrictions(); - updateUI(restrictions); + Bundle restrictions = manager.getApplicationRestrictions(); + List<RestrictionEntry> entries = manager.getManifestRestrictions(getActivity().getApplicationContext().getPackageName()); + for (RestrictionEntry entry : entries) { + String key = entry.getKey(); + Log.d(TAG, "key: " + key); + if (key.equals(KEY_CAN_SAY_HELLO)) { + updateCanSayHello(entry, restrictions); + } else if (key.equals(KEY_MESSAGE)) { + updateMessage(entry, restrictions); + } else if (key.equals(KEY_NUMBER)) { + updateNumber(entry, restrictions); + } else if (key.equals(KEY_RANK)) { + updateRank(entry, restrictions); + } else if (key.equals(KEY_APPROVALS)) { + updateApprovals(entry, restrictions); + } + } + } + + private void updateCanSayHello(RestrictionEntry entry, Bundle restrictions) { + boolean canSayHello; + if (restrictions == null || !restrictions.containsKey(KEY_CAN_SAY_HELLO)) { + canSayHello = entry.getSelectedState(); + } else { + canSayHello = restrictions.getBoolean(KEY_CAN_SAY_HELLO); + } + mTextSayHello.setText(canSayHello ? + R.string.explanation_can_say_hello_true : + R.string.explanation_can_say_hello_false); + mButtonSayHello.setEnabled(canSayHello); } - private void updateUI(Bundle restrictions) { - if (canSayHello(restrictions)) { - mTextSayHello.setText(R.string.explanation_can_say_hello_true); - mButtonSayHello.setEnabled(true); + private void updateMessage(RestrictionEntry entry, Bundle restrictions) { + if (restrictions == null || !restrictions.containsKey(KEY_MESSAGE)) { + mMessage = entry.getSelectedString(); } else { - mTextSayHello.setText(R.string.explanation_can_say_hello_false); - mButtonSayHello.setEnabled(false); + mMessage = restrictions.getString(KEY_MESSAGE); } } - /** - * Returns the current status of the restriction. - * - * @param restrictions The application restrictions - * @return True if the app is allowed to say hello - */ - private boolean canSayHello(Bundle restrictions) { - final boolean defaultValue = false; - boolean canSayHello = restrictions == null ? defaultValue : - restrictions.getBoolean("can_say_hello", defaultValue); - Log.d(TAG, "canSayHello: " + canSayHello); - return canSayHello; + private void updateNumber(RestrictionEntry entry, Bundle restrictions) { + int number; + if (restrictions == null || !restrictions.containsKey(KEY_NUMBER)) { + number = entry.getIntValue(); + } else { + number = restrictions.getInt(KEY_NUMBER); + } + mTextNumber.setText(getString(R.string.your_number, number)); + } + + private void updateRank(RestrictionEntry entry, Bundle restrictions) { + String rank; + if (restrictions == null || !restrictions.containsKey(KEY_RANK)) { + rank = entry.getSelectedString(); + } else { + rank = restrictions.getString(KEY_RANK); + } + mTextRank.setText(getString(R.string.your_rank, rank)); + } + + private void updateApprovals(RestrictionEntry entry, Bundle restrictions) { + String[] approvals; + if (restrictions == null || !restrictions.containsKey(KEY_APPROVALS)) { + approvals = entry.getAllSelectedStrings(); + } else { + approvals = restrictions.getStringArray(KEY_APPROVALS); + } + String text; + if (approvals == null || approvals.length == 0) { + text = getString(R.string.none); + } else { + text = TextUtils.join(", ", approvals); + } + mTextApprovals.setText(getString(R.string.approvals_you_have, text)); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.say_hello: { - Toast.makeText(getActivity(), R.string.message_hello, Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), getString(R.string.message, mMessage), + Toast.LENGTH_SHORT).show(); break; } } diff --git a/admin/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml b/admin/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml index fc5e23dc..18ca0a4d 100644 --- a/admin/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml +++ b/admin/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml @@ -14,24 +14,60 @@ 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:padding="@dimen/margin_medium"> - - <TextView - android:id="@+id/say_hello_explanation" + + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/explanation_can_say_hello_true" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:orientation="vertical" + android:padding="@dimen/margin_medium"> - <Button - android:id="@+id/say_hello" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/margin_medium" - android:text="@string/action_can_say_hello" /> + <TextView + android:id="@+id/say_hello_explanation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/explanation_can_say_hello_true"/> + + <Button + android:id="@+id/say_hello" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/margin_medium" + android:text="@string/action_can_say_hello"/> + + <include layout="@layout/separator"/> + + <TextView + android:id="@+id/your_number" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/your_number"/> + + <include layout="@layout/separator"/> + + <TextView + android:id="@+id/your_rank" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/your_rank"/> + + <include layout="@layout/separator"/> + + <TextView + android:id="@+id/approvals_you_have" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/approvals_you_have"/> + + </LinearLayout> -</LinearLayout> +</ScrollView> diff --git a/admin/AppRestrictionSchema/Application/src/main/res/layout/separator.xml b/admin/AppRestrictionSchema/Application/src/main/res/layout/separator.xml new file mode 100644 index 00000000..6927d801 --- /dev/null +++ b/admin/AppRestrictionSchema/Application/src/main/res/layout/separator.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2014 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. +--> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="@dimen/margin_medium" + android:layout_marginTop="@dimen/margin_medium" + android:background="#9000"/> diff --git a/admin/AppRestrictionSchema/Application/src/main/res/values/restriction_values.xml b/admin/AppRestrictionSchema/Application/src/main/res/values/restriction_values.xml new file mode 100644 index 00000000..558d097f --- /dev/null +++ b/admin/AppRestrictionSchema/Application/src/main/res/values/restriction_values.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2014 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. +--> +<resources> + + <!-- Bool restriction --> + <string name="title_can_say_hello">Can say hello</string> + <string name="description_can_say_hello">Whether the app can say hello to the user</string> + <bool name="default_can_say_hello">false</bool> + + <!-- String restriction --> + <string name="title_message">Message</string> + <string name="description_message">A message string to show</string> + <string name="default_message">Hello!</string> + + <!-- Integer restriction --> + <string name="title_number">Number</string> + <string name="description_number">Sample integer value</string> + <integer name="default_number">32582657</integer> + + <!-- Choice restriction --> + <string name="title_rank">Rank</string> + <string name="description_rank">Rank of the user</string> + <string-array name="entries_rank"> + <item>Apprentice</item> + <item>Intermediate</item> + <item>Master</item> + </string-array> + <string name="entry_value_rank_apprentice">apprentice</string> + <string name="entry_value_rank_intermediate">intermediate</string> + <string name="entry_value_rank_master">master</string> + <string-array name="entry_values_rank"> + <item>@string/entry_value_rank_apprentice</item> + <item>@string/entry_value_rank_intermediate</item> + <item>@string/entry_value_rank_master</item> + </string-array> + <string name="default_rank">@string/entry_value_rank_apprentice</string> + + <!-- Multi-select restriction --> + <string name="title_approvals">Approvals</string> + <string name="description_approvals">Approvals</string> + <string-array name="entries_approvals"> + <item>Read</item> + <item>Write</item> + <item>Execute</item> + </string-array> + <string name="entry_value_approvals_read">read</string> + <string name="entry_value_approvals_write">write</string> + <string name="entry_value_approvals_execute">execute</string> + <string-array name="entry_values_approvals"> + <item>@string/entry_value_approvals_read</item> + <item>@string/entry_value_approvals_write</item> + <item>@string/entry_value_approvals_execute</item> + </string-array> + <string-array name="default_approvals"> + <!-- Empty --> + </string-array> + + <!-- Hidden restriction --> + <string name="title_secret_code">Secret code</string> + <string name="description_secret_code">This restriction is hidden and will not be shown to the administrator.</string> + <string name="default_secret_code">(Hidden restriction must have some default value)</string> + +</resources> diff --git a/admin/AppRestrictionSchema/Application/src/main/res/values/strings.xml b/admin/AppRestrictionSchema/Application/src/main/res/values/strings.xml index b8ef110b..6dce123f 100644 --- a/admin/AppRestrictionSchema/Application/src/main/res/values/strings.xml +++ b/admin/AppRestrictionSchema/Application/src/main/res/values/strings.xml @@ -16,11 +16,14 @@ limitations under the License. --> <resources> - <string name="title_can_say_hello">Can say hello</string> - <string name="description_can_say_hello">Whether the app can say hello to the user</string> <string name="explanation_can_say_hello_true">I can say hello to you.</string> <string name="explanation_can_say_hello_false">I am restricted from saying hello to you.</string> <string name="action_can_say_hello">Say hello</string> - <string name="message_hello">Hello!</string> + <string name="message">All I can say is \"%s\".</string> -</resources>
\ No newline at end of file + <string name="your_number">Your number: %d</string> + <string name="your_rank">Your rank: %s</string> + <string name="approvals_you_have">Approvals you have: %s</string> + <string name="none">none</string> + +</resources> diff --git a/admin/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml b/admin/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml index 409527fc..9e47f458 100644 --- a/admin/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml +++ b/admin/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml @@ -16,11 +16,55 @@ limitations under the License. --> <restrictions xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- + Refer to the javadoc of RestrictionsManager for detail of this file. + https://developer.android.com/reference/android/content/RestrictionsManager.html + --> + <restriction - android:defaultValue="false" + android:defaultValue="@bool/default_can_say_hello" android:description="@string/description_can_say_hello" android:key="can_say_hello" android:restrictionType="bool" - android:title="@string/title_can_say_hello" /> + android:title="@string/title_can_say_hello"/> + + <restriction + android:defaultValue="@string/default_message" + android:description="@string/description_message" + android:key="message" + android:restrictionType="string" + android:title="@string/title_message"/> + + <restriction + android:defaultValue="@integer/default_number" + android:description="@string/description_number" + android:key="number" + android:restrictionType="integer" + android:title="@string/title_number"/> + + <restriction + android:defaultValue="@string/default_rank" + android:description="@string/description_rank" + android:entries="@array/entries_rank" + android:entryValues="@array/entry_values_rank" + android:key="rank" + android:restrictionType="choice" + android:title="@string/title_rank"/> + + <restriction + android:defaultValue="@array/default_approvals" + android:description="@string/description_approvals" + android:entries="@array/entries_approvals" + android:entryValues="@array/entry_values_approvals" + android:key="approvals" + android:restrictionType="multi-select" + android:title="@string/title_approvals"/> + + <restriction + android:defaultValue="@string/default_secret_code" + android:description="@string/description_secret_code" + android:key="secret_code" + android:restrictionType="hidden" + android:title="@string/title_secret_code"/> </restrictions> diff --git a/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties b/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties index 0c71e760..fb79885e 100644 --- a/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties +++ b/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Mon Dec 01 11:44:58 JST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME |